From krzk at kernel.org  Mon Jun  1 01:42:28 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 1 Jun 2026 10:42:28 +0200
Subject: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607
 binding
In-Reply-To: <PH0PR19MB9973385EBACD2645B8845DE4F2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
 <20260530031739.109063-3-macroalpha82@gmail.com>
 <20260530-certain-goose-from-neptune-96e8ae@quoll>
 <PH0PR19MB9973385EBACD2645B8845DE4F2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <345e5048-c3aa-44d0-a66d-55a0322419db@kernel.org>

On 01/06/2026 03:44, Chris Morgan wrote:
> On Sat, May 30, 2026 at 09:26:31AM +0200, Krzysztof Kozlowski wrote:
>> On Fri, May 29, 2026 at 10:17:29PM -0500, Chris Morgan wrote:
>>> From: Chris Morgan <macromorgan at hotmail.com>
>>>
>>> Add devicetree binding for the Invensense ICM42607 and Invensense
>>> ICM42607P inertial measurement unit. This unit is a combined
>>> accelerometer, gyroscope, and thermometer available via I2C or SPI.
>>
>> Implement feedback from v3. Subject is still incorrect.
>>
> 
> I'm sorry, that was dropped due to an oversight. I'll correct it.
> 
>>>
>>> This device is functionally very similar to the icm42600 series with a
>>> very different register layout, however unlike the icm42600 driver we
>>> require a interrupt-names property be present.
>>
>> Why do we require it? Who needs it?
>>
> 
> The driver this was based off of, the icm42600 driver, has a fallback
> to select the 1st available interrupt in the event of the named

So some other driver? That's not relevant here if you do not use that.

> interrupt not existing. I was told not to do that here so the named
> interrupt is a requirement for the icm42607.

So icm42607 driver needs it? Then write it explicitly.

Best regards,
Krzysztof


From jic23 at kernel.org  Mon Jun  1 02:15:40 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Mon, 1 Jun 2026 10:15:40 +0100
Subject: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607
 binding
In-Reply-To: <PH0PR19MB9973385EBACD2645B8845DE4F2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
	<20260530031739.109063-3-macroalpha82@gmail.com>
	<20260530-certain-goose-from-neptune-96e8ae@quoll>
	<PH0PR19MB9973385EBACD2645B8845DE4F2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260601101540.6f23b09f@jic23-huawei>

On Sun, 31 May 2026 20:44:03 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Sat, May 30, 2026 at 09:26:31AM +0200, Krzysztof Kozlowski wrote:
> > On Fri, May 29, 2026 at 10:17:29PM -0500, Chris Morgan wrote:  
> > > From: Chris Morgan <macromorgan at hotmail.com>
> > > 
> > > Add devicetree binding for the Invensense ICM42607 and Invensense
> > > ICM42607P inertial measurement unit. This unit is a combined
> > > accelerometer, gyroscope, and thermometer available via I2C or SPI.  
> > 
> > Implement feedback from v3. Subject is still incorrect.
> >   
> 
> I'm sorry, that was dropped due to an oversight. I'll correct it.
> 
> > > 
> > > This device is functionally very similar to the icm42600 series with a
> > > very different register layout, however unlike the icm42600 driver we
> > > require a interrupt-names property be present.  
> > 
> > Why do we require it? Who needs it?
> >   
> 
> The driver this was based off of, the icm42600 driver, has a fallback
> to select the 1st available interrupt in the event of the named
> interrupt not existing. I was told not to do that here so the named
> interrupt is a requirement for the icm42607.

A bit more background on this.  I think it went as follows.

When that other driver originally went in we didn't pick up on their
being multiple interrupt lines.  Hence once that came up because
someone had a board that only connected the other pin we had to
'guess' which one was the default (I'm sure we asked people :)

I'll noted that we had at least one case in the past (can't remember
if it was this part) where the assumed default was not the first one :(
We've even had package variants (which we don't normally use different
compatibles for) where only INT2 actually had a pin.

Hence, since then we've been more careful with these devices.
Given there is nothing special with one interrupt rather than the other
with a mux on each that lets us route all interrupts signals to each
pin, my strong preference is we don't make assumptions and always require
the firmeware to say which one it is.

Jonathan

> 
> > Best regards,
> > Krzysztof
> >   
> 
> Thank you,
> Chris



From phucduc.bui at gmail.com  Mon Jun  1 03:05:11 2026
From: phucduc.bui at gmail.com (Bui Duc Phuc)
Date: Mon, 1 Jun 2026 17:05:11 +0700
Subject: [PATCH 1/3] ASoC: dt-bindings: rockchip-spdif: Correct SPDIF
 clock descriptions
In-Reply-To: <20260530-adventurous-basilisk-of-happiness-def6fa@quoll>
References: <20260522100318.73474-1-phucduc.bui@gmail.com> <20260522100318.73474-2-phucduc.bui@gmail.com>
 <20260530-adventurous-basilisk-of-happiness-def6fa@quoll>
Message-ID: <CAABR9nHh5WbC+A-7KV9jKEUbmK8WHgpf=VUk0DJqFrhhQFRpwg@mail.gmail.com>

Hi Krzysztof,

Thank you for your review .

> So example is wrong?
>
> What about all the users?

I only updated the internal description text to match the existing clock-names.
The clock ordering (mclk followed by hclk) remains unchanged,
so external .dts files and the example section at the end of the
binding are unaffected.

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

Thank you for the guidance. I will address this in v2.

> > The clock descriptions are currently swapped relative to the
> > clock names used by the driver.
>
> Why would order of clock names in the driver matter here? I do not
> understand that explanation.
>

I inferred that 'hclk' is the bus clock from the driver, which uses
devm_regmap_init_mmio_clk() with 'hclk',
and this matches the description found in several Rockchip datasheets.
However, I understand that the binding should be described
independently of the driver implementation.
Therefore, I'll drop this description in the next revision.

Best Regards,
Phuc


From amadeus at jmu.edu.cn  Mon Jun  1 03:10:00 2026
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Mon,  1 Jun 2026 18:10:00 +0800
Subject: [PATCH 1/1] arm64: dts: rockchip: enable button for Radxa E25
Message-ID: <20260601101000.2076721-1-amadeus@jmu.edu.cn>

The Radxa E25 board has an ADC button. Enable it.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
 arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts
index 98cfa3abb809..a091c3a44747 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
 
 /dts-v1/;
+#include <dt-bindings/input/input.h>
 #include "rk3568-radxa-cm3i.dtsi"
 
 / {
@@ -11,6 +12,19 @@ aliases {
 		mmc1 = &sdmmc0;
 	};
 
+	adc-keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 0>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+
+		button-recovery {
+			label = "Recovery";
+			linux,code = <KEY_VENDOR>;
+			press-threshold-microvolt = <0>;
+		};
+	};
+
 	pwm-leds {
 		compatible = "pwm-leds-multicolor";
 
-- 
2.34.1



From heiko at sntech.de  Mon Jun  1 03:20:02 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  1 Jun 2026 12:20:02 +0200
Subject: [PATCH] arm64: dts: rockchip: rk3399-nanopi-r4s: Disable removed devices
In-Reply-To: <20260505172903.33271-1-wens@kernel.org>
References: <20260505172903.33271-1-wens@kernel.org>
Message-ID: <178030918398.239725.10006310705727779216.b4-ty@sntech.de>


On Wed, 06 May 2026 01:29:02 +0800, Chen-Yu Tsai wrote:
> While the design of the NanoPi R4S is based on the common NanoPi 4
> family, it is trimmed down a lot.
> 
> Disable all the peripherals on the SoC that are not used, and delete
> all the external components that are not present.
> 
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: rk3399-nanopi-r4s: Disable removed devices
      commit: 8333fe46b0010d110b36f1628dd8dfc77d2c389a

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Jun  1 03:20:03 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  1 Jun 2026 12:20:03 +0200
Subject: [PATCH] arm64: dts: rockchip: rk3399-nanopi-r4s-enterprise: Fix EEPROM compatible
In-Reply-To: <20260505165244.1902-1-wens@kernel.org>
References: <20260505165244.1902-1-wens@kernel.org>
Message-ID: <178030918399.239725.16965452923012750982.b4-ty@sntech.de>


On Wed, 06 May 2026 00:52:43 +0800, Chen-Yu Tsai wrote:
> The EEPROM used on the R4S (enterprise) is the 24AA025E48T-I/OT from
> MicroChip. This is a 2-Kbit EEPROM with 16-byte page size. The latter
> half of the EEPROM is read-only, and the last 48 bits contain a globally
> unique MAC address. That is to say this is not an ordinary EEPROM.
> 
> The compatible for this type of EEPROM was introduced later that the
> board. Switch over to the correct compatible now that it is available.
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: rk3399-nanopi-r4s-enterprise: Fix EEPROM compatible
      commit: ab1375e25ea3fef62a4a5a93abf5d03d67aaf99c

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Mon Jun  1 03:20:01 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  1 Jun 2026 12:20:01 +0200
Subject: [PATCH v3 0/2] arm64: dts: rockchip: Add peripheral support for Khadas Edge 2L
In-Reply-To: <20260507033541.2576335-1-gray.huang@wesion.com>
References: <20260507033541.2576335-1-gray.huang@wesion.com>
Message-ID: <178030918401.239725.2769966054558634435.b4-ty@sntech.de>


On Thu, 07 May 2026 11:35:39 +0800, Gray Huang wrote:
> This patch series adds support for several key peripherals to the
> Khadas Edge 2L board, which is based on the Rockchip RK3576 SoC.
> 
> These patches build upon the basic board support that was previously
> applied to the rockchip tree. This series enables essential
> functionalities including power management, RTC, wireless connectivity,
> graphics, display output, and USB support.
> 
> [...]

Applied, thanks!

[1/2] arm64: dts: rockchip: Enable USB for Khadas Edge 2L
      commit: 720fe68fd9f138ada2936ffcf3dd0129a889455a
[2/2] arm64: dts: rockchip: Add Bluetooth support for Khadas Edge 2L
      commit: ef81db2fdd5a75e3834a4726dc7837f6d2a7229d

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From andy.yan at rock-chips.com  Mon Jun  1 03:46:13 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:46:13 +0800
Subject: [PATCH 3/5] drm/rockchip: vop2: Delay old_{layer|port}_sel
 updates in setup_layer_mixer()
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-3-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <20260504-vop2-layer-cfg-tmout-v1-3-730226a7331e@collabora.com>
Message-ID: <a476a98f-3cd7-45e8-a726-28a1ab4cdf97@rock-chips.com>

Hello,

On 5/5/26 02:24, Cristian Ciocaltea wrote:
> The old_layer_sel and old_port_sel local variables were introduced to
> hold the previous VP configuration for comparisons and wait targets,
> working around the premature update of vop2->old_layer_sel and
> vop2->old_port_sel earlier in the function.
> 
> Remove these superfluous locals and instead defer the assignments of
> vop2->old_layer_sel and vop2->old_port_sel to just before the
> corresponding shadow register writes, where the transition from old to
> new logically belongs.
> 
> No functional change intended.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
    
    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 21 +++++++++------------
>   1 file changed, 9 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index 5206f01ec787..1f5e8c2acecd 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -2136,9 +2136,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   	struct drm_plane *plane;
>   	u32 layer_sel = 0;
>   	u32 port_sel;
> -	u32 old_layer_sel = 0;
>   	u32 atv_layer_sel = 0;
> -	u32 old_port_sel = 0;
>   	u8 layer_id;
>   	u8 old_layer_id;
>   	u8 layer_sel_id;
> @@ -2161,8 +2159,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   	else
>   		ovl_ctrl &= ~RK3568_OVL_CTRL__YUV_MODE(vp->id);
>   
> -	old_port_sel = vop2->old_port_sel;
> -	port_sel = old_port_sel;
> +	port_sel = vop2->old_port_sel;
>   	port_sel &= RK3568_OVL_PORT_SEL__SEL_PORT;
>   
>   	if (vp0->nlayers)
> @@ -2188,8 +2185,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   		port_sel |= FIELD_PREP(RK3588_OVL_PORT_SET__PORT3_MUX, 7);
>   
>   	atv_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
> -	old_layer_sel = vop2->old_layer_sel;
> -	layer_sel = old_layer_sel;
> +	layer_sel = vop2->old_layer_sel;
>   
>   	ofs = 0;
>   	for (i = 0; i < vp->id; i++)
> @@ -2273,8 +2269,6 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   			     old_win->data->layer_sel_id[vp->id]);
>   	}
>   
> -	vop2->old_layer_sel = layer_sel;
> -	vop2->old_port_sel = port_sel;
>   	/*
>   	 * As the RK3568_OVL_LAYER_SEL and RK3568_OVL_PORT_SEL are shared by all Video Ports,
>   	 * and the configuration take effect by one Video Port's vsync.
> @@ -2290,7 +2284,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   	 *    of the new VP.
>   	 */
>   
> -	if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) {
> +	if (layer_sel != vop2->old_layer_sel && atv_layer_sel != vop2->old_layer_sel) {
>   		cfg_done = vop2_readl(vop2, RK3568_REG_CFG_DONE);
>   		cfg_done &= (BIT(vop2->data->nr_vps) - 1);
>   		cfg_done &= ~BIT(vp->id);
> @@ -2298,20 +2292,23 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   		 * Changes of other VPs' overlays have not taken effect
>   		 */
>   		if (cfg_done)
> -			rk3568_vop2_wait_for_layer_cfg_done(vop2, old_layer_sel);
> +			rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
>   	}
>   
> -	if (layer_sel != old_layer_sel || port_sel != old_port_sel)
> +	if (layer_sel != vop2->old_layer_sel || port_sel != vop2->old_port_sel)
>   		ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
>   	vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
>   
> -	if (port_sel != old_port_sel) {
> +	if (port_sel != vop2->old_port_sel) {
> +		vop2->old_port_sel = port_sel;
>   		vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
>   		vop2_cfg_done(vp);
>   		rk3568_vop2_wait_for_port_mux_done(vop2);
>   	}
>   
> +	vop2->old_layer_sel = layer_sel;
>   	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
> +
>   	mutex_unlock(&vop2->ovl_lock);
>   }
>   
> 



From andy.yan at rock-chips.com  Mon Jun  1 03:44:38 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:44:38 +0800
Subject: [PATCH 1/5] drm/rockchip: vop2: Fix wrong wait target in layer
 cfg done check
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-1-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <20260504-vop2-layer-cfg-tmout-v1-1-730226a7331e@collabora.com>
Message-ID: <2111c699-bf61-4451-b33b-a848b166eb9e@rock-chips.com>

Hello,

On 5/5/26 02:23, Cristian Ciocaltea wrote:
> rk3568_vop2_setup_layer_mixer() waits for the previous Video Port (VP)
> layer configuration to take effect before writing a new one to the
> shared RK3568_OVL_LAYER_SEL shadow register.  However, it passes
> vop2->old_layer_sel to rk3568_vop2_wait_for_layer_cfg_done() as the
> expected value, which at that point already contains the new VP layer.
> 
> This causes the wait to poll for a value that has not been written to
> the shadow register yet, resulting in spurious timeouts when two
> non-blocking atomic commits race:
> 
>    rockchip-drm display-subsystem: [drm] *ERROR* wait layer cfg done timeout [...]
> 
> Pass the local old_layer_sel instead, which still holds the value
> captured from vop2->old_layer_sel before it was overwritten, i.e. the
> previous VP target that the hardware is expected to latch.
> 
> Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>


    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index 02a788a4dfdd..edca0fb16e08 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -2307,7 +2307,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   		 * Changes of other VPs' overlays have not taken effect
>   		 */
>   		if (cfg_done)
> -			rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
> +			rk3568_vop2_wait_for_layer_cfg_done(vop2, old_layer_sel);
>   	}
>   
>   	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
> 



From andy.yan at rock-chips.com  Mon Jun  1 03:46:41 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:46:41 +0800
Subject: [PATCH 4/5] drm/rockchip: vop2: Drop redundant zero-init in
 setup_layer_mixer()
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-4-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <20260504-vop2-layer-cfg-tmout-v1-4-730226a7331e@collabora.com>
Message-ID: <71b11cb4-9c9c-4875-a48f-98cb0e3e0517@rock-chips.com>

Hello,

On 5/5/26 02:24, Cristian Ciocaltea wrote:
> The layer_sel and atv_layer_sel local variables in
> rk3568_vop2_setup_layer_mixer() are unconditionally assigned from
> vop2->old_layer_sel and the RK3568_OVL_LAYER_SEL register read,
> respectively, before any use.
> 
> Remove the superfluous zero-initializers.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
   
    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>


> ---
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index 1f5e8c2acecd..0849bd922ffb 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -2134,9 +2134,9 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   {
>   	struct vop2 *vop2 = vp->vop2;
>   	struct drm_plane *plane;
> -	u32 layer_sel = 0;
> +	u32 layer_sel;
>   	u32 port_sel;
> -	u32 atv_layer_sel = 0;
> +	u32 atv_layer_sel;
>   	u8 layer_id;
>   	u8 old_layer_id;
>   	u8 layer_sel_id;
> 



From andy.yan at rock-chips.com  Mon Jun  1 03:54:25 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:54:25 +0800
Subject: [PATCH 0/5] drm/rockchip: vop2: Fix layer cfg done timeout on
 multi-output setups
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
Message-ID: <2d2b6308-ae46-46fd-b1ce-e4f199b6eb27@rock-chips.com>

Hello Cristian,

On 5/5/26 02:23, Cristian Ciocaltea wrote:
> On RK3588/RK3568 boards with multiple active display outputs, start/stop
> transitions may trigger a timeout during overlay layer configuration:
> 
>    rockchip-drm display-subsystem: [drm] *ERROR* wait layer cfg done timeout
> 
> The shared OVL_LAYER_SEL and OVL_PORT_SEL shadow registers are committed
> to the active configuration at the vsync of whichever Video Port is
> selected by LAYERSEL_REGDONE_SEL.  When two Video Ports race through
> atomic commits, rk3568_vop2_setup_layer_mixer() has two issues that
> cause the wait to poll for a value the hardware might not be able to
> produce.
> 
> Patch 1 fixes passing the wrong target to the wait function, since the
> expected value was already overwritten with the current VP's new
> layer_sel before reaching the wait.
> 
> Patch 2 moves the wait before the LAYERSEL_REGDONE_SEL switch, so the
> previous VP's vsync can still latch the pending configuration.
> 
> Patches 3 through 5 contain only minor follow-up cleanup.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>


Thank you very much for your work, these fixes all look sensible.
However, I haven't been able to construct a scenario via weston that
reproduce these issues. Could you please tell me how you triggered them?

> ---
> Cristian Ciocaltea (5):
>        drm/rockchip: vop2: Fix wrong wait target in layer cfg done check
>        drm/rockchip: vop2: Wait for layer cfg done before switching LAYERSEL_REGDONE_SEL
>        drm/rockchip: vop2: Delay old_{layer|port}_sel updates in setup_layer_mixer()
>        drm/rockchip: vop2: Drop redundant zero-init in setup_layer_mixer()
>        drm/rockchip: vop2: Use vop2->old_layer_sel directly in wait_for_layer_cfg_done()
> 
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 46 +++++++++++++---------------
>   1 file changed, 22 insertions(+), 24 deletions(-)
> ---
> base-commit: d4c14903bf5e28e740516c4fbb7db01e0dedf3af
> change-id: 20260504-vop2-layer-cfg-tmout-73617a0a103c
> 
> 



From andy.yan at rock-chips.com  Mon Jun  1 03:45:28 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:45:28 +0800
Subject: [PATCH 2/5] drm/rockchip: vop2: Wait for layer cfg done before
 switching LAYERSEL_REGDONE_SEL
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-2-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <20260504-vop2-layer-cfg-tmout-v1-2-730226a7331e@collabora.com>
Message-ID: <a92af1c4-cd0e-4d31-9fd1-7e9cae6bb1d1@rock-chips.com>

Hello,

On 5/5/26 02:24, Cristian Ciocaltea wrote:
> LAYERSEL_REGDONE_SEL mask of RK3568_OVL_CTRL register controls which
> Video Port (VP) vsync latches the shared RK3568_OVL_{LAYER|PORT}_SEL
> shadow registers into the active configuration.
> 
> rk3568_vop2_setup_layer_mixer() overwrites LAYERSEL_REGDONE_SEL to the
> current VP ID before waiting for the previous VP layer configuration to
> take effect.  As a consequence, the previous VP vsync can no longer
> trigger the latch, so the wait polls a value that might never appear.
> 
> Move the layer cfg done wait before the RK3568_OVL_CTRL write so the
> previous VP vsync can still commit the pending configuration.
> 
> Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

   
    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 19 ++++++++++---------
>   1 file changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index edca0fb16e08..5206f01ec787 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -2289,15 +2289,6 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   	 *    lead to the configuration of the previous VP being take effect along with the VSYNC
>   	 *    of the new VP.
>   	 */
> -	if (layer_sel != old_layer_sel || port_sel != old_port_sel)
> -		ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
> -	vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
> -
> -	if (port_sel != old_port_sel) {
> -		vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
> -		vop2_cfg_done(vp);
> -		rk3568_vop2_wait_for_port_mux_done(vop2);
> -	}
>   
>   	if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) {
>   		cfg_done = vop2_readl(vop2, RK3568_REG_CFG_DONE);
> @@ -2310,6 +2301,16 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   			rk3568_vop2_wait_for_layer_cfg_done(vop2, old_layer_sel);
>   	}
>   
> +	if (layer_sel != old_layer_sel || port_sel != old_port_sel)
> +		ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id);
> +	vop2_writel(vop2, RK3568_OVL_CTRL, ovl_ctrl);
> +
> +	if (port_sel != old_port_sel) {
> +		vop2_writel(vop2, RK3568_OVL_PORT_SEL, port_sel);
> +		vop2_cfg_done(vp);
> +		rk3568_vop2_wait_for_port_mux_done(vop2);
> +	}
> +
>   	vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel);
>   	mutex_unlock(&vop2->ovl_lock);
>   }
> 



From andy.yan at rock-chips.com  Mon Jun  1 03:47:24 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Mon, 1 Jun 2026 18:47:24 +0800
Subject: [PATCH 5/5] drm/rockchip: vop2: Use vop2->old_layer_sel directly
 in wait_for_layer_cfg_done()
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-5-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <20260504-vop2-layer-cfg-tmout-v1-5-730226a7331e@collabora.com>
Message-ID: <fa6a9fac-9d87-4fa8-b3ae-6e9365130152@rock-chips.com>

Hello,

On 5/5/26 02:24, Cristian Ciocaltea wrote:
> After the old_layer_sel local was removed, the only caller of
> rk3568_vop2_wait_for_layer_cfg_done() already passes vop2->old_layer_sel
> as the expected value.
> 
> Drop the redundant parameter and read the member directly inside the
> function.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

    
    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>


> ---
>   drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index 0849bd922ffb..1d8473a6dfd1 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -2115,7 +2115,7 @@ static u32 rk3568_vop2_read_layer_cfg(struct vop2 *vop2)
>   	return vop2_readl(vop2, RK3568_OVL_LAYER_SEL);
>   }
>   
> -static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
> +static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2)
>   {
>   	u32 atv_layer_cfg;
>   	int ret;
> @@ -2124,10 +2124,10 @@ static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg)
>   	 * Spin until the previous layer configuration is done.
>   	 */
>   	ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg,
> -					atv_layer_cfg == cfg, 10, 50 * 1000);
> +					atv_layer_cfg == vop2->old_layer_sel, 10, 50 * 1000);
>   	if (ret)
>   		drm_err_ratelimited(vop2->drm, "wait layer cfg done timeout: 0x%x--0x%x\n",
> -				    atv_layer_cfg, cfg);
> +				    atv_layer_cfg, vop2->old_layer_sel);
>   }
>   
>   static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
> @@ -2292,7 +2292,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp)
>   		 * Changes of other VPs' overlays have not taken effect
>   		 */
>   		if (cfg_done)
> -			rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel);
> +			rk3568_vop2_wait_for_layer_cfg_done(vop2);
>   	}
>   
>   	if (layer_sel != vop2->old_layer_sel || port_sel != vop2->old_port_sel)
> 



From sebastian.reichel at collabora.com  Mon Jun  1 04:55:36 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 1 Jun 2026 13:55:36 +0200
Subject: [PATCH v4 1/3] dt-bindings: display: bridge: analogix-dp: Add
 data-lanes support for endpoint
In-Reply-To: <20260529040530.741336-2-damon.ding@rock-chips.com>
References: <20260529040530.741336-1-damon.ding@rock-chips.com>
 <20260529040530.741336-2-damon.ding@rock-chips.com>
Message-ID: <ah1y8hRl9M40YNfF@venus>

Hi,

On Fri, May 29, 2026 at 12:05:28PM +0800, Damon Ding wrote:
> Add data-lanes property support to the port at 1 endpoint for physical
> lane mapping configuration.
> 
> Lane mapping is mainly used for below scenarios:
> 1. Correct PCB lane swap and differential line routing crossover
>    without hardware changes;
> 2. Adapt mismatched lane pin definitions between SoC and eDP panel;
> 3. Support multiple panel hardware variants on the same board
>    by configuring data-lanes in device tree only.
> 
> Additionally, add data-lanes setting in Rockchip eDP DT node example
> to show actual lane mapping usage.
> 
> Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
> 
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

Greetings,

-- Sebastian

> Changes in v2:
> - Add lane mapping application scenarios in commit message.
> - Remove redundant deprecated property 'data-lanes' for eDP node.
> - Update port at 1 $ref to /schemas/graph.yaml#/$defs/port-base.
> 
> Changes in v3:
> - Squash data-lanes adjustment of Rockchip eDP DT example into this
>   commit.
> - Add unevaluatedProperties: false to both the port at 1 and endpoint
>   nodes.
> ---
>  .../bindings/display/bridge/analogix,dp.yaml  | 19 ++++++++++++++-----
>  .../rockchip/rockchip,analogix-dp.yaml        |  1 +
>  2 files changed, 15 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
> index 62f0521b0924..ecf206871cdd 100644
> --- a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
> +++ b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
> @@ -42,13 +42,22 @@ properties:
>      properties:
>        port at 0:
>          $ref: /schemas/graph.yaml#/properties/port
> -        description:
> -          Input node to receive pixel data.
> +        description: Input node to receive pixel data.
>  
>        port at 1:
> -        $ref: /schemas/graph.yaml#/properties/port
> -        description:
> -          Port node with one endpoint connected to a dp-connector node.
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: Port node with one endpoint connected to sink device node.
> +        properties:
> +          endpoint:
> +            $ref: /schemas/media/video-interfaces.yaml#
> +            unevaluatedProperties: false
> +            properties:
> +              data-lanes:
> +                minItems: 1
> +                maxItems: 4
> +                items:
> +                  enum: [ 0, 1, 2, 3 ]
>  
>      required:
>        - port at 0
> diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
> index d99b23b88cc5..f690ee393fdb 100644
> --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
> +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
> @@ -117,6 +117,7 @@ examples:
>            reg = <1>;
>  
>            edp_out_panel: endpoint {
> +            data-lanes = <0 1>;
>              remote-endpoint = <&panel_in_edp>;
>            };
>          };
> -- 
> 2.34.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-rockchip/attachments/20260601/978c9de5/attachment-0001.sig>

From sebastian.reichel at collabora.com  Mon Jun  1 04:59:29 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 1 Jun 2026 13:59:29 +0200
Subject: [PATCH v4 3/3] drm/bridge: analogix_dp: Add support for optional
 data-lanes mapping
In-Reply-To: <20260529040530.741336-4-damon.ding@rock-chips.com>
References: <20260529040530.741336-1-damon.ding@rock-chips.com>
 <20260529040530.741336-4-damon.ding@rock-chips.com>
Message-ID: <ah1zPfYFYYLNzbqV@venus>

Hi,

On Fri, May 29, 2026 at 12:05:30PM +0800, Damon Ding wrote:
> Parse the optional 'data-lanes' device tree property to support
> custom physical lane mapping configuration.
> 
> If no valid configuration is found, fall back to the default
> lane map (0, 1, 2, 3) automatically and keep the driver running.
> 
> Lane mapping is mainly used for below scenarios:
> 1. Correct PCB lane swap and differential line routing crossover
>    without hardware changes;
> 2. Adapt mismatched lane pin definitions between SoC and eDP panel;
> 3. Support multiple panel hardware variants on the same board
>    by configuring data-lanes in device tree only.
> 
> Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
> 
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

Greetings,

-- Sebastian

> 
> Changes in v2:
> - Add lane mapping application scenarios in commit message.
> ---
>  .../drm/bridge/analogix/analogix_dp_core.c    | 56 +++++++++++++++++++
>  .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
>  .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
>  .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
>  4 files changed, 70 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 699a7f380c56..b2e729850391 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1234,6 +1234,59 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
>  	.detect = analogix_dp_bridge_detect,
>  };
>  
> +static int analogix_dp_dt_parse_lanes_map(struct analogix_dp_device *dp)
> +{
> +	struct video_info *video_info = &dp->video_info;
> +	struct device_node *endpoint;
> +	u32 tmp[LANE_COUNT4];
> +	u32 map[LANE_COUNT4] = {0, 1, 2, 3};
> +	bool used[LANE_COUNT4] = {false};
> +	int num_lanes;
> +	int ret, i;
> +
> +	memcpy(video_info->lane_map, map, sizeof(map));
> +
> +	num_lanes = drm_of_get_data_lanes_count_ep(dp->dev->of_node, 1, 0, 1,
> +						   video_info->max_lane_count);
> +	if (num_lanes < 0)
> +		return -EINVAL;
> +
> +	endpoint = of_graph_get_endpoint_by_regs(dp->dev->of_node, 1, -1);
> +	if (!endpoint)
> +		return -EINVAL;
> +
> +	ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, num_lanes);
> +	of_node_put(endpoint);
> +	if (ret)
> +		return -EINVAL;
> +
> +	for (i = 0; i < num_lanes; i++) {
> +		if (tmp[i] >= LANE_COUNT4) {
> +			dev_dbg(dp->dev, "data-lanes[%d] = %u is out of range\n", i, tmp[i]);
> +			return -EINVAL;
> +		}
> +
> +		if (used[tmp[i]]) {
> +			dev_dbg(dp->dev, "data-lanes[%d] = %u is duplicate\n", i, tmp[i]);
> +			return -EINVAL;
> +		}
> +
> +		used[tmp[i]] = true;
> +		map[i] = tmp[i];
> +	}
> +
> +	for (i = 0; i < LANE_COUNT4 && num_lanes < LANE_COUNT4; i++) {
> +		if (!used[i])
> +			map[num_lanes++] = i;
> +	}
> +
> +	dev_dbg(dp->dev, "Using parsed lane map: <%u %u %u %u>\n", map[0], map[1], map[2], map[3]);
> +
> +	memcpy(video_info->lane_map, map, sizeof(map));
> +
> +	return 0;
> +}
> +
>  static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
>  {
>  	struct device_node *dp_node = dp->dev->of_node;
> @@ -1274,6 +1327,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
>  		break;
>  	}
>  
> +	if (analogix_dp_dt_parse_lanes_map(dp))
> +		dev_dbg(dp->dev, "No valid data-lanes found, using default lane map\n");
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> index 17347448c6b0..634fad241e69 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
> @@ -137,6 +137,8 @@ struct video_info {
>  
>  	int max_link_rate;
>  	enum link_lane_count_type max_lane_count;
> +
> +	u32 lane_map[LANE_COUNT4];
>  };
>  
>  struct link_train {
> @@ -175,7 +177,7 @@ struct analogix_dp_device {
>  /* analogix_dp_reg.c */
>  void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable);
>  void analogix_dp_stop_video(struct analogix_dp_device *dp);
> -void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable);
> +void analogix_dp_lane_mapping(struct analogix_dp_device *dp);
>  void analogix_dp_init_analog_param(struct analogix_dp_device *dp);
>  void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
>  void analogix_dp_reset(struct analogix_dp_device *dp);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> index 38fd8d5014d2..45c7652645a1 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
> @@ -48,16 +48,15 @@ void analogix_dp_stop_video(struct analogix_dp_device *dp)
>  	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
>  }
>  
> -void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
> +void analogix_dp_lane_mapping(struct analogix_dp_device *dp)
>  {
> +	u32 *lane_map = dp->video_info.lane_map;
>  	u32 reg;
>  
> -	if (enable)
> -		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
> -		      LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
> -	else
> -		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
> -		      LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
> +	reg = lane_map[0] << LANE0_MAP_SHIFT;
> +	reg |= lane_map[1] << LANE1_MAP_SHIFT;
> +	reg |= lane_map[2] << LANE2_MAP_SHIFT;
> +	reg |= lane_map[3] << LANE3_MAP_SHIFT;
>  
>  	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
>  }
> @@ -140,7 +139,7 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
>  
>  	usleep_range(20, 30);
>  
> -	analogix_dp_lane_swap(dp, 0);
> +	analogix_dp_lane_mapping(dp);
>  
>  	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
>  	writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> index 12735139046c..ac914e37089b 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
> @@ -209,6 +209,10 @@
>  #define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
>  #define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
>  #define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
> +#define LANE3_MAP_SHIFT				(6)
> +#define LANE2_MAP_SHIFT				(4)
> +#define LANE1_MAP_SHIFT				(2)
> +#define LANE0_MAP_SHIFT				(0)
>  
>  /* ANALOGIX_DP_ANALOG_CTL_1 */
>  #define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
> -- 
> 2.34.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-rockchip/attachments/20260601/8a6ef2d2/attachment.sig>

From luca.ceresoli at bootlin.com  Mon Jun  1 05:02:48 2026
From: luca.ceresoli at bootlin.com (Luca Ceresoli)
Date: Mon, 01 Jun 2026 14:02:48 +0200
Subject: [PATCH v4 2/3] drm/bridge: analogix_dp: Add validation for
 samsung,lane-count property
In-Reply-To: <17160115-6c30-434b-9dab-b768110cd8d6@rock-chips.com>
References: <20260529040530.741336-1-damon.ding@rock-chips.com>
 <20260529040530.741336-3-damon.ding@rock-chips.com>
 <178014803941.21632.16225608049285101452.b4-review@b4>
 <DIW1WGLL0GW5.1BGU194UXN0HO@bootlin.com>
 <17160115-6c30-434b-9dab-b768110cd8d6@rock-chips.com>
Message-ID: <178031536852.7135.7751258958371598959.b4-reply@b4>

Hello Damon,

On 2026-06-01 10:59:27+08:00, Damon Ding wrote:
> Hi Luca,
>
> On 5/30/2026 9:38 PM, Luca Ceresoli wrote:
>
> > On Sat May 30, 2026 at 3:33 PM CEST, Luca Ceresoli wrote:
> >
> > Meh, messed up with 'b4 review' :-/ Apologies
> >
> > "This sashiko report" [0] was about an enum being signed, so '== 0' could miss
> > negative numbers coming from bogus DT values higher than 1^31.
>
> Ah, I agree. It would be better to add a new inline function to validate
> that the lane count passed from DT is exactly 1, 2, or 4, just as
> Sashiko suggested.
>
> >>
> >
> > And this was about "Additionally, does this check inadvertently allow 3,
> > which is an invalid DisplayPort lane count?"
>
> Yes, the DisplayPort specification only allows lane counts of 1, 2, or
> 4. I did miss the check for the invalid value 3 in the current code.
>
> (BTW: I did not find a common helper function in drm_dp_helper.h to
> validate valid DP lane counts (1, 2, 4). I'm not sure if it would be
> better to add a generic lane count validation function to the DP helper
> library instead, to avoid duplicating the same functionality across
> individual DP drivers. Perhaps other DP experts could provide some
> advice on this.)

A bool function in common code, to be reused by all DP drivers, would be
good.



From damon.ding at rock-chips.com  Mon Jun  1 05:24:42 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Mon, 1 Jun 2026 20:24:42 +0800
Subject: [PATCH v4 2/3] drm/bridge: analogix_dp: Add validation for
 samsung,lane-count property
In-Reply-To: <178031536852.7135.7751258958371598959.b4-reply@b4>
References: <20260529040530.741336-1-damon.ding@rock-chips.com>
 <20260529040530.741336-3-damon.ding@rock-chips.com>
 <178014803941.21632.16225608049285101452.b4-review@b4>
 <DIW1WGLL0GW5.1BGU194UXN0HO@bootlin.com>
 <17160115-6c30-434b-9dab-b768110cd8d6@rock-chips.com>
 <178031536852.7135.7751258958371598959.b4-reply@b4>
Message-ID: <ba122231-0def-4b62-add7-be3382f07805@rock-chips.com>

On 6/1/2026 8:02 PM, Luca Ceresoli wrote:
> Hello Damon,
> 
> On 2026-06-01 10:59:27+08:00, Damon Ding wrote:
>> Hi Luca,
>>
>> On 5/30/2026 9:38 PM, Luca Ceresoli wrote:
>>
>>> On Sat May 30, 2026 at 3:33 PM CEST, Luca Ceresoli wrote:
>>>
>>> Meh, messed up with 'b4 review' :-/ Apologies
>>>
>>> "This sashiko report" [0] was about an enum being signed, so '== 0' could miss
>>> negative numbers coming from bogus DT values higher than 1^31.
>>
>> Ah, I agree. It would be better to add a new inline function to validate
>> that the lane count passed from DT is exactly 1, 2, or 4, just as
>> Sashiko suggested.
>>
>>>>
>>>
>>> And this was about "Additionally, does this check inadvertently allow 3,
>>> which is an invalid DisplayPort lane count?"
>>
>> Yes, the DisplayPort specification only allows lane counts of 1, 2, or
>> 4. I did miss the check for the invalid value 3 in the current code.
>>
>> (BTW: I did not find a common helper function in drm_dp_helper.h to
>> validate valid DP lane counts (1, 2, 4). I'm not sure if it would be
>> better to add a generic lane count validation function to the DP helper
>> library instead, to avoid duplicating the same functionality across
>> individual DP drivers. Perhaps other DP experts could provide some
>> advice on this.)
> 
> A bool function in common code, to be reused by all DP drivers, would be
> good.
> 
> 
> 

Yes, will do in v5.

Best regards,
Damon



From hrushirajg23 at gmail.com  Mon Jun  1 05:36:02 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 18:06:02 +0530
Subject: [PATCH 0/1] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601123603.129679-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - SDIO Wi-Fi
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

This patch adds the DTS file and wires it into the Makefile. Binding
documentation for the vendor prefix "vicharak" and the compatible string
"vicharak,axon" will be submitted as a follow-up to this series.

Hrushiraj Gandhi (1):
  arm64: dts: rockchip: add Vicharak Axon board

 arch/arm64/boot/dts/rockchip/Makefile        |    1 +
 arch/arm64/boot/dts/rockchip/rk3588-axon.dts | 1069 ++++++++++++++++++
 2 files changed, 1070 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 05:36:03 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 18:06:03 +0530
Subject: [PATCH 1/1] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601123603.129679-1-hrushirajg23@gmail.com>
References: <20260601123603.129679-1-hrushirajg23@gmail.com>
Message-ID: <20260601123603.129679-2-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile        |    1 +
 arch/arm64/boot/dts/rockchip/rk3588-axon.dts | 1069 ++++++++++++++++++
 2 files changed, 1070 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..503927ffa849 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-axon.dts
new file mode 100644
index 000000000000..dcab9462f51b
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-axon.dts
@@ -0,0 +1,1069 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: pcie20-avdd0v85-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie20_avdd1v8: pcie20-avdd1v8-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: pcie30-avdd0v75-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: pcie30-avdd1v8-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		clocks = <&hym8563>;
+		clock-names = "ext_clock";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdio_reset_wifi>;
+		reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
+		status = "okay";
+	};
+
+	vcc0_4v0: vcc4v0_sys: vcc0-4v0-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: vcc12v-dcin-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: vcc1-5v0-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: vcc5v0-usb20-host-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+	mem-supply = <&vdd_cpu_big0_mem_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+	mem-supply = <&vdd_cpu_big0_mem_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+	mem-supply = <&vdd_cpu_big1_mem_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+	mem-supply = <&vdd_cpu_big1_mem_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+	mem-supply = <&vdd_cpu_lit_mem_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	enable-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	enable-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: vdd_cpu_big0_mem_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-compatible = "rk860x-reg";
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: vdd_cpu_big1_mem_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-compatible = "rk860x-reg";
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c3 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c3m0_xfer>;
+	status = "okay";
+
+	es8388: audio-codec at 11 {
+		compatible = "everest,es8388";
+		reg = <0x11>;
+		clocks = <&cru I2S0_8CH_MCLKOUT>;
+		clock-names = "mclk";
+		assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
+		assigned-clock-rates = <12288000>;
+		DVDD-supply = <&vcc_1v8_s0>;
+		AVDD-supply = <&vcc_3v3_s0>;
+		PVDD-supply = <&vcc_1v8_s0>;
+		HPVDD-supply = <&vcc_3v3_s0>;
+		#sound-dai-cells = <0>;
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdio {
+	max-frequency = <150000000>;
+	no-sd;
+	no-mmc;
+	bus-width = <4>;
+	disable-wp;
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&sdio_pwrseq>;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdiom0_pins>;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-init-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	wireless-wlan {
+		sdio_reset_wifi: sdio-reset-wifi {
+			rockchip,pins =
+				<4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&u2phy1 {
+	status = "okay";
+};
+
+&u2phy1_otg {
+	status = "okay";
+};
+
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From heiko at sntech.de  Mon Jun  1 05:51:22 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 01 Jun 2026 14:51:22 +0200
Subject: [PATCH 1/1] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601123603.129679-2-hrushirajg23@gmail.com>
References: <20260601123603.129679-1-hrushirajg23@gmail.com>
 <20260601123603.129679-2-hrushirajg23@gmail.com>
Message-ID: <10605990.5OynTdThKG@phil>

Hi,

Am Montag, 1. Juni 2026, 14:36:03 Mitteleurop?ische Sommerzeit schrieb Hrushiraj Gandhi:
> Add initial support for the Vicharak Axon single-board computer based on
> the Rockchip RK3588 SoC.
> 
> The board supports:
> 
> - eMMC storage
> - microSD card
> - Gigabit Ethernet
> - HDMI output (dual HDMI)
> - HDMI input
> - USB 2.0 host ports
> - PCIe 2.0 slots
> - PCIe 3.0 x4 slot
> - SATA
> - RTC
> - Status LEDs
> 
> The board uses an RK806 PMIC and provides the regulators required by
> the RK3588 SoC.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
> ---
>  arch/arm64/boot/dts/rockchip/Makefile        |    1 +
>  arch/arm64/boot/dts/rockchip/rk3588-axon.dts | 1069 ++++++++++++++++++

this is missing the addition of the board dt binding.
(in a separate patch)

Please see how other boards are handled in the git histoy.


>  2 files changed, 1070 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-axon.dts
> 
> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
> index cb55c6b70d0e..503927ffa849 100644
> --- a/arch/arm64/boot/dts/rockchip/Makefile
> +++ b/arch/arm64/boot/dts/rockchip/Makefile
> @@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-axon.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-axon.dts

please name that
rk3588-vicharak-axon.dts


> new file mode 100644
> index 000000000000..dcab9462f51b
> --- /dev/null
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-axon.dts
> @@ -0,0 +1,1069 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/linux-event-codes.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
> +#include <dt-bindings/usb/pd.h>
> +#include "rk3588.dtsi"
> +
> +/ {
> +	model = "Vicharak Axon";
> +	compatible = "vicharak,axon", "rockchip,rk3588";
> +
> +	aliases {
> +		mmc0 = &sdmmc;
> +		mmc1 = &sdhci;
> +		mmc2 = &sdio;
> +		serial2 = &uart2;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial2:1500000n8";
> +	};
> +
> +	hdmi0-con {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi0_con_in: endpoint {
> +				remote-endpoint = <&hdmi0_out_con>;
> +			};
> +		};
> +	};
> +
> +	hdmi1-con {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi1_con_in: endpoint {
> +				remote-endpoint = <&hdmi1_out_con>;
> +			};
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +		status = "okay";
> +
> +		power_led: power-led {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_STATUS;
> +			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
> +			linux,default-trigger = "heartbeat";
> +		};
> +
> +		status_led: status-led {
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_STATUS;
> +			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
> +			linux,default-trigger = "none";
> +		};
> +	};
> +
> +	pcie20_avdd0v85: pcie20-avdd0v85-regulator {

regulator nodes, should be like "pcie20_avdd0v85: regulator-pcie20-avdd0v85 {"

> +&cpu_b0 {
> +	cpu-supply = <&vdd_cpu_big0_s0>;
> +	mem-supply = <&vdd_cpu_big0_mem_s0>;

mem-supply for cpu-cores is vendor-kernel stuff (and it's the same
regulator anyway), so please
- drop those properties,
- drop the phandle

and run
make ARCH=arm64 CHECK_DTBS=y rockchip/rk3588-axon.dtb

and fix all the reported issues please.


Thanks
Heiko






From sebastian.reichel at collabora.com  Mon Jun  1 05:55:25 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 1 Jun 2026 14:55:25 +0200
Subject: [PATCH v2 2/2] arm64: dts: rockchip: fix PCIe regulator name on
 NanoPC-T6
In-Reply-To: <20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-2-49700248143f@pardini.net>
References: <20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-0-49700248143f@pardini.net>
 <20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-2-49700248143f@pardini.net>
Message-ID: <ah2AYT4XmYR03I7z@venus>

Hi,

On Fri, May 29, 2026 at 05:31:25PM +0200, Ricardo Pardini via B4 Relay wrote:
> From: Ricardo Pardini <ricardo at pardini.net>
> 
> The GPIO-switched 3v3 regulator on the NanoPC-T6 is labeled
> vcc3v3_pcie2x1l0, but it is wired to and consumed by &pcie2x1l1, and
> its enable is the pcie_m2_1_pwren pin - i.e. it powers the M.2 slot on
> pcie2x1l1, not pcie2x1l0. The two soldered RTL8125 NICs on pcie2x1l0
> and pcie2x1l2 instead share the always-on vcc_3v3_pcie20 rail, so
> nothing actually uses an "l0" switched supply.
> 
> Rename the label, node name and regulator-name to vcc3v3_pcie2x1l1 so
> they match the controller the rail actually supplies.
> 
> Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
> ---

You should use the regulator name from the schematics. I had a quick
look and https://wiki.friendlyelec.com/wiki/images/9/97/NanoPC-T6_2301_SCH.PDF
describes the GPIO as PCIE_M2_1_PWREN as you mention in your commit
message. That GPIO controls a regulator for the power net "VDD_MPCIE_3.3V".
So that's the expected name :)

Greetings,

-- Sebastian

>  arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
> index 04c4479f08170..7d314df3f947b 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
> @@ -203,13 +203,13 @@ vbus5v0_usb: regulator-vbus5v0-usb {
>  		vin-supply = <&vcc5v0_sys>;
>  	};
>  
> -	vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 {
> +	vcc3v3_pcie2x1l1: regulator-vcc3v3-pcie2x1l1 {
>  		compatible = "regulator-fixed";
>  		enable-active-high;
>  		gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
>  		pinctrl-names = "default";
>  		pinctrl-0 = <&pcie_m2_1_pwren>;
> -		regulator-name = "vcc3v3_pcie2x1l0";
> +		regulator-name = "vcc3v3_pcie2x1l1";
>  		regulator-min-microvolt = <3300000>;
>  		regulator-max-microvolt = <3300000>;
>  		vin-supply = <&vcc5v0_sys>;
> @@ -655,7 +655,7 @@ rtl_eth0: ethernet at 0,0 {
>  
>  &pcie2x1l1 {
>  	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
> -	vpcie3v3-supply = <&vcc3v3_pcie2x1l0>;
> +	vpcie3v3-supply = <&vcc3v3_pcie2x1l1>;
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&pcie2_1_rst>;
>  	status = "okay";
> 
> -- 
> 2.54.0
> 
> 
-------------- 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-rockchip/attachments/20260601/7034734b/attachment.sig>

From sebastian.reichel at collabora.com  Mon Jun  1 06:05:00 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 1 Jun 2026 15:05:00 +0200
Subject: [PATCH v2 0/2] describe PCIe ethernet interfaces and alias
 ethernet0/1 on NanoPC-T6
In-Reply-To: <20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-0-49700248143f@pardini.net>
References: <20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-0-49700248143f@pardini.net>
Message-ID: <ah2BWZzNBn7pZubu@venus>

Hi,

On Fri, May 29, 2026 at 05:31:23PM +0200, Ricardo Pardini via B4 Relay wrote:
> This describes the two on-board Realtek RTL8125BG PCIe Ethernet
> controllers on the FriendlyElec NanoPC-T6 (RK3588) board and aliases
> them to ethernet0/ethernet1.
> 
> Many Rockchip boards have on-board RTL8125 PCIe NICs, wired to
> pcie2x1l0 and pcie2x1l2. The controllers were already enabled in the
> board DT, but the Ethernet function nodes themselves are not
> described, so the kernel (and u-boot) has no DT handle on the NICs.
> 
> Adding the function nodes lets us:
> - expose stable ethernet0/ethernet1 aliases for the two NICs, the
>   same way other rk3588 boards alias their GMAC interfaces; and
> - let U-Boot's fdt_fixup_ethernet() patch mac-address properties in
>   at boot time from its ethaddr/eth1addr environment - useful on
>   boards (like this one) whose on-NIC EEPROM is not pre-programmed
>   with a unique MAC. The kernel and U-Boot then agree on the MAC,
>   which matters for network-boot setups.

This is the patch rationale and thus should be part of the commit
message in the first patch.

> Checkpatch warnings:
> -  WARNING: DT compatible string "pci10ec,8125" appears un-documented
> -  WARNING: DT compatible string vendor "pci10ec" appears un-documented
> Both are expected. "pciVVVV,DDDD" is the Open Firmware PCI Bus
> Binding spelling, where VVVV/DDDD are the PCI vendor and device IDs
> allocated by the PCI-SIG (10ec = Realtek, 8125 = RTL8125). It is not a
> DT vendor prefix.

No, it is not expected. We need some binding for it :) This is
similar to USB, see e.g.

Documentation/devicetree/bindings/net/microchip,lan95xx.yaml

Greetings,

-- Sebastian

> If this is seen as a good thing, it would apply very similarly to
> the Radxa Rock 5 series and others.
> 
> While at it, rename regulator vcc3v3_pcie2x1l0 to l1, since that is
> what is actually powers; since only cosmetic, I did not include
> a Fixes tag.
> 
> ---
> Changes in v2:
> - fix: pcie2x1l0, not pcie2x1l1; indirectly caught by Sashiko's review [1]
> - while-at-it: rename regulator vcc3v3_pcie2x1l0 to l1
> - Link to v1: https://patch.msgid.link/20260525-rk3588-dts-rtl-eth-describe-dt-alias-v1-1-a6fcda563ac7 at pardini.net
> 
> [1] https://sashiko.dev/#/patchset/20260525-rk3588-dts-rtl-eth-describe-dt-alias-v1-1-a6fcda563ac7%40pardini.net
> 
> To: Rob Herring <robh at kernel.org>
> To: Krzysztof Kozlowski <krzk+dt at kernel.org>
> To: Conor Dooley <conor+dt at kernel.org>
> To: Heiko Stuebner <heiko at sntech.de>
> Cc: Sebastian Reichel <sebastian.reichel at collabora.com>
> Cc: devicetree at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org
> Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
> 
> ---
> Ricardo Pardini (2):
>       arm64: dts: rockchip: describe PCIe Ethernet controllers on NanoPC-T6
>       arm64: dts: rockchip: fix PCIe regulator name on NanoPC-T6
> 
>  arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 36 ++++++++++++++++++++--
>  1 file changed, 33 insertions(+), 3 deletions(-)
> ---
> base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
> change-id: 20260524-rk3588-dts-rtl-eth-describe-dt-alias-c1ed187b7c50
> 
> Best regards,
> --  
> Ricardo Pardini <ricardo at pardini.net>
> 
> 
-------------- 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-rockchip/attachments/20260601/439bea63/attachment.sig>

From hrushirajg23 at gmail.com  Mon Jun  1 06:25:27 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 18:55:27 +0530
Subject: [PATCH v2 0/2] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601132529.139172-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - SDIO Wi-Fi
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v1:
- Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
- Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
- Renamed regulator nodes to the standard `regulator-name` pattern
- Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
- Fixed pcie20_avdd0v85 vin-supply mismatch
- Removed obsolete `regulator-compatible` property
- Removed invalid `regulator-init-microvolt` property
- Removed dangling `enable-active-high` properties from fixed regulators
- Cleaned up unneeded i2c3 / es8388 nodes
- Added missing `vpcie3v3-supply` properties to PCIe nodes

Hrushiraj Gandhi (2):
  arm64: dts: rockchip: add Vicharak Axon board
  dt-bindings: arm: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |    5 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 1038 +++++++++++++++++
 4 files changed, 1046 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 06:25:28 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 18:55:28 +0530
Subject: [PATCH v2 1/2] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601132529.139172-1-hrushirajg23@gmail.com>
References: <20260601132529.139172-1-hrushirajg23@gmail.com>
Message-ID: <20260601132529.139172-2-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 1038 +++++++++++++++++
 2 files changed, 1039 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..fcb115b02eff 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..fecd13a52e88
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,1038 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: regulator-sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		clocks = <&hym8563>;
+		clock-names = "ext_clock";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdio_reset_wifi>;
+		reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
+		status = "okay";
+	};
+
+	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	enable-gpios = <&gpio1 RK_PB0 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	enable-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdio {
+	max-frequency = <150000000>;
+	no-sd;
+	no-mmc;
+	bus-width = <4>;
+	disable-wp;
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&sdio_pwrseq>;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdiom0_pins>;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	wireless-wlan {
+		sdio_reset_wifi: sdio-reset-wifi {
+			rockchip,pins =
+				<4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&u2phy1 {
+	status = "okay";
+};
+
+&u2phy1_otg {
+	status = "okay";
+};
+
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 06:25:29 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 18:55:29 +0530
Subject: [PATCH v2 2/2] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601132529.139172-1-hrushirajg23@gmail.com>
References: <20260601132529.139172-1-hrushirajg23@gmail.com>
Message-ID: <20260601132529.139172-3-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC, and add the vicharak
vendor prefix to the vendor-prefixes list.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml    | 5 +++++
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 28784d66ae7b..504a691a33b9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1791,6 +1791,8 @@ patternProperties:
     description: VIA Technologies, Inc.
   "^vialab,.*":
     description: VIA Labs, Inc.
+  "^vicharak,.*":
+    description: Vicharak Computers Pvt. Ltd.
   "^vicor,.*":
     description: Vicor Corporation
   "^videostrong,.*":
-- 
2.47.3



From andyshrk at 163.com  Mon Jun  1 06:44:15 2026
From: andyshrk at 163.com (Andy Yan)
Date: Mon, 1 Jun 2026 21:44:15 +0800 (CST)
Subject: [PATCH 0/2] YUV support for VOP2 background color
In-Reply-To: <20260524-vop2-bg-yuv-v1-0-dcb6a52923f5@collabora.com>
References: <20260524-vop2-bg-yuv-v1-0-dcb6a52923f5@collabora.com>
Message-ID: <8061cc0.a9f1.19e836d8cf0.Coremail.andyshrk@163.com>


Hello Cristian,

At 2026-05-25 00:27:27, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>Since commit bec7cbfa7d4f ("drm/rockchip: vop2: Support setting custom
>background color") the VOP2 display controller allows configuring the
>background color of each video output port.
>
>However, this is currently limited to RGB formats.  When operating in
>YUV overlay mode, the color must be programmed using YUV format.
>
>Add the necessary RGB-to-YCbCr conversion logic, covering all color
>spaces supported by the display controller: BT601L, BT601F, BT709L and
>BT2020L.
>


Do you currently have a branch that makes dw-hdmi-qp output in YUV mode ?

>Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>---
>Cristian Ciocaltea (2):
>      drm/rockchip: vop2: Rename CSC_BT2020 to CSC_BT2020L
>      drm/rockchip: vop2: Add YUV support to background color
>
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 154 ++++++++++++++++++++++++---
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |   2 +-
> 2 files changed, 139 insertions(+), 17 deletions(-)
>---
>base-commit: 213c92ac9717e4951f052a499f91c89302889813
>change-id: 20260524-vop2-bg-yuv-1b0e6a09c579
>

From macromorgan at hotmail.com  Mon Jun  1 06:50:02 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 1 Jun 2026 08:50:02 -0500
Subject: [PATCH V9 06/11] iio: imu: inv_icm42607: Add Buffer support for
 icm42607
In-Reply-To: <20260531133801.481e173c@jic23-huawei>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
 <20260530031739.109063-7-macroalpha82@gmail.com>
 <20260531133801.481e173c@jic23-huawei>
Message-ID: <PH0PR19MB997338785108348427BBB2B7D2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>

On Sun, May 31, 2026 at 01:38:01PM +0100, Jonathan Cameron wrote:
> On Fri, 29 May 2026 22:17:33 -0500
> Chris Morgan <macroalpha82 at gmail.com> wrote:
> 
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Add all FIFO parsing and reading functions to support
> > inv_icm42607 hardware.
> > 
> > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> A few things inline.
> 
> J
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > new file mode 100644
> > index 000000000000..e065d60ac119
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > @@ -0,0 +1,483 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (C) 2026 InvenSense, Inc.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/iio/buffer.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/minmax.h>
> > +#include <linux/mutex.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> > +#include <linux/unaligned.h>
> > +
> > +#include <linux/iio/common/inv_sensors_timestamp.h>
> > +
> > +#include "inv_icm42607.h"
> > +#include "inv_icm42607_buffer.h"
> > +
> > +/* FIFO header: 1 byte */
> > +#define INV_ICM42607_FIFO_HEADER_MSG		BIT(7)
> > +#define INV_ICM42607_FIFO_HEADER_ACCEL		BIT(6)
> > +#define INV_ICM42607_FIFO_HEADER_GYRO		BIT(5)
> > +#define INV_ICM42607_FIFO_HEADER_TMST_FSYNC	GENMASK(3, 2)
> > +#define INV_ICM42607_FIFO_HEADER_ODR_ACCEL	BIT(1)
> > +#define INV_ICM42607_FIFO_HEADER_ODR_GYRO	BIT(0)
> > +
> > +struct inv_icm42607_fifo_1sensor_packet {
> > +	u8 header;
> > +	struct inv_icm42607_fifo_sensor_data data;
> > +	s8 temp;
> > +} __packed;
> > +
> > +struct inv_icm42607_fifo_2sensors_packet {
> > +	u8 header;
> > +	struct inv_icm42607_fifo_sensor_data accel;
> Good example of the need for the inner structures to be packed

Are you saying I should set the inv_icm42607_fifo_sensor_data to be
__packed? I think I was told in a previous patch not to do that, but
I can add it back.

> 
> > +	struct inv_icm42607_fifo_sensor_data gyro;
> > +	s8 temp;
> > +	__be16 timestamp;
> > +} __packed;
> > +
> > +ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel,
> > +					const void **gyro, const int8_t **temp,
> > +					const void **timestamp)
> > +{
> > +	const struct inv_icm42607_fifo_1sensor_packet *pack1 = get_unaligned(&packet);
> > +	const struct inv_icm42607_fifo_2sensors_packet *pack2 = get_unaligned(&packet);
> 
> Hmm. Sashiko points out you are messing around with pointers here and it's not those but
> what the point to that we need to worry about alignment for.
> You could memcpy that data into local structures.

I still suck at pointers, sorry. What exactly would you recommend here?
memcpy the packet value into an allocated
inv_icm42607_fifo_1sensor_packet or inv_icm42607_fifo_2sensors_packet?

> 
> 
> > +	u8 header = *((const u8 *)packet);
> > +
> > +	/* FIFO empty */
> > +	if (header & INV_ICM42607_FIFO_HEADER_MSG) {
> > +		*accel = NULL;
> > +		*gyro = NULL;
> > +		*temp = NULL;
> > +		*timestamp = NULL;
> > +		return 0;
> > +	}
> > +
> > +	/* accel + gyro */
> > +	if ((header & INV_ICM42607_FIFO_HEADER_ACCEL) &&
> > +	    (header & INV_ICM42607_FIFO_HEADER_GYRO)) {
> > +		*accel = &pack2->accel;
> > +		*gyro = &pack2->gyro;
> > +		*temp = &pack2->temp;
> > +		*timestamp = &pack2->timestamp;
> > +		return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE;
> > +	}
> > +
> > +	/* accel only */
> > +	if (header & INV_ICM42607_FIFO_HEADER_ACCEL) {
> > +		*accel = &pack1->data;
> > +		*gyro = NULL;
> > +		*temp = &pack1->temp;
> > +		*timestamp = NULL;
> > +		return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
> > +	}
> > +
> > +	/* gyro only */
> > +	if (header & INV_ICM42607_FIFO_HEADER_GYRO) {
> > +		*accel = NULL;
> > +		*gyro = &pack1->data;
> > +		*temp = &pack1->temp;
> > +		*timestamp = NULL;
> > +		return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
> > +	}
> > +
> > +	/* invalid packet if here */
> > +	return -EINVAL;
> > +}
> 
> > +/**
> > + * inv_icm42607_buffer_update_watermark - update watermark FIFO threshold
> > + * @st:	driver internal state
> > + *
> > + * Returns 0 on success, a negative error code otherwise.
> > + */
> > +int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st)
> > +{
> > +	const struct device *dev = regmap_get_device(st->map);
> > +	unsigned int wm_gyro, wm_accel, watermark;
> > +	u32 latency_gyro, latency_accel, latency;
> > +	u32 period_gyro, period_accel;
> > +	size_t packet_size, wm_size;
> > +	__le16 raw_wm;
> > +	bool restore;
> > +	int ret;
> > +
> > +	packet_size = inv_icm42607_get_packet_size(st->fifo.en);
> > +
> > +	/* compute sensors latency, depending on sensor watermark and odr */
> > +	wm_gyro = inv_icm42607_wm_truncate(st->fifo.watermark.gyro, packet_size);
> > +	wm_accel = inv_icm42607_wm_truncate(st->fifo.watermark.accel, packet_size);
> > +	/* use us for odr to avoid overflow using 32 bits values */
> > +	period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr) / 1000UL;
> > +	period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr) / 1000UL;
> > +	latency_gyro = period_gyro * wm_gyro;
> > +	latency_accel = period_accel * wm_accel;
> > +
> > +	/* 0 value for watermark means that the sensor is turned off */
> > +	if (wm_gyro == 0 && wm_accel == 0)
> > +		return 0;
> > +
> > +	if (latency_gyro == 0) {
> > +		watermark = wm_accel;
> > +		st->fifo.watermark.eff_accel = wm_accel;
> > +	} else if (latency_accel == 0) {
> > +		watermark = wm_gyro;
> > +		st->fifo.watermark.eff_gyro = wm_gyro;
> > +	} else {
> > +		/* compute the smallest latency that is a multiple of both */
> > +		if (latency_gyro <= latency_accel)
> > +			latency = latency_gyro - (latency_accel % latency_gyro);
> > +		else
> > +			latency = latency_accel - (latency_gyro % latency_accel);
> > +		/* all this works because periods are multiple of each others */
> > +		watermark = latency / min(period_gyro, period_accel);
> > +		watermark = max(watermark, 1);
> > +		/* update effective watermark */
> > +		st->fifo.watermark.eff_gyro = max(latency / period_gyro, 1);
> > +		st->fifo.watermark.eff_accel = max(latency / period_accel, 1);
> > +	}
> > +
> > +	/* changing FIFO watermark requires to turn off watermark interrupt */
> > +	ret = regmap_update_bits_check(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > +				       INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > +				       0, &restore);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* compute watermark value in bytes */
> > +	wm_size = watermark * packet_size;
> > +	raw_wm = INV_ICM42607_FIFO_WATERMARK_VAL(wm_size);
> > +	memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
> > +	ret = regmap_bulk_write(st->map, INV_ICM42607_REG_FIFO_CONFIG2,
> > +				st->buffer, sizeof(raw_wm));
> > +	if (ret) {
> > +		dev_err(dev, "Unable to change watermark value: %d\n", ret);
> > +		if (restore)
> > +			regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > +					   INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > +					   INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
> 
> set_bits.
> 
> > +		return ret;
> > +	}
> > +
> > +	/* restore watermark interrupt */
> > +	if (restore) {
> > +		ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > +					 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > +					 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
> 
> set_bits
> 
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> > +
> > +static int inv_icm42607_buffer_predisable(struct iio_dev *indio_dev)
> > +{
> > +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> > +	int ret;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	if (st->fifo.on > 1) {
> > +		st->fifo.on--;
> > +		return 0;
> > +	}
> > +
> > +	/* Set FIFO to 0 since iio core ignores teardown errors. */
> > +	st->fifo.on = 0;
> > +
> > +	/* set FIFO in bypass mode */
> > +	ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
> > +			   INV_ICM42607_FIFO_CONFIG1_BYPASS);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* flush FIFO data */
> > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > +			   INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* disable FIFO threshold interrupt */
> > +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > +				 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
> 
> 	regmap_clear_bits()
> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	return 0;
> > +}
> > +
> > +static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev)
> > +{
> > +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> > +	struct device *dev = regmap_get_device(st->map);
> > +	unsigned int sensor;
> > +	unsigned int *watermark;
> > +	int ret;
> > +
> > +	if (indio_dev == st->indio_gyro) {
> > +		sensor = INV_ICM42607_SENSOR_GYRO;
> > +		watermark = &st->fifo.watermark.gyro;
> > +	} else if (indio_dev == st->indio_accel) {
> > +		sensor = INV_ICM42607_SENSOR_ACCEL;
> > +		watermark = &st->fifo.watermark.accel;
> > +	} else {
> > +		return -EINVAL;
> > +	}
> > +
> > +	mutex_lock(&st->lock);
> > +
> > +	/*
> > +	 * FIFO enabled at update scan mode for accel or gyro, and
> > +	 * disabled here.
> > +	 */
> > +	ret = inv_icm42607_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
> > +	if (ret)
> > +		goto out_unlock;
> > +
> > +	*watermark = 0;
> 
> Add a comment on why this needs to be set to 0.  Normally that only
> matters at all if the fifo is on, so I guess something unusual here?

I think it's just resetting the watermark to 0 when shutting down,
not 100% sure though.

> 
> 
> > +	ret = inv_icm42607_buffer_update_watermark(st);
> > +	if (ret)
> > +		goto out_unlock;
> > +
> > +out_unlock:
> > +	mutex_unlock(&st->lock);
> > +
> > +	pm_runtime_put_autosuspend(dev);
> > +
> > +	return ret;
> > +}
> 
> > +int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st,
> > +				  unsigned int max)
> > +{
> > +	const void *accel, *gyro, *timestamp;
> > +	size_t i, max_count;
> > +	const s8 *temp;
> > +	ssize_t size;
> > +	int ret;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	/* reset all samples counters */
> > +	st->fifo.count = 0;
> > +	st->fifo.nb.gyro = 0;
> > +	st->fifo.nb.accel = 0;
> > +	st->fifo.nb.total = 0;
> > +
> > +	/* compute maximum FIFO read size */
> > +	if (max == 0)
> > +		max_count = sizeof(st->fifo.data);
> > +	else
> > +		max_count = min((max * inv_icm42607_get_packet_size(st->fifo.en)),
> > +				sizeof(st->fifo.data));
> > +
> > +	/* read FIFO count value */
> > +	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH,
> > +			       st->buffer, sizeof(u8) * 2);
> > +	if (ret)
> > +		return ret;
> > +	st->fifo.count = be16_to_cpup(st->buffer);
> 
> Might be ok to assume this is always a multiple of the scan size, but 
> maybe sanity check it to keep sashiko happy and remove that assumption
> of atomic update.
> 
> > +
> > +	/* check and clamp FIFO count value */
> > +	if (st->fifo.count == 0)
> > +		return 0;
> > +
> > +	st->fifo.count = min(st->fifo.count, max_count);
> > +
> > +	/* read all FIFO data in internal buffer */
> > +	ret = regmap_noinc_read(st->map, INV_ICM42607_REG_FIFO_DATA,
> > +				st->fifo.data, st->fifo.count);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* compute number of samples for each sensor */
> > +	for (i = 0; i < st->fifo.count; i += size) {
> > +		size = inv_icm42607_fifo_decode_packet(&st->fifo.data[i],
> > +				&accel, &gyro, &temp, &timestamp);
> > +		/* Make sure the size is at least 1 valid packet. */
> > +		if (size < INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE)
> > +			break;
> > +		/* Error if we are going to overflow the buffer. */
> > +		if (i + size > st->fifo.count)
> > +			return -EIO;
> > +		if (gyro != NULL && inv_icm42607_fifo_is_data_valid(gyro))
> > +			st->fifo.nb.gyro++;
> > +		if (accel != NULL && inv_icm42607_fifo_is_data_valid(accel))
> > +			st->fifo.nb.accel++;
> > +		st->fifo.nb.total++;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
> > new file mode 100644
> > index 000000000000..b77deb66f8bd
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
> 
> > +
> > +/* FIFO data packet */
> > +struct inv_icm42607_fifo_sensor_data {
> > +	__be16 x;
> > +	__be16 y;
> > +	__be16 z;
> > +};
> 
> Sashiko is probably correct that this should be packed.
> Makes not difference here but it's not aligned in the places it's embedded
> in other structs and the compiler seeing this will assume it is aligned.
> 

So I should pack this instead of doing the "get_unaligned()" call?
Thank you.

> > +
> > +#define INV_ICM42607_FIFO_DATA_INVALID		-32768
> > +
> > +static inline bool
> > +inv_icm42607_fifo_is_data_valid(const struct inv_icm42607_fifo_sensor_data *s)
> > +{
> > +	s16 x, y, z;
> > +
> > +	x = be16_to_cpu(s->x);
> > +	y = be16_to_cpu(s->y);
> > +	z = be16_to_cpu(s->z);
> > +
> > +	if (x == INV_ICM42607_FIFO_DATA_INVALID &&
> > +	    y == INV_ICM42607_FIFO_DATA_INVALID &&
> > +	    z == INV_ICM42607_FIFO_DATA_INVALID)
> > +		return false;
> > +
> > +	return true;
> > +}
> 


From heiko at sntech.de  Mon Jun  1 07:01:50 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 01 Jun 2026 16:01:50 +0200
Subject: [PATCH v2 2/2] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601132529.139172-3-hrushirajg23@gmail.com>
References: <20260601132529.139172-1-hrushirajg23@gmail.com>
 <20260601132529.139172-3-hrushirajg23@gmail.com>
Message-ID: <13821740.F0gNSz5aLb@phil>

Am Montag, 1. Juni 2026, 15:25:29 Mitteleurop?ische Sommerzeit schrieb Hrushiraj Gandhi:
> Add the device tree binding for the Vicharak Axon single-board
> computer based on the Rockchip RK3588 SoC, and add the vicharak
> vendor prefix to the vendor-prefixes list.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>

I do believe those also need to be separate patches.
One to add the vendor-prefix, one for the binding.


Heiko

> ---
>  Documentation/devicetree/bindings/arm/rockchip.yaml    | 5 +++++
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  2 files changed, 7 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
> index 1a9dde18626d..b023d4cc9842 100644
> --- a/Documentation/devicetree/bindings/arm/rockchip.yaml
> +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
> @@ -1306,6 +1306,11 @@ properties:
>            - const: turing,rk1
>            - const: rockchip,rk3588
>  
> +      - description: Vicharak Axon
> +        items:
> +          - const: vicharak,axon
> +          - const: rockchip,rk3588
> +
>        - description: WolfVision PF5 mainboard
>          items:
>            - const: wolfvision,rk3568-pf5
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index 28784d66ae7b..504a691a33b9 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1791,6 +1791,8 @@ patternProperties:
>      description: VIA Technologies, Inc.
>    "^vialab,.*":
>      description: VIA Labs, Inc.
> +  "^vicharak,.*":
> +    description: Vicharak Computers Pvt. Ltd.
>    "^vicor,.*":
>      description: Vicor Corporation
>    "^videostrong,.*":
> 






From hrushirajg23 at gmail.com  Mon Jun  1 07:30:19 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:00:19 +0530
Subject: [PATCH v3 0/3] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601143022.153941-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - SDIO Wi-Fi
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v2:
- Split the dt-bindings patch into two separate patches: one for the vendor prefix and one for the board binding as requested by Heiko.
- Removed invalid `enable-gpios` property from HDMI nodes (ignored by dw-hdmi-qp binding)
- Fixed copy-paste error in `rk806_dvs1_null` pinctrl node (gpio_pwrctrl2 -> gpio_pwrctrl1)

Changes since v1:
- Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
- Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
- Renamed regulator nodes to the standard `regulator-name` pattern
- Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
- Fixed pcie20_avdd0v85 vin-supply mismatch
- Removed obsolete `regulator-compatible` property
- Removed invalid `regulator-init-microvolt` property
- Removed dangling `enable-active-high` properties from fixed regulators
- Cleaned up unneeded i2c3 / es8388 nodes
- Added missing `vpcie3v3-supply` properties to PCIe nodes

Hrushiraj Gandhi (3):
  dt-bindings: vendor-prefixes: add vicharak
  dt-bindings: arm: rockchip: add Vicharak Axon board
  arm64: dts: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |    5 +
 .../devicetree/bindings/vendor-prefixes.yaml  |    2 +
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 1036 +++++++++++++++++
 4 files changed, 1044 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 07:30:20 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:00:20 +0530
Subject: [PATCH v3 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601143022.153941-1-hrushirajg23@gmail.com>
References: <20260601143022.153941-1-hrushirajg23@gmail.com>
Message-ID: <20260601143022.153941-2-hrushirajg23@gmail.com>

Add the vendor prefix for Vicharak Computers Pvt. Ltd.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 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 28784d66ae7b..504a691a33b9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1791,6 +1791,8 @@ patternProperties:
     description: VIA Technologies, Inc.
   "^vialab,.*":
     description: VIA Labs, Inc.
+  "^vicharak,.*":
+    description: Vicharak Computers Pvt. Ltd.
   "^vicor,.*":
     description: Vicor Corporation
   "^videostrong,.*":
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 07:30:21 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:00:21 +0530
Subject: [PATCH v3 2/3] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601143022.153941-1-hrushirajg23@gmail.com>
References: <20260601143022.153941-1-hrushirajg23@gmail.com>
Message-ID: <20260601143022.153941-3-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 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 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 07:30:22 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:00:22 +0530
Subject: [PATCH v3 3/3] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601143022.153941-1-hrushirajg23@gmail.com>
References: <20260601143022.153941-1-hrushirajg23@gmail.com>
Message-ID: <20260601143022.153941-4-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 1036 +++++++++++++++++
 2 files changed, 1037 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..fcb115b02eff 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..9d1e61e1857a
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,1036 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: regulator-sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	sdio_pwrseq: sdio-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		clocks = <&hym8563>;
+		clock-names = "ext_clock";
+		pinctrl-names = "default";
+		pinctrl-0 = <&sdio_reset_wifi>;
+		reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
+		status = "okay";
+	};
+
+	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdio {
+	max-frequency = <150000000>;
+	no-sd;
+	no-mmc;
+	bus-width = <4>;
+	disable-wp;
+	cap-sd-highspeed;
+	cap-sdio-irq;
+	keep-power-in-suspend;
+	mmc-pwrseq = <&sdio_pwrseq>;
+	non-removable;
+	pinctrl-names = "default";
+	pinctrl-0 = <&sdiom0_pins>;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	wireless-wlan {
+		sdio_reset_wifi: sdio-reset-wifi {
+			rockchip,pins =
+				<4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&u2phy1 {
+	status = "okay";
+};
+
+&u2phy1_otg {
+	status = "okay";
+};
+
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From jic23 at kernel.org  Mon Jun  1 07:36:53 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Mon, 1 Jun 2026 15:36:53 +0100
Subject: [PATCH V9 06/11] iio: imu: inv_icm42607: Add Buffer support for
 icm42607
In-Reply-To: <PH0PR19MB997338785108348427BBB2B7D2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
	<20260530031739.109063-7-macroalpha82@gmail.com>
	<20260531133801.481e173c@jic23-huawei>
	<PH0PR19MB997338785108348427BBB2B7D2A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260601153653.698c9c58@jic23-huawei>

On Mon, 1 Jun 2026 08:50:02 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Sun, May 31, 2026 at 01:38:01PM +0100, Jonathan Cameron wrote:
> > On Fri, 29 May 2026 22:17:33 -0500
> > Chris Morgan <macroalpha82 at gmail.com> wrote:
> >   
> > > From: Chris Morgan <macromorgan at hotmail.com>
> > > 
> > > Add all FIFO parsing and reading functions to support
> > > inv_icm42607 hardware.
> > > 
> > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>  
> > A few things inline.
> > 
> > J
> >   
> > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > > new file mode 100644
> > > index 000000000000..e065d60ac119
> > > --- /dev/null
> > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > > @@ -0,0 +1,483 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + * Copyright (C) 2026 InvenSense, Inc.
> > > + */
> > > +
> > > +#include <linux/delay.h>
> > > +#include <linux/iio/buffer.h>
> > > +#include <linux/iio/iio.h>
> > > +#include <linux/minmax.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/unaligned.h>
> > > +
> > > +#include <linux/iio/common/inv_sensors_timestamp.h>
> > > +
> > > +#include "inv_icm42607.h"
> > > +#include "inv_icm42607_buffer.h"
> > > +
> > > +/* FIFO header: 1 byte */
> > > +#define INV_ICM42607_FIFO_HEADER_MSG		BIT(7)
> > > +#define INV_ICM42607_FIFO_HEADER_ACCEL		BIT(6)
> > > +#define INV_ICM42607_FIFO_HEADER_GYRO		BIT(5)
> > > +#define INV_ICM42607_FIFO_HEADER_TMST_FSYNC	GENMASK(3, 2)
> > > +#define INV_ICM42607_FIFO_HEADER_ODR_ACCEL	BIT(1)
> > > +#define INV_ICM42607_FIFO_HEADER_ODR_GYRO	BIT(0)
> > > +
> > > +struct inv_icm42607_fifo_1sensor_packet {
> > > +	u8 header;
> > > +	struct inv_icm42607_fifo_sensor_data data;
> > > +	s8 temp;
> > > +} __packed;
> > > +
> > > +struct inv_icm42607_fifo_2sensors_packet {
> > > +	u8 header;
> > > +	struct inv_icm42607_fifo_sensor_data accel;  
> > Good example of the need for the inner structures to be packed  
> 
> Are you saying I should set the inv_icm42607_fifo_sensor_data to be
> __packed? I think I was told in a previous patch not to do that, but
> I can add it back.

My understanding is that it is necessary. Just add a comment on why
next to the structure.  Otherwise typically the compiler assumes
they are aligned and doesn't work around that.  Alternatively just
use an array of u8 and get_unaligned() to extract the values.
(read on - on I suspect this is the better path forwards)
> 
> >   
> > > +	struct inv_icm42607_fifo_sensor_data gyro;
> > > +	s8 temp;
> > > +	__be16 timestamp;
> > > +} __packed;
> > > +
> > > +ssize_t inv_icm42607_fifo_decode_packet(const void *packet, const void **accel,
> > > +					const void **gyro, const int8_t **temp,
> > > +					const void **timestamp)
> > > +{
> > > +	const struct inv_icm42607_fifo_1sensor_packet *pack1 = get_unaligned(&packet);
> > > +	const struct inv_icm42607_fifo_2sensors_packet *pack2 = get_unaligned(&packet);  
> > 
> > Hmm. Sashiko points out you are messing around with pointers here and it's not those but
> > what the point to that we need to worry about alignment for.
> > You could memcpy that data into local structures.  
> 
> I still suck at pointers, sorry. What exactly would you recommend here?
> memcpy the packet value into an allocated
> inv_icm42607_fifo_1sensor_packet or inv_icm42607_fifo_2sensors_packet?

yes. Copy it. though given the result has unaligned internal elements so it
doesn't really help much.  I'm thinking simpler to just treat it as a byte stream
and access each element directly.


> 
> > 
> >   
> > > +	u8 header = *((const u8 *)packet);
> > > +
> > > +	/* FIFO empty */
> > > +	if (header & INV_ICM42607_FIFO_HEADER_MSG) {
> > > +		*accel = NULL;
> > > +		*gyro = NULL;
> > > +		*temp = NULL;
> > > +		*timestamp = NULL;
> > > +		return 0;
> > > +	}
> > > +
> > > +	/* accel + gyro */
> > > +	if ((header & INV_ICM42607_FIFO_HEADER_ACCEL) &&
> > > +	    (header & INV_ICM42607_FIFO_HEADER_GYRO)) {
> > > +		*accel = &pack2->accel;
> > > +		*gyro = &pack2->gyro;
> > > +		*temp = &pack2->temp;
> > > +		*timestamp = &pack2->timestamp;
> > > +		return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE;
> > > +	}
> > > +
> > > +	/* accel only */
> > > +	if (header & INV_ICM42607_FIFO_HEADER_ACCEL) {
> > > +		*accel = &pack1->data;
> > > +		*gyro = NULL;
> > > +		*temp = &pack1->temp;
> > > +		*timestamp = NULL;
> > > +		return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
> > > +	}
> > > +
> > > +	/* gyro only */
> > > +	if (header & INV_ICM42607_FIFO_HEADER_GYRO) {
> > > +		*accel = NULL;
> > > +		*gyro = &pack1->data;
> > > +		*temp = &pack1->temp;
> > > +		*timestamp = NULL;
> > > +		return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE;
> > > +	}
> > > +
> > > +	/* invalid packet if here */
> > > +	return -EINVAL;
> > > +}  
> >   
> > > +/**
> > > + * inv_icm42607_buffer_update_watermark - update watermark FIFO threshold
> > > + * @st:	driver internal state
> > > + *
> > > + * Returns 0 on success, a negative error code otherwise.
> > > + */
> > > +int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st)
> > > +{
> > > +	const struct device *dev = regmap_get_device(st->map);
> > > +	unsigned int wm_gyro, wm_accel, watermark;
> > > +	u32 latency_gyro, latency_accel, latency;
> > > +	u32 period_gyro, period_accel;
> > > +	size_t packet_size, wm_size;
> > > +	__le16 raw_wm;
> > > +	bool restore;
> > > +	int ret;
> > > +
> > > +	packet_size = inv_icm42607_get_packet_size(st->fifo.en);
> > > +
> > > +	/* compute sensors latency, depending on sensor watermark and odr */
> > > +	wm_gyro = inv_icm42607_wm_truncate(st->fifo.watermark.gyro, packet_size);
> > > +	wm_accel = inv_icm42607_wm_truncate(st->fifo.watermark.accel, packet_size);
> > > +	/* use us for odr to avoid overflow using 32 bits values */
> > > +	period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr) / 1000UL;
> > > +	period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr) / 1000UL;
> > > +	latency_gyro = period_gyro * wm_gyro;
> > > +	latency_accel = period_accel * wm_accel;
> > > +
> > > +	/* 0 value for watermark means that the sensor is turned off */
> > > +	if (wm_gyro == 0 && wm_accel == 0)
> > > +		return 0;
> > > +
> > > +	if (latency_gyro == 0) {
> > > +		watermark = wm_accel;
> > > +		st->fifo.watermark.eff_accel = wm_accel;
> > > +	} else if (latency_accel == 0) {
> > > +		watermark = wm_gyro;
> > > +		st->fifo.watermark.eff_gyro = wm_gyro;
> > > +	} else {
> > > +		/* compute the smallest latency that is a multiple of both */
> > > +		if (latency_gyro <= latency_accel)
> > > +			latency = latency_gyro - (latency_accel % latency_gyro);
> > > +		else
> > > +			latency = latency_accel - (latency_gyro % latency_accel);
> > > +		/* all this works because periods are multiple of each others */
> > > +		watermark = latency / min(period_gyro, period_accel);
> > > +		watermark = max(watermark, 1);
> > > +		/* update effective watermark */
> > > +		st->fifo.watermark.eff_gyro = max(latency / period_gyro, 1);
> > > +		st->fifo.watermark.eff_accel = max(latency / period_accel, 1);
> > > +	}
> > > +
> > > +	/* changing FIFO watermark requires to turn off watermark interrupt */
> > > +	ret = regmap_update_bits_check(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > > +				       INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > > +				       0, &restore);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* compute watermark value in bytes */
> > > +	wm_size = watermark * packet_size;
> > > +	raw_wm = INV_ICM42607_FIFO_WATERMARK_VAL(wm_size);
> > > +	memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
> > > +	ret = regmap_bulk_write(st->map, INV_ICM42607_REG_FIFO_CONFIG2,
> > > +				st->buffer, sizeof(raw_wm));
> > > +	if (ret) {
> > > +		dev_err(dev, "Unable to change watermark value: %d\n", ret);
> > > +		if (restore)
> > > +			regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > > +					   INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > > +					   INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);  
> > 
> > set_bits.
> >   
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* restore watermark interrupt */
> > > +	if (restore) {
> > > +		ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > > +					 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN,
> > > +					 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);  
> > 
> > set_bits
> >   
> > > +		if (ret)
> > > +			return ret;
> > > +	}
> > > +
> > > +	return 0;
> > > +}  
> >   
> > > +
> > > +static int inv_icm42607_buffer_predisable(struct iio_dev *indio_dev)
> > > +{
> > > +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> > > +	int ret;
> > > +
> > > +	guard(mutex)(&st->lock);
> > > +
> > > +	if (st->fifo.on > 1) {
> > > +		st->fifo.on--;
> > > +		return 0;
> > > +	}
> > > +
> > > +	/* Set FIFO to 0 since iio core ignores teardown errors. */
> > > +	st->fifo.on = 0;
> > > +
> > > +	/* set FIFO in bypass mode */
> > > +	ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
> > > +			   INV_ICM42607_FIFO_CONFIG1_BYPASS);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* flush FIFO data */
> > > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > > +			   INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* disable FIFO threshold interrupt */
> > > +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
> > > +				 INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN, 0);  
> > 
> > 	regmap_clear_bits()
> >   
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev)
> > > +{
> > > +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> > > +	struct device *dev = regmap_get_device(st->map);
> > > +	unsigned int sensor;
> > > +	unsigned int *watermark;
> > > +	int ret;
> > > +
> > > +	if (indio_dev == st->indio_gyro) {
> > > +		sensor = INV_ICM42607_SENSOR_GYRO;
> > > +		watermark = &st->fifo.watermark.gyro;
> > > +	} else if (indio_dev == st->indio_accel) {
> > > +		sensor = INV_ICM42607_SENSOR_ACCEL;
> > > +		watermark = &st->fifo.watermark.accel;
> > > +	} else {
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	mutex_lock(&st->lock);
> > > +
> > > +	/*
> > > +	 * FIFO enabled at update scan mode for accel or gyro, and
> > > +	 * disabled here.
> > > +	 */
> > > +	ret = inv_icm42607_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
> > > +	if (ret)
> > > +		goto out_unlock;
> > > +
> > > +	*watermark = 0;  
> > 
> > Add a comment on why this needs to be set to 0.  Normally that only
> > matters at all if the fifo is on, so I guess something unusual here?  
> 
> I think it's just resetting the watermark to 0 when shutting down,
> not 100% sure though.
> 
> > 
> >   
> > > +	ret = inv_icm42607_buffer_update_watermark(st);
> > > +	if (ret)
> > > +		goto out_unlock;
> > > +
> > > +out_unlock:
> > > +	mutex_unlock(&st->lock);
> > > +
> > > +	pm_runtime_put_autosuspend(dev);
> > > +
> > > +	return ret;
> > > +}  
> >   
> > > +int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st,
> > > +				  unsigned int max)
> > > +{
> > > +	const void *accel, *gyro, *timestamp;
> > > +	size_t i, max_count;
> > > +	const s8 *temp;
> > > +	ssize_t size;
> > > +	int ret;
> > > +
> > > +	guard(mutex)(&st->lock);
> > > +
> > > +	/* reset all samples counters */
> > > +	st->fifo.count = 0;
> > > +	st->fifo.nb.gyro = 0;
> > > +	st->fifo.nb.accel = 0;
> > > +	st->fifo.nb.total = 0;
> > > +
> > > +	/* compute maximum FIFO read size */
> > > +	if (max == 0)
> > > +		max_count = sizeof(st->fifo.data);
> > > +	else
> > > +		max_count = min((max * inv_icm42607_get_packet_size(st->fifo.en)),
> > > +				sizeof(st->fifo.data));
> > > +
> > > +	/* read FIFO count value */
> > > +	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH,
> > > +			       st->buffer, sizeof(u8) * 2);
> > > +	if (ret)
> > > +		return ret;
> > > +	st->fifo.count = be16_to_cpup(st->buffer);  
> > 
> > Might be ok to assume this is always a multiple of the scan size, but 
> > maybe sanity check it to keep sashiko happy and remove that assumption
> > of atomic update.
> >   
> > > +
> > > +	/* check and clamp FIFO count value */
> > > +	if (st->fifo.count == 0)
> > > +		return 0;
> > > +
> > > +	st->fifo.count = min(st->fifo.count, max_count);
> > > +
> > > +	/* read all FIFO data in internal buffer */
> > > +	ret = regmap_noinc_read(st->map, INV_ICM42607_REG_FIFO_DATA,
> > > +				st->fifo.data, st->fifo.count);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* compute number of samples for each sensor */
> > > +	for (i = 0; i < st->fifo.count; i += size) {
> > > +		size = inv_icm42607_fifo_decode_packet(&st->fifo.data[i],
> > > +				&accel, &gyro, &temp, &timestamp);
> > > +		/* Make sure the size is at least 1 valid packet. */
> > > +		if (size < INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE)
> > > +			break;
> > > +		/* Error if we are going to overflow the buffer. */
> > > +		if (i + size > st->fifo.count)
> > > +			return -EIO;
> > > +		if (gyro != NULL && inv_icm42607_fifo_is_data_valid(gyro))
> > > +			st->fifo.nb.gyro++;
> > > +		if (accel != NULL && inv_icm42607_fifo_is_data_valid(accel))
> > > +			st->fifo.nb.accel++;
> > > +		st->fifo.nb.total++;
> > > +	}
> > > +
> > > +	return 0;
> > > +}  
> >   
> > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
> > > new file mode 100644
> > > index 000000000000..b77deb66f8bd
> > > --- /dev/null
> > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h  
> >   
> > > +
> > > +/* FIFO data packet */
> > > +struct inv_icm42607_fifo_sensor_data {
> > > +	__be16 x;
> > > +	__be16 y;
> > > +	__be16 z;
> > > +};  
> > 
> > Sashiko is probably correct that this should be packed.
> > Makes not difference here but it's not aligned in the places it's embedded
> > in other structs and the compiler seeing this will assume it is aligned.
> >   
> 
> So I should pack this instead of doing the "get_unaligned()" call?
This whole thing feels like a loosing battle. Just rip the structures out and
use defines for the offsets.

> Thank you.



From macromorgan at hotmail.com  Mon Jun  1 07:37:56 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 1 Jun 2026 09:37:56 -0500
Subject: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to
 icm42607
In-Reply-To: <20260531135823.015c4fd1@jic23-huawei>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
 <20260530031739.109063-11-macroalpha82@gmail.com>
 <20260531135823.015c4fd1@jic23-huawei>
Message-ID: <PH0PR19MB997338A6EE5428FC9B058F2E07A5152@PH0PR19MB997338.namprd19.prod.outlook.com>

On Sun, May 31, 2026 at 01:58:23PM +0100, Jonathan Cameron wrote:
> On Fri, 29 May 2026 22:17:37 -0500
> Chris Morgan <macroalpha82 at gmail.com> wrote:
> 
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Add gyroscope functions to the icm42607 driver.
> > 
> > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> 
> Hi Chris,
> Various things inline.
> 
> Thanks,
> 
> Jonathan
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > index 5b69bf895b35..c45239613344 100644
> > --- a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> 
> >  int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> >  {
> > +	struct inv_icm42607_sensor_state *gyro_st = iio_priv(st->indio_gyro);
> >  	struct inv_icm42607_sensor_state *accel_st = iio_priv(st->indio_accel);
> >  	struct inv_sensors_timestamp *ts;
> >  	int ret;
> > @@ -491,6 +494,16 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> >  	if (st->fifo.nb.total == 0)
> >  		return 0;
> >  
> > +	/* handle gyroscope timestamp and FIFO data parsing */
> > +	if (st->fifo.nb.gyro > 0) {
> > +		ts = &gyro_st->ts;
> > +		inv_sensors_timestamp_interrupt(ts, st->fifo.watermark.eff_gyro,
> > +						st->timestamp.gyro);
> > +		ret = inv_icm42607_gyro_parse_fifo(st->indio_gyro);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> >  	/* handle accelerometer timestamp and FIFO data parsing */
> >  	if (st->fifo.nb.accel > 0) {
> >  		ts = &accel_st->ts;
> > @@ -507,12 +520,14 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> >  int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,
> >  				     unsigned int count)
> >  {
> > +	struct inv_icm42607_sensor_state *gyro_st = iio_priv(st->indio_gyro);
> >  	struct inv_icm42607_sensor_state *accel_st = iio_priv(st->indio_accel);
> >  	struct inv_sensors_timestamp *ts;
> > -	s64 accel_ts;
> > +	s64 gyro_ts, accel_ts;
> >  	int ret;
> >  
> >  	accel_ts = iio_get_time_ns(st->indio_accel);
> > +	gyro_ts = iio_get_time_ns(st->indio_gyro);
> 
> Sashiko calls out correctly that there is a race with devices finishing
> coming up that might be hit here.  Probably need some sort of presence
> check and locking to be sure those are both valid.
> 

While I'm not sure how to fix this exactly, I think (attempting to)
test deadlocks I found a bigger issue... I don't think my interrupt
line is hooked up at all...

Assuming I should be getting interrupts when enabling the buffer
(and also assuming I can do that with sysfs) I'm not getting any calls
to the IRQ routine.

Would you know a better way to test the hardware buffers? Thus far
my tests for data correctness involved either `monitor-sensor -a`
or reading the values directly from sysfs.

Assuming I am in fact working with a device with no interrupt line, I
can just modify this to remove the hardware buffer stuff and the IRQ
stuff and work with an even more simplified driver. Probably going to
miss the 7.2 merge window at this time, but still...

> 
> 
> >  
> >  	ret = inv_icm42607_buffer_fifo_read(st, count);
> >  	if (ret)
> 
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
> > new file mode 100644
> > index 000000000000..8d59156086b1
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
> 
> > +
> > +static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
> > +	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
> > +	{ },
> No comma. Check for any other commas after terminating entries like this one.
> > +};
> 
> 
> > +
> > +int inv_icm42607_gyro_parse_fifo(struct iio_dev *indio_dev)
> > +{
> > +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> > +	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
> > +	struct inv_sensors_timestamp *ts = &gyro_st->ts;
> > +	ssize_t i, size;
> > +	unsigned int no;
> > +	const void *accel, *gyro, *timestamp;
> > +	const s8 *temp;
> > +	unsigned int odr;
> > +	s64 ts_val;
> > +	struct inv_icm42607_gyro_buffer buffer = { };
> > +
> > +	guard(mutex)(&st->lock);
> Sashiko thinks there is a deadlock here as this lock will already
> be held.  Report looks correct to me + same bug in the accelerometer case.
> 
> I'm surprised you didn't see them in testing as deadlocks tend to be obvious!
> 

Yeah... about that... turns out my IRQ wasn't firing correctly so I was never
hitting this path. I suspect the line isn't even hooked up!

> 
> > +
> > +	/* parse all fifo packets */
> > +	for (i = 0, no = 0; i < st->fifo.count; i += size, ++no) {
> > +		size = inv_icm42607_fifo_decode_packet(&st->fifo.data[i],
> > +				&accel, &gyro, &temp, &timestamp, &odr);
> > +		/* quit if error or FIFO is empty */
> > +		if (size <= 0)
> > +			return size;
> > +
> > +		/* If the packet size could cause us to overflow, return. */
> > +		if (i + size > st->fifo.count)
> > +			return -EIO;
> > +
> > +		/* skip packet if no gyro data or data is invalid */
> > +		if (gyro == NULL || !inv_icm42607_fifo_is_data_valid(gyro))
> > +			continue;
> > +
> > +		/* update odr */
> > +		if (odr & INV_ICM42607_SENSOR_GYRO)
> > +			inv_sensors_timestamp_apply_odr(ts, st->fifo.period,
> > +							st->fifo.nb.total, no);
> > +
> > +		memcpy(&buffer.gyro, gyro, sizeof(buffer.gyro));
> > +		/* convert 8 bits FIFO temperature in high resolution format */
> > +		buffer.temp = temp ? (*temp * 64) : 0;
> > +		ts_val = inv_sensors_timestamp_pop(ts);
> > +		iio_push_to_buffers_with_ts(indio_dev, &buffer,
> > +					    sizeof(buffer), ts_val);
> > +	}
> > +
> > +	return 0;
> > +}
> 

Thank you again for all your help.


From hrushirajg23 at gmail.com  Mon Jun  1 08:18:07 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:48:07 +0530
Subject: [PATCH v4 0/3] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601151810.162173-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v3:
- Completely removed `sdio_pwrseq` and `wireless-wlan` pinctrl nodes as Wi-Fi/SDIO was already removed.
- Removed unused `u2phy0`, `u2phy0_otg`, `u2phy1`, `u2phy1_otg` nodes to fix orphaned PHY warnings, since the USB 2.0 host ports utilize `u2phy2` and `u2phy3`.
- (The pcie2x1l0 / sata0 conflict warning by Sashiko AI is a false positive: sata0 is on combphy0 and pcie2x1l0 is on combphy1, matching rk3588-base.dtsi).

Changes since v2:
- Split the dt-bindings patch into two separate patches: one for the vendor prefix and one for the board binding as requested by Heiko.
- Removed invalid `enable-gpios` property from HDMI nodes (ignored by dw-hdmi-qp binding)
- Fixed copy-paste error in `rk806_dvs1_null` pinctrl node (gpio_pwrctrl2 -> gpio_pwrctrl1)

Changes since v1:
- Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
- Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
- Renamed regulator nodes to the standard `regulator-name` pattern
- Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
- Fixed pcie20_avdd0v85 vin-supply mismatch
- Removed obsolete `regulator-compatible` property
- Removed invalid `regulator-init-microvolt` property
- Removed dangling `enable-active-high` properties from fixed regulators
- Cleaned up unneeded i2c3 / es8388 nodes
- Added missing `vpcie3v3-supply` properties to PCIe nodes

Hrushiraj Gandhi (3):
  dt-bindings: vendor-prefixes: add vicharak
  dt-bindings: arm: rockchip: add Vicharak Axon board
  arm64: dts: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |   5 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 979 ++++++++++++++++++
 4 files changed, 987 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 08:18:08 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:48:08 +0530
Subject: [PATCH v4 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601151810.162173-1-hrushirajg23@gmail.com>
References: <20260601151810.162173-1-hrushirajg23@gmail.com>
Message-ID: <20260601151810.162173-2-hrushirajg23@gmail.com>

Add the vendor prefix for Vicharak Computers Pvt. Ltd.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 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 28784d66ae7b..504a691a33b9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1791,6 +1791,8 @@ patternProperties:
     description: VIA Technologies, Inc.
   "^vialab,.*":
     description: VIA Labs, Inc.
+  "^vicharak,.*":
+    description: Vicharak Computers Pvt. Ltd.
   "^vicor,.*":
     description: Vicor Corporation
   "^videostrong,.*":
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 08:18:09 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:48:09 +0530
Subject: [PATCH v4 2/3] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601151810.162173-1-hrushirajg23@gmail.com>
References: <20260601151810.162173-1-hrushirajg23@gmail.com>
Message-ID: <20260601151810.162173-3-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 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 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 08:18:10 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 20:48:10 +0530
Subject: [PATCH v4 3/3] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601151810.162173-1-hrushirajg23@gmail.com>
References: <20260601151810.162173-1-hrushirajg23@gmail.com>
Message-ID: <20260601151810.162173-4-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 979 ++++++++++++++++++
 2 files changed, 980 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..fcb115b02eff 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..bfc50480668e
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,979 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: regulator-sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:06:00 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:36:00 +0530
Subject: [PATCH v5 0/3] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601160603.167706-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v4:
- Re-enabled `combphy2_psu` which is a required PHY for `pcie2x1l1`. (It was incorrectly removed in v4 during the unused PHY cleanup).
- Fixed alphabetical sorting of `rk3588-vicharak-axon.dtb` in the Makefile.

Changes since v3:
- Completely removed `sdio_pwrseq` and `wireless-wlan` pinctrl nodes as Wi-Fi/SDIO was already removed.
- Removed unused `u2phy0`, `u2phy0_otg`, `u2phy1`, `u2phy1_otg` nodes to fix orphaned PHY warnings, since the USB 2.0 host ports utilize `u2phy2` and `u2phy3`.

Changes since v2:
- Split the dt-bindings patch into two separate patches: one for the vendor prefix and one for the board binding as requested by Heiko.
- Removed invalid `enable-gpios` property from HDMI nodes (ignored by dw-hdmi-qp binding)
- Fixed copy-paste error in `rk806_dvs1_null` pinctrl node (gpio_pwrctrl2 -> gpio_pwrctrl1)

Changes since v1:
- Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
- Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
- Renamed regulator nodes to the standard `regulator-name` pattern
- Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
- Fixed pcie20_avdd0v85 vin-supply mismatch
- Removed obsolete `regulator-compatible` property
- Removed invalid `regulator-init-microvolt` property
- Removed dangling `enable-active-high` properties from fixed regulators
- Cleaned up unneeded i2c3 / es8388 nodes
- Added missing `vpcie3v3-supply` properties to PCIe nodes

Hrushiraj Gandhi (3):
  dt-bindings: vendor-prefixes: add vicharak
  dt-bindings: arm: rockchip: add Vicharak Axon board
  arm64: dts: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |   5 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 983 ++++++++++++++++++
 4 files changed, 991 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:06:01 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:36:01 +0530
Subject: [PATCH v5 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601160603.167706-1-hrushirajg23@gmail.com>
References: <20260601160603.167706-1-hrushirajg23@gmail.com>
Message-ID: <20260601160603.167706-2-hrushirajg23@gmail.com>

Add the vendor prefix for Vicharak Computers Pvt. Ltd.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 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 28784d66ae7b..504a691a33b9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1791,6 +1791,8 @@ patternProperties:
     description: VIA Technologies, Inc.
   "^vialab,.*":
     description: VIA Labs, Inc.
+  "^vicharak,.*":
+    description: Vicharak Computers Pvt. Ltd.
   "^vicor,.*":
     description: Vicor Corporation
   "^videostrong,.*":
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:06:02 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:36:02 +0530
Subject: [PATCH v5 2/3] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601160603.167706-1-hrushirajg23@gmail.com>
References: <20260601160603.167706-1-hrushirajg23@gmail.com>
Message-ID: <20260601160603.167706-3-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 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 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:06:03 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:36:03 +0530
Subject: [PATCH v5 3/3] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601160603.167706-1-hrushirajg23@gmail.com>
References: <20260601160603.167706-1-hrushirajg23@gmail.com>
Message-ID: <20260601160603.167706-4-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 983 ++++++++++++++++++
 2 files changed, 984 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..b10c6d80c5cc 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -211,6 +211,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou-video-demo.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-v10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-gameforce-ace.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..f0ba75a750e8
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,983 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: regulator-sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:13:44 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 19:13:44 +0300
Subject: [PATCH v4 1/3] drm/bridge: synopsys: dw-dp: Support unregistering
 the AUX channel
In-Reply-To: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
Message-ID: <20260601-drm-rk-fixes-v4-1-c3f3f123e1da@collabora.com>

The DisplayPort AUX channel gets initialized and registered during
dw_dp_bind(), but it is never unregistered, which may lead to resource
leaks and/or use-after-free.

Add the missing dw_dp_unbind() function to allow the users of the
library to handle the required cleanup, i.e. unregister the AUX adapter.

Fixes: 86eecc3a9c2e ("drm/bridge: synopsys: Add DW DPTX Controller support library")
Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 6 ++++++
 include/drm/bridge/dw_dp.h              | 1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index 21541be094c4..36ee6e027af5 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -2093,6 +2093,12 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL_GPL(dw_dp_bind);
 
+void dw_dp_unbind(struct dw_dp *dp)
+{
+	drm_dp_aux_unregister(&dp->aux);
+}
+EXPORT_SYMBOL_GPL(dw_dp_unbind);
+
 MODULE_AUTHOR("Andy Yan <andyshrk at 163.com>");
 MODULE_DESCRIPTION("DW DP Core Library");
 MODULE_LICENSE("GPL");
diff --git a/include/drm/bridge/dw_dp.h b/include/drm/bridge/dw_dp.h
index 25363541e69d..22105c3e8e4d 100644
--- a/include/drm/bridge/dw_dp.h
+++ b/include/drm/bridge/dw_dp.h
@@ -24,4 +24,5 @@ struct dw_dp_plat_data {
 
 struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 			 const struct dw_dp_plat_data *plat_data);
+void dw_dp_unbind(struct dw_dp *dp);
 #endif /* __DW_DP__ */

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:13:46 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 19:13:46 +0300
Subject: [PATCH v4 3/3] drm/rockchip: dw_dp: Release core resources
In-Reply-To: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
Message-ID: <20260601-drm-rk-fixes-v4-3-c3f3f123e1da@collabora.com>

Core resources such as the DisplayPort AUX channel get initialized and
registered during dw_dp_bind(), but are never unregistered, which may
lead to memory leaks and/or use-after-free:

[  224.661371] BUG: KASAN: slab-use-after-free in device_is_dependent+0xe0/0x2b0
[  224.662015] Read of size 8 at addr ffff00011aee8550 by task modprobe/658
[  224.662612]
[  224.662752] CPU: 7 UID: 0 PID: 658 Comm: modprobe Not tainted 7.0.0-rc2-next-20260305 #14 PREEMPT
[  224.662759] Hardware name: Radxa ROCK 5B (DT)
[  224.662762] Call trace:
[  224.662764]  show_stack+0x20/0x38 (C)
[  224.662772]  dump_stack_lvl+0x6c/0x98
[  224.662777]  print_report+0x160/0x4b8
[  224.662783]  kasan_report+0xb4/0xe0
[  224.662790]  __asan_report_load8_noabort+0x20/0x30
[  224.662796]  device_is_dependent+0xe0/0x2b0
[  224.662802]  device_is_dependent+0x108/0x2b0
[  224.662808]  device_link_add+0x1f8/0x10b0
[  224.662813]  devm_of_phy_get_by_index+0x120/0x200
[  224.662819]  dw_dp_bind+0x34c/0xb10 [dw_dp]
[  224.662830]  dw_dp_rockchip_bind+0x194/0x250 [rockchipdrm]
[  224.662864]  component_bind_all+0x3a8/0x720
[  224.662869]  rockchip_drm_bind+0x120/0x390 [rockchipdrm]
[  224.662899]  try_to_bring_up_aggregate_device+0x76c/0x838
[  224.662904]  component_master_add_with_match+0x1f4/0x230
[  224.662909]  rockchip_drm_platform_probe+0x420/0x538 [rockchipdrm]
[  224.662939]  platform_probe+0xe8/0x168
[  224.662945]  really_probe+0x340/0x828
[  224.662950]  __driver_probe_device+0x2e0/0x350
[  224.662954]  driver_probe_device+0x80/0x140
[  224.662959]  __driver_attach+0x398/0x460
[  224.662964]  bus_for_each_dev+0xe0/0x198
[  224.662968]  driver_attach+0x50/0x68
[  224.662972]  bus_add_driver+0x2a0/0x4c0
[  224.662977]  driver_register+0x294/0x360
[  224.662982]  __platform_driver_register+0x7c/0x98
[  224.662987]  rockchip_drm_init+0xc4/0xff8 [rockchipdrm]

Since a previous commit exported dw_dp_unbind() function in DW DP core
library to take care of the necessary cleanup, use this in the
component's unbind() callback, as well as in its bind() error path.

Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index f137f699737c..0de822360c8d 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -107,15 +107,26 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
 		return PTR_ERR(dp->base);
 
 	connector = drm_bridge_connector_init(drm_dev, encoder);
-	if (IS_ERR(connector))
+	if (IS_ERR(connector)) {
+		dw_dp_unbind(dp->base);
 		return dev_err_probe(dev, PTR_ERR(connector),
 				     "Failed to init bridge connector\n");
+	}
 
 	return 0;
 }
 
+static void dw_dp_rockchip_unbind(struct device *dev, struct device *master,
+				  void *data)
+{
+	struct rockchip_dw_dp *dp = dev_get_drvdata(dev);
+
+	dw_dp_unbind(dp->base);
+}
+
 static const struct component_ops dw_dp_rockchip_component_ops = {
 	.bind = dw_dp_rockchip_bind,
+	.unbind = dw_dp_rockchip_unbind,
 };
 
 static int dw_dp_probe(struct platform_device *pdev)

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:13:43 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 19:13:43 +0300
Subject: [PATCH v4 0/3] Rockchip DRM use-after-free & null-ptr-deref fixes
Message-ID: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>

The first three patches in the series are fixes for use-after-free &
null-ptr-deref related issues found in dw_dp and inno-hdmi Rockchip DRM
drivers.

The following three patches provide a few minor improvements to dw_dp
and dw_hdmi_qp, while the remaining two address use-after-free and
memory allocation in DW DP core library.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v4:
- Collected R-b from Andy
- Fixed a conflict while rebasing onto latest drm-misc-next
- Added new patch: drm/rockchip: dw_dp: Add missing newline in
  dev_err_probe() message
- Link to v3: https://lore.kernel.org/r/20260327-drm-rk-fixes-v3-0-fd2e6900c08c at collabora.com

Changes in v3:
- Dropped patches 1..6,8 already applied by Heiko
- Reworked remaining patch "drm/bridge: synopsys: dw-dp: Unregister AUX
  channel on bridge detach" into:
  * drm/bridge: synopsys: dw-dp: Support unregistering the AUX channel
  * drm/rockchip: dw_dp: Release core resources
- Link to v2: https://lore.kernel.org/r/20260310-drm-rk-fixes-v2-0-645ecfb43f49 at collabora.com

Changes in v2:
- Fixed conflicts while rebasing onto latest drm-misc-next
- Added two more patches:
  * drm/bridge: synopsys: dw-dp: Unregister AUX channel on bridge detach
  * drm/bridge: synopsys: dw-dp: Drop useless memory allocation
- Link to v1: https://lore.kernel.org/r/20260122-drm-rk-fixes-v1-0-3942f185750e at collabora.com

To: Andy Yan <andy.yan at rock-chips.com>
To: Andrzej Hajda <andrzej.hajda at intel.com>
To: Neil Armstrong <neil.armstrong at linaro.org>
To: Robert Foss <rfoss at kernel.org>
To: Laurent Pinchart <Laurent.pinchart at ideasonboard.com>
To: Jonas Karlman <jonas at kwiboo.se>
To: Jernej Skrabec <jernej.skrabec at gmail.com>
To: Luca Ceresoli <luca.ceresoli at bootlin.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>
To: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
To: Sandy Huang <hjc at rock-chips.com>
To: Heiko St?bner <heiko at sntech.de>
To: Dmitry Baryshkov <lumag at kernel.org>
To: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Cc: kernel at collabora.com
Cc: dri-devel at lists.freedesktop.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org

---
Cristian Ciocaltea (3):
      drm/bridge: synopsys: dw-dp: Support unregistering the AUX channel
      drm/rockchip: dw_dp: Add missing newline in dev_err_probe() message
      drm/rockchip: dw_dp: Release core resources

 drivers/gpu/drm/bridge/synopsys/dw-dp.c   |  6 ++++++
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 15 +++++++++++++--
 include/drm/bridge/dw_dp.h                |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)
---
base-commit: e84b07e0a30b371117f9a1120a4645c213f39cd9
change-id: 20260122-drm-rk-fixes-a7622c71553e



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:13:45 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 19:13:45 +0300
Subject: [PATCH v4 2/3] drm/rockchip: dw_dp: Add missing newline in
 dev_err_probe() message
In-Reply-To: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
Message-ID: <20260601-drm-rk-fixes-v4-2-c3f3f123e1da@collabora.com>

Add the missing trailing newline to dev_err_probe() call in
dw_dp_rockchip_bind().

Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
Fixes: 26cb3e26efa7 ("drm/rockchip: dw_dp: Simplify error handling")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 32bc73a1d5e4..f137f699737c 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -109,7 +109,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
 	connector = drm_bridge_connector_init(drm_dev, encoder);
 	if (IS_ERR(connector))
 		return dev_err_probe(dev, PTR_ERR(connector),
-				     "Failed to init bridge connector");
+				     "Failed to init bridge connector\n");
 
 	return 0;
 }

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:20:12 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 1 Jun 2026 19:20:12 +0300
Subject: [PATCH v3 2/2] drm/rockchip: dw_dp: Release core resources
In-Reply-To: <a496ada3-fc3f-4b29-a445-20d5615b67e0@rock-chips.com>
References: <20260327-drm-rk-fixes-v3-0-fd2e6900c08c@collabora.com>
 <20260327-drm-rk-fixes-v3-2-fd2e6900c08c@collabora.com>
 <a496ada3-fc3f-4b29-a445-20d5615b67e0@rock-chips.com>
Message-ID: <0dd8e7dd-d772-4fa7-b92e-124517009b34@collabora.com>

Hi Andy,

On 5/31/26 1:29 PM, Andy Yan wrote:
> Hello,
> 
> On 3/27/26 08:55, Cristian Ciocaltea wrote:
>> Core resources such as the DisplayPort AUX channel get initialized and
>> registered during dw_dp_bind(), but are never unregistered, which may
>> lead to memory leaks and/or use-after-free:
>>
>> [  224.661371] BUG: KASAN: slab-use-after-free in device_is_dependent+0xe0/0x2b0
>> [  224.662015] Read of size 8 at addr ffff00011aee8550 by task modprobe/658
>> [  224.662612]
>> [  224.662752] CPU: 7 UID: 0 PID: 658 Comm: modprobe Not tainted 7.0.0-rc2-next-20260305 #14 PREEMPT
>> [  224.662759] Hardware name: Radxa ROCK 5B (DT)
>> [  224.662762] Call trace:
>> [  224.662764]  show_stack+0x20/0x38 (C)
>> [  224.662772]  dump_stack_lvl+0x6c/0x98
>> [  224.662777]  print_report+0x160/0x4b8
>> [  224.662783]  kasan_report+0xb4/0xe0
>> [  224.662790]  __asan_report_load8_noabort+0x20/0x30
>> [  224.662796]  device_is_dependent+0xe0/0x2b0
>> [  224.662802]  device_is_dependent+0x108/0x2b0
>> [  224.662808]  device_link_add+0x1f8/0x10b0
>> [  224.662813]  devm_of_phy_get_by_index+0x120/0x200
>> [  224.662819]  dw_dp_bind+0x34c/0xb10 [dw_dp]
>> [  224.662830]  dw_dp_rockchip_bind+0x194/0x250 [rockchipdrm]
>> [  224.662864]  component_bind_all+0x3a8/0x720
>> [  224.662869]  rockchip_drm_bind+0x120/0x390 [rockchipdrm]
>> [  224.662899]  try_to_bring_up_aggregate_device+0x76c/0x838
>> [  224.662904]  component_master_add_with_match+0x1f4/0x230
>> [  224.662909]  rockchip_drm_platform_probe+0x420/0x538 [rockchipdrm]
>> [  224.662939]  platform_probe+0xe8/0x168
>> [  224.662945]  really_probe+0x340/0x828
>> [  224.662950]  __driver_probe_device+0x2e0/0x350
>> [  224.662954]  driver_probe_device+0x80/0x140
>> [  224.662959]  __driver_attach+0x398/0x460
>> [  224.662964]  bus_for_each_dev+0xe0/0x198
>> [  224.662968]  driver_attach+0x50/0x68
>> [  224.662972]  bus_add_driver+0x2a0/0x4c0
>> [  224.662977]  driver_register+0x294/0x360
>> [  224.662982]  __platform_driver_register+0x7c/0x98
>> [  224.662987]  rockchip_drm_init+0xc4/0xff8 [rockchipdrm]
>>
>> Since a previous commit exported dw_dp_unbind() function in DW DP core
>> library to take care of the necessary cleanup, use this in the
>> component's unbind() callback, as well as in its bind() error path.
>>
>> Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>> ---
>>   drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 20 +++++++++++++++++---
>>   1 file changed, 17 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>> index 22c0911f1896..8cba90d2dd56 100644
>> --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>> @@ -108,14 +108,28 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
>>         connector = drm_bridge_connector_init(drm_dev, encoder);
>>       if (IS_ERR(connector))
>> -        return dev_err_probe(dev, PTR_ERR(connector),
>> -                     "Failed to init bridge connector");
>> +        ret = dev_err_probe(dev, PTR_ERR(connector),
>> +                    "Failed to init bridge connector");
>> +    else
>> +        ret = drm_connector_attach_encoder(connector, encoder);
>>   -    return drm_connector_attach_encoder(connector, encoder);
> 
> This line has already been removed in the latest code.

Indeed, handled now in v4 [1] by rebasing onto latest drm-misc. 
Also added a new patch to fix a missing "\n".

Thanks for reviewing!

Regards,
Cristian

[1] https://lore.kernel.org/all/20260601-drm-rk-fixes-v4-0-c3f3f123e1da at collabora.com/


From hrushirajg23 at gmail.com  Mon Jun  1 09:21:39 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:51:39 +0530
Subject: [PATCH v6 0/3] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260601162143.170030-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v5:
- Enabled `i2s5_8ch` and `i2s6_8ch` CPU DAIs to resolve probe deferral issues for `hdmi0_sound` and `hdmi1_sound`.

Changes since v4:
- Re-enabled `combphy2_psu` which is a required PHY for `pcie2x1l1`. (It was incorrectly removed in v4 during the unused PHY cleanup).
- Fixed alphabetical sorting of `rk3588-vicharak-axon.dtb` in the Makefile.

Changes since v3:
- Completely removed `sdio_pwrseq` and `wireless-wlan` pinctrl nodes as Wi-Fi/SDIO was already removed.
- Removed unused `u2phy0`, `u2phy0_otg`, `u2phy1`, `u2phy1_otg` nodes to fix orphaned PHY warnings, since the USB 2.0 host ports utilize `u2phy2` and `u2phy3`.

Changes since v2:
- Split the dt-bindings patch into two separate patches: one for the vendor prefix and one for the board binding as requested by Heiko.
- Removed invalid `enable-gpios` property from HDMI nodes (ignored by dw-hdmi-qp binding)
- Fixed copy-paste error in `rk806_dvs1_null` pinctrl node (gpio_pwrctrl2 -> gpio_pwrctrl1)

Changes since v1:
- Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
- Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
- Renamed regulator nodes to the standard `regulator-name` pattern
- Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
- Fixed pcie20_avdd0v85 vin-supply mismatch
- Removed obsolete `regulator-compatible` property
- Removed invalid `regulator-init-microvolt` property
- Removed dangling `enable-active-high` properties from fixed regulators
- Cleaned up unneeded i2c3 / es8388 nodes
- Added missing `vpcie3v3-supply` properties to PCIe nodes

Hrushiraj Gandhi (3):
  dt-bindings: vendor-prefixes: add vicharak
  dt-bindings: arm: rockchip: add Vicharak Axon board
  arm64: dts: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |   5 +
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 991 ++++++++++++++++++
 4 files changed, 999 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:21:40 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:51:40 +0530
Subject: [PATCH v6 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601162143.170030-1-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
Message-ID: <20260601162143.170030-2-hrushirajg23@gmail.com>

Add the vendor prefix for Vicharak Computers Pvt. Ltd.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 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 28784d66ae7b..504a691a33b9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1791,6 +1791,8 @@ patternProperties:
     description: VIA Technologies, Inc.
   "^vialab,.*":
     description: VIA Labs, Inc.
+  "^vicharak,.*":
+    description: Vicharak Computers Pvt. Ltd.
   "^vicor,.*":
     description: Vicor Corporation
   "^videostrong,.*":
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:21:41 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:51:41 +0530
Subject: [PATCH v6 2/3] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260601162143.170030-1-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
Message-ID: <20260601162143.170030-3-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 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 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.47.3



From hrushirajg23 at gmail.com  Mon Jun  1 09:21:42 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  1 Jun 2026 21:51:42 +0530
Subject: [PATCH v6 3/3] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601162143.170030-1-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
Message-ID: <20260601162143.170030-4-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 991 ++++++++++++++++++
 2 files changed, 992 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..b10c6d80c5cc 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -211,6 +211,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou-video-demo.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-v10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-gameforce-ace.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..4d7fafd76c16
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,991 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		mmc2 = &sdio;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		status = "okay";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&vdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	sata_vcc_5v0: regulator-sata-vcc-5v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "sata_vcc_5v0";
+		startup-delay-us = <5000>;
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc0_4v0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <4000000>;
+		regulator-max-microvolt = <4000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+		status = "okay";
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+		status = "okay";
+	};
+};
+
+&i2s5_8ch {
+	status = "okay";
+};
+
+&i2s6_8ch {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From cristian.ciocaltea at collabora.com  Mon Jun  1 09:29:24 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 1 Jun 2026 19:29:24 +0300
Subject: [PATCH v5 05/10] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC
 scrambling and high TMDS clock ratio support
In-Reply-To: <9a7855a7-6b0c-4aa2-8516-13d94beabac6@rock-chips.com>
References: <20260426-dw-hdmi-qp-scramb-v5-0-d778e70c317b@collabora.com>
 <20260426-dw-hdmi-qp-scramb-v5-5-d778e70c317b@collabora.com>
 <9a7855a7-6b0c-4aa2-8516-13d94beabac6@rock-chips.com>
Message-ID: <b0fc7c12-51e3-4bb7-9ed7-fda1a30d4e9d@collabora.com>

Hi Andy,

On 6/1/26 7:06 AM, Andy Yan wrote:
> Hello,
> 
> On 4/26/26 08:20, Cristian Ciocaltea wrote:
>> Enable HDMI 2.0 display modes (e.g. 4K at 60Hz) by adding SCDC management
>> for the high TMDS clock ratio and scrambling, required when the TMDS
>> character rate exceeds the 340 MHz HDMI 1.4b limit.
>>
>> A periodic work item monitors the sink's scrambling status to recover
>> from sink-side resets.  On hotplug detect, if SCDC scrambling state is
>> out of sync with the driver, trigger a CRTC reset to re-establish the
>> link.
>>
>> Reject modes requiring TMDS rates above 600 MHz, as those fall in the
>> HDMI 2.1 FRL domain which is not supported. In no_hpd configurations,
>> further restrict to 340 MHz since SCDC requires a connected sink.
>>
>> Tested-by: Diederik de Haas <diederik at cknow-tech.com>
>> Tested-by: Maud Spierings <maud_spierings at hotmail.com>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>> ---
>>   drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 188 ++++++++++++++++++++++++---
>>   1 file changed, 172 insertions(+), 16 deletions(-)

[...]

>>   }
>>     static const struct drm_edid *
>> @@ -832,12 +986,12 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
>>   {
>>       struct dw_hdmi_qp *hdmi = bridge->driver_private;
>>   -    /*
>> -     * TODO: when hdmi->no_hpd is 1 we must not support modes that
>> -     * require scrambling, including every mode with a clock above
>> -     * HDMI14_MAX_TMDSCLK.
>> -     */
>> -    if (rate > HDMI14_MAX_TMDSCLK) {
> 
> The locally defined HDMI14_MAX_TMDSCLK has been removed, we should now use
> HDMI_1_3_CHAR_RATE_MAX, and I think we should apply the same change to
> HDMI20_MAX_TMDSRATE

Yep, already addressed in my local dev branch.  Please note this revision is
obsolete, there's already v6 available and I'm going to submit v7 a bit later
today.

Thanks,
Cristian


From macroalpha82 at gmail.com  Mon Jun  1 09:29:45 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:45 -0500
Subject: [PATCH V3 0/6] Add Anbernic RG Vita-Pro
Message-ID: <20260601162951.254968-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the Anbernic RG Vita-Pro, based on the Rockchip RK3576 SoC.

Changes Since V1:
 - Updated documentation filename to matche compatible string.
 - Corrected order of allocating IRQ in charger driver and switched
   to using devm managed function to allocate work queue.

Changes Since V2:
 - Corrected issue with naming of panel binding document and added
   fallback compatible string.
 - Switched to devm helpers in panel driver. Note that
   devm_drm_panel_add() is currently only in the drm-next branch.
 - Optimized setting GPIOs for panel driver.

Chris Morgan (6):
  dt-bindings: power: supply: sgm41542: document sgm41542
  power: supply: sgm41542: Add SG Micro sgm41542 charger
  dt-bindings: display: panel: document Anbernic TD4310 panel
  drm/panel: anbernic-td4310: Add RG Vita Pro panel
  dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
  arm64: dts: rockchip: Add Anbernic RG Vita-Pro

 .../devicetree/bindings/arm/rockchip.yaml     |    6 +
 .../display/panel/anbernic,td4310.yaml        |   66 +
 .../power/supply/sgmicro,sgm41542.yaml        |   99 ++
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1317 +++++++++++++++++
 drivers/gpu/drm/panel/Kconfig                 |   10 +
 drivers/gpu/drm/panel/Makefile                |    1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c |  251 ++++
 drivers/power/supply/Kconfig                  |    8 +
 drivers/power/supply/Makefile                 |    1 +
 drivers/power/supply/sgm41542_charger.c       | 1035 +++++++++++++
 11 files changed, 2795 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
 create mode 100644 drivers/power/supply/sgm41542_charger.c

-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:46 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:46 -0500
Subject: [PATCH V3 1/6] dt-bindings: power: supply: sgm41542: document sgm41542
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Document the SG Micro sgm41542 battery charger/boost converter.
The parameters of input-current-limit-microamp and
input-voltage-limit-microvolt are defined as such since they are in
common use among multiple bindings currently.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../power/supply/sgmicro,sgm41542.yaml        | 99 +++++++++++++++++++
 1 file changed, 99 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
new file mode 100644
index 000000000000..8d37f502c1f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SGM41542 Battery Charger
+
+description:
+  The SGMicro SGM41542 is a single cell battery charger/boost controller.
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+  - Xu Shengfei <xsf at rock-chips.com>
+
+properties:
+  compatible:
+    const: sgmicro,sgm41542
+
+  input-current-limit-microamp:
+    description:
+      Optional value to clamp the maximum input current limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (2400000).
+    minimum: 100000
+    maximum: 3800000
+
+  input-voltage-limit-microvolt:
+    description:
+      Optional value to clamp the maximum input voltage limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (4500000).
+    minimum: 3900000
+    maximum: 12000000
+
+  interrupts:
+    maxItems: 1
+
+  monitored-battery:
+    description: |
+        A phandle to a monitored battery node. Values for the following
+        are used by the driver and if not present will result in default
+        values being applied:
+        constant-charge-current-max-microamp
+        constant-charge-voltage-max-microvolt
+        charge-term-current-microamp
+        precharge-current-microamp
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    properties:
+      otg-vbus:
+        type: object
+        description: OTG boost regulator
+        $ref: /schemas/regulator/regulator.yaml
+        unevaluatedProperties: false
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    battery: battery {
+      compatible = "simple-battery";
+      constant-charge-current-max-microamp = <10000000>;
+      constant-charge-voltage-max-microvolt = <4350000>;
+      precharge-current-microamp = <180000>;
+      charge-term-current-microamp = <300000>;
+    };
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      charger at 3b {
+        compatible = "sgmicro,sgm41542";
+        reg = <0x3b>;
+        input-current-limit-microamp = <3000000>;
+        input-voltage-limit-microvolt = <4500000>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        monitored-battery = <&battery>;
+
+        regulators {
+          otg-vbus {
+            regulator-max-microvolt = <5000000>;
+            regulator-min-microvolt = <5000000>;
+          };
+        };
+      };
+    };
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:48 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:48 -0500
Subject: [PATCH V3 3/6] dt-bindings: display: panel: document Anbernic TD4310 panel
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
new file mode 100644
index 000000000000..6f7f92b9c860
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Anbernic TD4310 Based Panels
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+
+description:
+  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
+  (a 1080x1920 5.5 inch panel).
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - anbernic,panel-vita-pro
+      - const: anbernic,td4310
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: Panel power supply
+
+required:
+  - compatible
+  - port
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel at 0 {
+            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+            reg = <0>;
+            backlight = <&backlight>;
+            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+            rotation = <270>;
+            vdd-supply = <&vdd_lcd>;
+
+            port {
+                panel_in: endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:47 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:47 -0500
Subject: [PATCH V3 2/6] power: supply: sgm41542: Add SG Micro sgm41542 charger
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the SG Micro SGM41542 charger/boost converter.
Driver was adapted from Rockchip BSP driver [1] and confirmed
with vendor datasheet [2].

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
[2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/power/supply/Kconfig            |    8 +
 drivers/power/supply/Makefile           |    1 +
 drivers/power/supply/sgm41542_charger.c | 1035 +++++++++++++++++++++++
 3 files changed, 1044 insertions(+)
 create mode 100644 drivers/power/supply/sgm41542_charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 83392ed6a8da..57dae0913472 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -856,6 +856,14 @@ config CHARGER_RK817
 	help
 	  Say Y to include support for Rockchip RK817 Battery Charger.
 
+config CHARGER_SGM41542
+	tristate "SGM41542 charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the SGM41542 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB3XX Battery Charger"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7ee839dca7f3..c376889db317 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
+obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
new file mode 100644
index 000000000000..1bc2eab55406
--- /dev/null
+++ b/drivers/power/supply/sgm41542_charger.c
@@ -0,0 +1,1035 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Chrager driver for Sgm4154x
+ *
+ * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Xu Shengfei <xsf at rock-chips.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/types.h>
+
+#define SGM4154X_MANUFACTURER			"SGMICRO"
+#define SGM4154X_NAME				"sgm41542"
+
+#define SGM4154X_CHRG_CTRL_0			0x00
+#define SGM4154X_HIZ_EN				BIT(7)
+#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
+#define SGM4154X_IINDPM_I_MIN_UA		100000
+#define SGM4154X_IINDPM_I_MAX_UA		3800000
+#define SGM4154X_IINDPM_STEP_UA			100000
+#define SGM4154X_IINDPM_DEF_UA			2400000
+
+#define SGM4154X_CHRG_CTRL_1			0x01
+#define SGM4154X_WDT_RST			BIT(6)
+#define SGM4154X_OTG_EN				BIT(5)
+#define SGM4154X_CHRG_EN			BIT(4)
+
+#define SGM4154X_CHRG_CTRL_2			0x02
+#define SGM4154X_BOOST_LIM			BIT(7)
+#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
+#define SGM4154X_ICHRG_I_STEP_UA		60000
+#define SGM4154X_ICHRG_I_MIN_UA			0
+#define SGM4154X_ICHRG_I_MAX_UA			3780000
+#define SGM4154X_ICHRG_I_DEF_UA			2040000
+
+#define SGM4154X_CHRG_CTRL_3			0x03
+#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
+#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_PRECHRG_I_MIN_UA		60000
+#define SGM4154X_PRECHRG_I_MAX_UA		780000
+#define SGM4154X_PRECHRG_I_DEF_UA		180000
+#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
+#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_TERMCHRG_I_MIN_UA		60000
+#define SGM4154X_TERMCHRG_I_MAX_UA		960000
+#define SGM4154X_TERMCHRG_I_DEF_UA		180000
+
+#define SGM4154X_CHRG_CTRL_4			0x04
+#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
+#define SGM4154X_VREG_V_MAX_UV			4624000
+#define SGM4154X_VREG_V_MIN_UV			3856000
+#define SGM4154X_VREG_V_DEF_UV			4208000
+#define SGM4154X_VREG_V_STEP_UV			32000
+#define SGM4154X_VRECHARGE			BIT(0)
+#define SGM4154X_VRECHRG_STEP_MV		100
+#define SGM4154X_VRECHRG_OFFSET_MV		100
+
+#define SGM4154X_CHRG_CTRL_5			0x05
+#define SGM4154X_TERM_EN			BIT(7)
+#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
+#define SGM4154X_WDT_TIMER_40S			BIT(4)
+#define SGM4154X_WDT_TIMER_80S			BIT(5)
+#define SGM4154X_WDT_TIMER_160S			(BIT(4) | BIT(5))
+#define SGM4154X_WDT_TIMER_DISABLE		0
+
+#define SGM4154X_CHRG_CTRL_6			0x06
+#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
+#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
+#define SGM4154X_OVP_10_5V			BIT(7)
+#define SGM4154X_OVP_6_5V			BIT(6)
+#define SGM4154X_OVP_5_5V			0
+#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
+#define SGM4154X_BOOSTV				GENMASK(5, 4)
+#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
+#define SGM4154X_VINDPM_V_MIN_UV		3900000
+#define SGM4154X_VINDPM_V_MAX_UV		12000000
+#define SGM4154X_VINDPM_STEP_UV			100000
+#define SGM4154X_VINDPM_DEF_UV			4500000
+
+#define SGM4154X_CHRG_CTRL_7			0x07
+
+#define SGM4154X_CHRG_STAT		0x08
+#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
+#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
+#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
+#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
+#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
+#define SGM4154X_USB_CDP		BIT(6)
+#define SGM4154X_USB_SDP		BIT(5)
+#define SGM4154X_NOT_CHRGING		0
+#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
+#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
+#define SGM4154X_FAST_CHRG		BIT(4)
+#define SGM4154X_PRECHRG		BIT(3)
+#define SGM4154X_PG_STAT		BIT(2)
+#define SGM4154X_THERM_STAT		BIT(1)
+#define SGM4154X_VSYS_STAT		BIT(0)
+
+#define SGM4154X_CHRG_FAULT		0x09
+#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
+#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
+#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
+#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
+#define SGM4154X_TEMP_WARM		BIT(1)
+#define SGM4154X_TEMP_NORMAL		BIT(0)
+
+#define SGM4154X_CHRG_CTRL_A		0x0a
+#define SGM4154X_VBUS_GOOD		BIT(7)
+#define SGM4154X_VINDPM_INT_MASK	BIT(1)
+#define SGM4154X_IINDPM_INT_MASK	BIT(0)
+
+#define SGM4154X_CHRG_CTRL_B		0x0b
+#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
+#define SGM4154X_PN_MASK		GENMASK(6, 3)
+
+#define SGM4154X_CHRG_CTRL_C		0x0c
+
+#define SGM4154X_CHRG_CTRL_D		0x0d
+#define SGM4154X_JEITA_EN		BIT(0)
+
+#define SGM4154X_INPUT_DET		0x0e
+#define SGM4154X_DPDM_ONGOING		BIT(7)
+
+#define SGM4154X_CHRG_CTRL_F		0x0f
+#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
+
+#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
+
+struct sgm4154x_init_data {
+	int ilim;	/* input current limit */
+	int vlim;	/* minimum system voltage limit */
+	int iterm;	/* termination current */
+	int iprechg;	/* precharge current */
+	int max_ichg;	/* maximum charge current */
+	int max_vreg;	/* maximum charge voltage */
+};
+
+struct sgm4154x_state {
+	bool vsys_stat;
+	bool therm_stat;
+	bool online;
+	u8 chrg_stat;
+	bool chrg_en;
+	bool vbus_gd;
+	u8 chrg_type;
+	u8 health;
+	u8 chrg_fault;
+	u8 ntc_fault;
+};
+
+struct sgm4154x_device {
+	struct i2c_client *client;
+	struct device *dev;
+	struct power_supply *charger;
+	struct regmap *regmap;
+	char model_name[I2C_NAME_SIZE];
+	struct sgm4154x_init_data init_data;
+	struct sgm4154x_state state;
+	struct regulator_dev *otg_rdev;
+	bool watchdog_enable;
+	struct workqueue_struct *sgm_monitor_wq;
+	struct delayed_work sgm_delay_work;
+};
+
+enum SGM4154X_VINDPM_OS {
+	VINDPM_OS_3900MV,
+	VINDPM_OS_5900MV,
+	VINDPM_OS_7500MV,
+	VINDPM_OS_10500MV,
+};
+
+static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_TERMCHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set term current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
+
+	reg_val = reg_val << 4;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_PRECHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set precharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, SGM4154X_ICHRG_I_MAX_UA);
+	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_2,
+				 SGM4154X_ICHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set icharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge current error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
+
+	return val * SGM4154X_ICHRG_I_STEP_UA;
+}
+
+static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
+{
+	int reg_val;
+	int ret;
+
+	/*
+	 * Note that the value of 0x01111 represents a "special value"
+	 * corresponding to 4352000uV instead of the expected 4336000uV,
+	 * per the datasheet. All other values are as expected.
+	 */
+	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
+	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
+	reg_val = reg_val << 3;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VREG_V_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set charge voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge voltage error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
+
+	/*
+	 * 0x01111 is a special value meaning 4352000uV, all other
+	 * values are as expected based on the offset and step values.
+	 */
+	if (val == 0x0f)
+		return 4352000;
+
+	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
+}
+
+static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
+				       unsigned int vindpm)
+{
+	enum SGM4154X_VINDPM_OS os_val;
+	unsigned int offset;
+	u8 reg_val;
+	int ret;
+
+
+	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
+	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
+		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
+		return -EINVAL;
+	}
+
+	if (vindpm < 5900000) {
+		os_val = VINDPM_OS_3900MV;
+		offset = 3900000;
+	} else if (vindpm >= 5900000 && vindpm < 7500000) {
+		os_val = VINDPM_OS_5900MV;
+		offset = 5900000;
+	} else if (vindpm >= 7500000 && vindpm < 10500000) {
+		os_val = VINDPM_OS_7500MV;
+		offset = 7500000;
+	} else {
+		os_val = VINDPM_OS_10500MV;
+		offset = 10500000;
+	}
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_F,
+				 SGM4154X_VINDPM_OS_MASK,
+				 os_val);
+	if (ret) {
+		dev_err(sgm->dev, "set vin dpm error!\n");
+		return ret;
+	}
+
+	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VINDPM_V_MASK, reg_val);
+	if (ret)
+		dev_err(sgm->dev, "input voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
+{
+	int reg_val;
+	int ret;
+
+	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Per the datasheet, values between 100000uA and 3100000uA work
+	 * as expected with the register defined as having a step of
+	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
+	 * The register value of 0x1f however corresponds to 3800000uA not
+	 * 3200000uA as one would expect.
+	 */
+
+	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
+		iindpm = 3100000;
+	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
+		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
+
+	reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_0,
+				 SGM4154X_IINDPM_I_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set input current limit error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int ilim;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
+	if (ret) {
+		dev_err(sgm->dev, "get input current limit error!\n");
+		return ret;
+	}
+
+	/* Max value is not 3200000uA as expected but is 3800000uA */
+	if (SGM4154X_IINDPM_I_MASK == (ilim & SGM4154X_IINDPM_I_MASK))
+		return SGM4154X_IINDPM_I_MAX_UA;
+
+	ilim = (ilim & SGM4154X_IINDPM_I_MASK) * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
+
+	return ilim;
+}
+
+static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_WDT_RST,
+				 SGM4154X_WDT_RST);
+
+	if (ret)
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, int time)
+{
+	u8 reg_val;
+	int ret;
+
+	if (time == 0)
+		reg_val = SGM4154X_WDT_TIMER_DISABLE;
+	else if (time == 40)
+		reg_val = SGM4154X_WDT_TIMER_40S;
+	else if (time == 80)
+		reg_val = SGM4154X_WDT_TIMER_80S;
+	else
+		reg_val = SGM4154X_WDT_TIMER_160S;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_5,
+				 SGM4154X_WDT_TIMER_MASK,
+				 reg_val);
+
+	if (ret) {
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+		return ret;
+	}
+
+	if (time) {
+		if (!sgm->watchdog_enable)
+			queue_delayed_work(sgm->sgm_monitor_wq,
+					   &sgm->sgm_delay_work,
+					   msecs_to_jiffies(1000 * 5));
+		sgm->watchdog_enable = true;
+	} else {
+		sgm->watchdog_enable = false;
+		sgm4154x_watchdog_timer_reset(sgm);
+	}
+
+	return ret;
+}
+
+static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 SGM4154X_CHRG_EN);
+	if (ret)
+		dev_err(sgm->dev, "enable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 0);
+	if (ret)
+		dev_err(sgm->dev, "disable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VAC_OVP_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set vac ovp error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_recharge_volt(struct sgm4154x_device *sgm, int recharge_volt)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VRECHARGE,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set recharger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_state(struct sgm4154x_device *sgm,
+			      struct sgm4154x_state *state)
+{
+	int reg, ret;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
+		return ret;
+	}
+	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
+	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
+	state->online = !!(reg & SGM4154X_PG_STAT);
+	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
+	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
+		return ret;
+	}
+	state->chrg_fault = reg;
+	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
+	state->health = state->ntc_fault;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
+		return ret;
+	}
+	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
+
+	return ret;
+}
+
+static int sgm4154x_property_is_writeable(struct power_supply *psy,
+					  enum power_supply_property prop)
+{
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int sgm4154x_charger_set_property(struct power_supply *psy,
+					 enum power_supply_property prop,
+					 const union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			ret = sgm4154x_enable_charger(sgm);
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
+		} else {
+			sgm4154x_set_watchdog_timer(sgm, 0);
+			ret = sgm4154x_disable_charger(sgm);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sgm4154x_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm, &state);
+	if (ret) {
+		dev_err(sgm->dev, "get state error!\n");
+		return ret;
+	}
+	sgm->state = state;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		else if (!state.chrg_stat)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		switch (state.chrg_stat) {
+		case SGM4154X_PRECHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_FAST_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		case SGM4154X_TERM_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_NOT_CHRGING:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		}
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = SGM4154X_MANUFACTURER;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SGM4154X_NAME;
+		break;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = state.online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = state.vbus_gd;
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		val->intval = sgm4154x_get_chrg_volt(sgm);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		val->intval = sgm4154x_get_ichrg_curr(sgm);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		val->intval = sgm->init_data.vlim;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		val->intval = sgm4154x_get_input_curr_lim(sgm);
+		if (val->intval < 0)
+			return  -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
+{
+	struct sgm4154x_device *sgm4154x = private;
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm4154x, &state);
+	if (ret) {
+		dev_err(sgm4154x->dev, "get state error!\n");
+		return IRQ_NONE;
+	}
+	sgm4154x->state = state;
+	if (state.vbus_gd) {
+		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
+			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
+			if (ret) {
+				dev_err(sgm4154x->dev, "set input current error!\n");
+				return IRQ_NONE;
+			}
+		}
+	}
+	power_supply_changed(sgm4154x->charger);
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property sgm4154x_power_supply_props[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_PRESENT
+};
+
+static char *sgm4154x_charger_supplied_to[] = {
+	"battery-monitor",
+};
+
+static struct power_supply_desc sgm4154x_power_supply_desc = {
+	.name = "sgm4154x-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = sgm4154x_power_supply_props,
+	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
+	.get_property = sgm4154x_charger_get_property,
+	.set_property = sgm4154x_charger_set_property,
+	.property_is_writeable = sgm4154x_property_is_writeable,
+};
+
+static const struct regmap_config sgm4154x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = SGM4154X_CHRG_CTRL_F,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
+				      struct device *dev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = sgm,
+					       .fwnode = dev->fwnode, };
+
+	psy_cfg.supplied_to = sgm4154x_charger_supplied_to;
+	psy_cfg.num_supplicants = ARRAY_SIZE(sgm4154x_charger_supplied_to);
+	psy_cfg.fwnode = dev->fwnode;
+	sgm->charger = devm_power_supply_register(sgm->dev,
+						  &sgm4154x_power_supply_desc,
+						  &psy_cfg);
+	if (IS_ERR(sgm->charger))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
+{
+	struct power_supply_battery_info *bat_info;
+	int ret;
+	u32 val;
+
+	/*
+	 * If unable to read devicetree info, use default/reset
+	 * values from hardware.
+	 */
+	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
+	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
+	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
+	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
+	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
+	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
+
+	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
+	if (ret)
+		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
+	else {
+		if (bat_info->constant_charge_current_max_ua)
+			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
+		if (bat_info->constant_charge_voltage_max_uv)
+			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
+		if (bat_info->charge_term_current_ua)
+			sgm->init_data.iterm = bat_info->charge_term_current_ua;
+		if (bat_info->precharge_current_ua)
+			sgm->init_data.iprechg = bat_info->precharge_current_ua;
+	}
+
+	power_supply_put_battery_info(sgm->charger, bat_info);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-voltage-limit-microvolt",
+				       &val);
+	if (!ret)
+		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
+					    SGM4154X_VINDPM_V_MAX_UV);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-current-limit-microamp",
+				       &val);
+	if (!ret)
+		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
+					    SGM4154X_IINDPM_I_MAX_UA);
+
+	ret = sgm4154x_set_watchdog_timer(sgm, 0);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_vac_ovp(sgm);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_D,
+			   SGM4154X_JEITA_EN,
+			   0);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_IINDPM_INT_MASK,
+			   SGM4154X_IINDPM_INT_MASK);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_VINDPM_INT_MASK,
+			   SGM4154X_VINDPM_INT_MASK);
+
+	/*
+	 * Recharge voltage set to 200 by BSP driver instead of hardware
+	 * default value of 100.
+	 */
+	ret = sgm4154x_set_recharge_volt(sgm, 200);
+
+	return ret;
+}
+
+static const u32 sgm4154x_chg_otg_cur_ua[] = {
+	1200000, 2000000,
+};
+
+static const struct regulator_ops sgm4154x_vbus_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const struct regulator_desc sgm4154x_otg_rdesc = {
+	.of_match = "otg-vbus",
+	.name = "otg-vbus",
+	.regulators_node = of_match_ptr("regulators"),
+	.ops = &sgm4154x_vbus_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4850000,
+	.uV_step = 150000,
+	.n_voltages = 4,
+	.vsel_reg = SGM4154X_CHRG_CTRL_6,
+	.vsel_mask = SGM4154X_BOOSTV,
+	.enable_reg = SGM4154X_CHRG_CTRL_1,
+	.enable_mask = SGM4154X_OTG_EN,
+	.curr_table = sgm4154x_chg_otg_cur_ua,
+	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
+	.csel_reg = SGM4154X_CHRG_CTRL_2,
+	.csel_mask = SGM4154X_BOOST_LIM,
+};
+
+static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
+{
+	struct regulator_config config = {
+		.dev = sgm->dev,
+		.regmap = sgm->regmap,
+		.driver_data = sgm,
+	};
+
+	sgm->otg_rdev = devm_regulator_register(sgm->dev,
+						&sgm4154x_otg_rdesc,
+						&config);
+
+	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
+}
+
+static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
+	if (ret)
+		return ret;
+
+	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
+		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
+
+	return 0;
+}
+
+static void sgm_charger_work(struct work_struct *work)
+{
+	struct sgm4154x_device *sgm =
+		container_of(work,
+			     struct sgm4154x_device,
+			     sgm_delay_work.work);
+
+	sgm4154x_watchdog_timer_reset(sgm);
+	if (sgm->watchdog_enable)
+		queue_delayed_work(sgm->sgm_monitor_wq,
+				   &sgm->sgm_delay_work,
+				   msecs_to_jiffies(1000 * 5));
+}
+
+static int sgm4154x_probe(struct i2c_client *client)
+{
+	const struct i2c_device_id *id = i2c_client_get_device_id(client);
+	struct device *dev = &client->dev;
+	struct sgm4154x_device *sgm;
+	int ret;
+
+	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
+	if (!sgm)
+		return -ENOMEM;
+
+	sgm->client = client;
+	sgm->dev = dev;
+
+	strscpy(sgm->model_name, id->name, I2C_NAME_SIZE);
+
+	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
+	if (IS_ERR(sgm->regmap))
+		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
+				     "Failed to allocate register map\n");
+
+	i2c_set_clientdata(client, sgm);
+
+	ret = sgm4154x_hw_chipid_detect(sgm);
+	if (ret)
+		dev_err_probe(dev, ret, "Unable to read HW ID\n");
+
+	device_init_wakeup(dev, 1);
+
+	ret = sgm4154x_power_supply_init(sgm, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register power supply\n");
+
+	ret = sgm4154x_hw_init(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						sgm4154x_irq_handler_thread,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						"sgm41542-irq", sgm);
+		if (ret)
+			return ret;
+		enable_irq_wake(client->irq);
+	}
+
+	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "%s",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE, "sgm-monitor-wq");
+	if (!sgm->sgm_monitor_wq)
+		return -EINVAL;
+
+	INIT_DELAYED_WORK(&sgm->sgm_delay_work, sgm_charger_work);
+
+	sgm4154x_vbus_regulator_register(sgm);
+
+	return 0;
+}
+
+static void sgm4154x_charger_shutdown(struct i2c_client *client)
+{
+	struct sgm4154x_device *sgm = i2c_get_clientdata(client);
+
+	sgm4154x_set_prechrg_curr(sgm, SGM4154X_PRECHRG_I_DEF_UA);
+	sgm4154x_disable_charger(sgm);
+}
+
+static const struct i2c_device_id sgm4154x_i2c_ids[] = {
+	{ "sgm41542" },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
+
+static const struct of_device_id sgm4154x_of_match[] = {
+	{ .compatible = "sgmicro,sgm41542", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
+
+static struct i2c_driver sgm4154x_driver = {
+	.driver = {
+		.name = "sgm4154x-charger",
+		.of_match_table = sgm4154x_of_match,
+	},
+	.probe = sgm4154x_probe,
+	.shutdown = sgm4154x_charger_shutdown,
+	.id_table = sgm4154x_i2c_ids,
+};
+
+module_i2c_driver(sgm4154x_driver);
+
+MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
+MODULE_DESCRIPTION("sgm4154x charger driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:49 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:49 -0500
Subject: [PATCH V3 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c | 251 ++++++++++++++++++
 3 files changed, 262 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d592f4f4b939..61dd00297ecc 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
 	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
 	  and RG-99 handheld gaming consoles.
 
+config DRM_PANEL_ANBERNIC_TD4310
+	tristate "Anbernic TD4310 LCD panel"
+	depends on GPIOLIB && OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here to enable support for Anbernic designed panels with the
+	  TD4310 panel controller such as the ones used on the Anbernic RG
+	  Vita Pro.
+
 config DRM_PANEL_ARM_VERSATILE
 	tristate "ARM Versatile panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a4291dc3905b..9d8f70c9de3e 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
 obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
new file mode 100644
index 000000000000..d277682f63a3
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Anbernic panels with TD4310 panel controller.
+ *
+ * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/mipi_display.h>
+
+struct anbernic_panel_td4310_info {
+	const struct drm_display_mode *display_mode;
+	u16 width_mm;
+	u16 height_mm;
+	u32 bus_flags;
+	unsigned long mode_flags;
+	u32 format;
+	u32 lanes;
+	u16 prepare_delay;
+	u16 reset_delay;
+	u16 init_delay;
+	u16 enable_delay;
+	u16 disable_delay;
+	u16 unprepare_delay;
+};
+
+struct anbernic_panel_td4310 {
+	struct device *dev;
+	struct mipi_dsi_device *dsi;
+	struct drm_panel panel;
+	const struct anbernic_panel_td4310_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	struct regulator *vdd;
+	enum drm_panel_orientation orientation;
+};
+
+static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
+{
+	return container_of(panel, struct anbernic_panel_td4310, panel);
+}
+
+static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+	int ret;
+
+	ret = regulator_enable(ctx->vdd);
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+	if (ret)
+		goto err_enable;
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	mipi_dsi_msleep(&dsi_ctx, 10);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	if (ret)
+		goto err_reset;
+	if (ctx->panel_info->reset_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	if (ret)
+		goto err_reset;
+
+	if (ctx->panel_info->enable_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 100);
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 100);
+
+	return dsi_ctx.accum_err;
+
+err_reset:
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+err_enable:
+	regulator_disable(ctx->vdd);
+	return ret;
+}
+
+static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 120);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, 120);
+
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	regulator_disable(ctx->vdd);
+
+	return 0;
+}
+
+static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
+				    struct drm_connector *connector)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
+
+	connector->display_info.bpc = 8;
+	connector->display_info.width_mm = panel_info->width_mm;
+	connector->display_info.height_mm = panel_info->height_mm;
+	connector->display_info.bus_flags = panel_info->bus_flags;
+
+	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
+}
+
+static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+
+	return ctx->orientation;
+}
+
+static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
+	.prepare = panel_anbernic_td4310_prepare,
+	.unprepare = panel_anbernic_td4310_unprepare,
+	.get_modes = panel_anbernic_td4310_get_mode,
+	.get_orientation = panel_anbernic_td4310_get_orientation,
+};
+
+static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct anbernic_panel_td4310 *ctx;
+	int ret;
+
+	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
+				   &panel_anbernic_td4310_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ctx->dev = dev;
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	if (!ctx->panel_info)
+		return -EINVAL;
+
+	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Cannot get reset gpio\n");
+
+	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+	if (IS_ERR(ctx->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+				     "Cannot get enable gpio\n");
+
+	ctx->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(ctx->vdd))
+		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
+				     "Failed to request vdd regulator\n");
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	dsi->lanes = ctx->panel_info->lanes;
+	dsi->format = ctx->panel_info->format;
+	dsi->mode_flags = ctx->panel_info->mode_flags;
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	devm_drm_panel_add(dev, &ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+
+	return 0;
+}
+
+static const struct drm_display_mode anbernic_vitapro_mode = {
+	.clock = 140020,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 50,
+	.hsync_end = 1080 + 50 + 4,
+	.htotal = 1080 + 50 + 4 + 50,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 15,
+	.vsync_end = 1920 + 15 + 4,
+	.vtotal = 1920 + 15 + 4 + 32,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
+	.display_mode = &anbernic_vitapro_mode,
+	.width_mm = 69,
+	.height_mm = 121,
+	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
+		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+	.prepare_delay = 50,
+	.reset_delay = 220,
+	.enable_delay = 120,
+	.disable_delay = 50,
+	.unprepare_delay = 20,
+};
+
+static const struct of_device_id panel_anbernic_td4310_of_match[] = {
+	{
+		.compatible = "anbernic,panel-vita-pro",
+		.data = &anbernic_vitapro_info,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
+
+static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
+	.driver = {
+		.name = "panel-anbernic-td4310",
+		.of_match_table = panel_anbernic_td4310_of_match,
+	},
+	.probe	= panel_anbernic_td4310_probe,
+};
+module_mipi_dsi_driver(anbernic_panel_td4310_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:50 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:50 -0500
Subject: [PATCH V3 5/6] dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add compatible string for the Anbernic RG Vita-Pro.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b8babe9d3a26 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -66,6 +66,12 @@ properties:
               - anbernic,rg-ds
           - const: rockchip,rk3568
 
+      - description: Anbernic RK3576 Handheld Gaming Console
+        items:
+          - enum:
+              - anbernic,rg-vita-pro
+          - const: rockchip,rk3576
+
       - description: Ariaboard Photonicat
         items:
           - const: ariaboard,photonicat
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  1 09:29:51 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  1 Jun 2026 11:29:51 -0500
Subject: [PATCH V3 6/6] arm64: dts: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260601162951.254968-1-macroalpha82@gmail.com>
References: <20260601162951.254968-1-macroalpha82@gmail.com>
Message-ID: <20260601162951.254968-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add device tree for the Anbernic RG Vita-Pro, based on the Rockchip
RK3576. All hardware is currently working except for the accelerometer,
the touchscreen, the battery monitor, and DisplayPort over USB-C. PWM
is also missing currently, and as a result the LEDs and panel backlight
are currently controlled via GPIO but will be changed to PWM once
supported.

The Anbernic RG Vita-Pro includes the following hardware:
 - A 1080x1920 DSI display with touch.
 - 21 buttons.
 - 2 Analog joysticks controlled via userspace.
 - 3 LEDs.
 - 64GB eMMC, 2 SDMMC slots.
 - RTL8852BE WiFi/Bluetooth combo
 - 1 USB 3.0 USB-C port in OTG mode.
 - 3.5mm headphone jack with play button support.
 - 5000mAH battery

The following hardware has incomplete driver support and is not yet
working:
 - An Invensense icm42607p accelerometer.
 - A Cellwise cw221x battery monitor.
 - A Synaptics i2c touchscreen.
 - DisplayPort over USB-C alt-mode.
 - PWM controller.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1317 +++++++++++++++++
 2 files changed, 1318 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..7d86676f98e8 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-100ask-dshanpi-a1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-anbernic-rg-vita-pro.dtb
 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
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
new file mode 100644
index 000000000000..7f703b5c8a29
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
@@ -0,0 +1,1317 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2026 Chris Morgan <macromorgan at hotmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+
+#include "rk3576.dtsi"
+
+/ {
+	model = "Anbernic RG Vita Pro";
+	chassis-type = "handset";
+	compatible = "anbernic,rg-vita-pro", "rockchip,rk3576";
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	adc_keys_home: adc-keys-home {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 1>;
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <60>;
+
+		button-home {
+			label = "HOME";
+			linux,code = <KEY_HOME>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	adc_keys_play: adc-keys-play {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 3>;
+		keyup-threshold-microvolt = <1300000>;
+		poll-interval = <60>;
+
+		button-play {
+			label = "PLAY";
+			linux,code = <KEY_PLAYPAUSE>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	/*
+	 * Values from BSP, except for internal resistance which was set
+	 * to 80 micro ohms which is more likely 80000 micro ohms.
+	 */
+	battery: battery {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <8000000>;
+		charge-term-current-microamp = <300000>;
+		constant-charge-current-max-microamp = <10000000>;
+		constant-charge-voltage-max-microvolt = <4350000>;
+		factory-internal-resistance-micro-ohms = <80000>;
+		precharge-current-microamp = <180000>;
+		precharge-upper-limit-microvolt = <3600000>;
+		voltage-max-design-microvolt = <4350000>;
+		voltage-min-design-microvolt = <3000000>;
+	};
+
+	hp_amp: audio-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&hp_amp_enable_h>;
+		pinctrl-names = "default";
+		sound-name-prefix = "Headphone Amp";
+	};
+
+	/*
+	 * LEDs and Backlights can be controlled as a PWM, but PWM
+	 * driver is not yet available.
+	 */
+	gpio_backlight: backlight {
+		compatible = "gpio-backlight";
+		gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&led_backlight_h>;
+		pinctrl-names = "default";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_amber_h>, <&led_green_h>, <&led_red_h>;
+		pinctrl-names = "default";
+
+		charging-led {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_CHARGING;
+			gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
+		};
+
+		full-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
+		};
+
+		bat-low-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_ALARM;
+			gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio_keys_control: gpio-keys-control {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&gamepad_keys_l>;
+		pinctrl-names = "default";
+
+		button-a {
+			gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
+			label = "EAST";
+			linux,code = <BTN_EAST>;
+		};
+
+		button-b {
+			gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+			label = "SOUTH";
+			linux,code = <BTN_SOUTH>;
+		};
+
+		button-down {
+			gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+			label = "DPAD-DOWN";
+			linux,code = <BTN_DPAD_DOWN>;
+		};
+
+		button-l1 {
+			gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>;
+			label = "TL";
+			linux,code = <BTN_TL>;
+		};
+
+		button-l2 {
+			gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+			label = "TL2";
+			linux,code = <BTN_TL2>;
+		};
+
+		button-left {
+			gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+			label = "DPAD-LEFT";
+			linux,code = <BTN_DPAD_LEFT>;
+		};
+
+		button-menu {
+			gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+			label = "MENU";
+			linux,code = <BTN_MODE>;
+		};
+
+		button-right {
+			gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+			label = "DPAD-RIGHT";
+			linux,code = <BTN_DPAD_RIGHT>;
+		};
+
+		button-r1 {
+			gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+			label = "T2";
+			linux,code = <BTN_TR>;
+		};
+
+		button-r2 {
+			gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+			label = "TR2";
+			linux,code = <BTN_TR2>;
+		};
+
+		button-select {
+			gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>;
+			label = "SELECT";
+			linux,code = <BTN_SELECT>;
+		};
+
+		button-start {
+			gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>;
+			label = "START";
+			linux,code = <BTN_START>;
+		};
+
+		button-thumbl {
+			gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+			label = "THUMBL";
+			linux,code = <BTN_THUMBL>;
+		};
+
+		button-thumbr {
+			gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>;
+			label = "THUMBR";
+			linux,code = <BTN_THUMBR>;
+		};
+
+		button-up {
+			gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+			label = "DPAD-UP";
+			linux,code = <BTN_DPAD_UP>;
+		};
+
+		button-x {
+			gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+			label = "NORTH";
+			linux,code = <BTN_NORTH>;
+		};
+
+		button-y {
+			gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+			label = "WEST";
+			linux,code = <BTN_WEST>;
+		};
+	};
+
+	gpio_keys_volume: gpio-keys-volume {
+		compatible = "gpio-keys";
+		autorepeat;
+		pinctrl-0 = <&vol_keys_l>;
+		pinctrl-names = "default";
+
+		vol-down-key {
+			gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEDOWN";
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+
+		vol-up-key {
+			gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEUP";
+			linux,code = <KEY_VOLUMEUP>;
+		};
+	};
+
+	hdmi-con {
+		compatible = "hdmi-connector";
+		type = "c";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_h>;
+		radio-type = "wlan";
+		shutdown-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+
+	sound: sound {
+		compatible = "simple-audio-card";
+		pinctrl-0 = <&hp_det>;
+		pinctrl-names = "default";
+		simple-audio-card,aux-devs = <&aw87391_pa_l>, <&aw87391_pa_r>,
+					     <&hp_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "rockchip,es8388-codec";
+		simple-audio-card,pin-switches = "Headphones", "Internal Speakers";
+		simple-audio-card,routing =
+			"LINPUT1", "Mic Jack",
+			"LINPUT2", "Mic Jack",
+			"RINPUT1", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone",
+			"Headphones", "Headphone Amp OUTL",
+			"Headphones", "Headphone Amp OUTR",
+			"Headphone Amp INL", "LOUT1",
+			"Headphone Amp INR", "ROUT1",
+			"Internal Speakers", "Left Amp OUT",
+			"Internal Speakers", "Right Amp OUT",
+			"Left Amp IN", "LOUT2",
+			"Right Amp IN", "ROUT2";
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Internal Speakers";
+		status = "okay";
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1100000>;
+		regulator-min-microvolt = <1100000>;
+		regulator-name = "vcc_1v1_nldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <2000000>;
+		regulator-min-microvolt = <2000000>;
+		regulator-name = "vcc_2v0_pldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_3v8_sys: regulator-vcc-3v8-sys {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <3800000>;
+		regulator-min-microvolt = <3800000>;
+		regulator-name = "vcc_3v8_sys";
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_3v3_sd_s0_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc_sdio: regulator-vcc-sdio {
+		compatible = "regulator-gpio";
+		regulator-name = "vcc_sdio";
+		gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_sdio_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <1800000>;
+		states = <1800000 0>, <3300000 1>;
+	};
+
+	vcc_wifi: regulator-vcc-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_wifi";
+		enable-active-high;
+		gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_wifi_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vdd_lcd: regulator-vdd-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_lcd";
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vdd_lcd_h>;
+		pinctrl-names = "default";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&dsi {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	panel: panel at 0 {
+		compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+		reg = <0>;
+		backlight = <&gpio_backlight>;
+		enable-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable>, <&lcd_rst>;
+		reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
+		rotation = <270>;
+		vdd-supply = <&vdd_lcd>;
+
+		port {
+			mipi_in_panel: endpoint {
+				remote-endpoint = <&mipi_out_panel>;
+			};
+		};
+	};
+};
+
+&dsi_in {
+	dsi_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dsi>;
+	};
+};
+
+&dsi_out {
+	mipi_out_panel: endpoint {
+		remote-endpoint = <&mipi_in_panel>;
+	};
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&hdmi_sound {
+	status = "okay";
+};
+
+&hdptxphy {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m1_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	/* synaptics,dsx-i2c touchscreen at 0x70 */
+};
+
+&i2c1 {
+	status = "okay";
+
+	pmic at 23 {
+		compatible = "rockchip,rk806";
+		reg = <0x23>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins
+			     &rk806_dvs1_null
+			     &rk806_dvs2_null
+			     &rk806_dvs3_null>;
+		system-power-controller;
+		vcc1-supply = <&vcc_3v8_sys>;
+		vcc2-supply = <&vcc_3v8_sys>;
+		vcc3-supply = <&vcc_3v8_sys>;
+		vcc4-supply = <&vcc_3v8_sys>;
+		vcc5-supply = <&vcc_3v8_sys>;
+		vcc6-supply = <&vcc_3v8_sys>;
+		vcc7-supply = <&vcc_3v8_sys>;
+		vcc8-supply = <&vcc_3v8_sys>;
+		vcc9-supply = <&vcc_3v8_sys>;
+		vcc10-supply = <&vcc_3v8_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc_3v8_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc_3v8_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_pwrdn: dvs1-pwrdn-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: dvs1-rst-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs1_slp: dvs1-slp-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_dvs: dvs2-dvs-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: dvs2-gpio-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_pwrdn: dvs2-pwrdn-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: dvs2-rst-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_slp: dvs2-slp-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_dvs: dvs3-dvs-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: dvs3-gpio-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_pwrdn: dvs3-pwrdn-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: dvs3-rst-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_slp: dvs3-slp-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		regulators {
+			vdd_cpu_big_s0: dcdc-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_big_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_npu_s0: dcdc-reg2 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_npu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vdd_gpu_s0: dcdc-reg5 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_logic_s0: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <800000>;
+				regulator-name = "vdd_logic_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdd_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo2_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdda_1v2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcca_3v3_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo6_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdda_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_ddr_pll_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v75_hdmi_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda0v75_hdmi_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_0v85_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda_0v75_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	/* inv,icm42607 IMU at 0x68 */
+};
+
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		assigned-clock-rates = <12288000>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		DVDD-supply = <&vcc_3v3_s3>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		pinctrl-0 = <&sai1m0_mclk>;
+		pinctrl-names = "default";
+		PVDD-supply = <&vcc_3v3_s3>;
+		#sound-dai-cells = <0>;
+	};
+
+	aw87391_pa_l: audio-codec at 58 {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x58>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Left Amp";
+	};
+
+	aw87391_pa_r: audio-codec at 5b {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x5b>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Right Amp";
+	};
+};
+
+&i2c6 {
+	pinctrl-0 = <&i2c6m3_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	sgm41542: charger at 3b {
+		compatible = "sgmicro,sgm41542";
+		reg = <0x3b>;
+		input-current-limit-microamp = <3000000>;
+		input-voltage-limit-microvolt = <4500000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-0 = <&charger_irq>;
+		pinctrl-names = "default";
+		monitored-battery = <&battery>;
+		status = "okay";
+
+		regulators {
+			vbus5v0_typec: otg-vbus {
+				regulator-name = "vbus5v0_typec";
+				regulator-max-microvolt = <5000000>;
+				regulator-min-microvolt = <5000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+
+	/* Unused iSmartWare SW2001 encryption device at 0x3c */
+
+	husb311: typec-portc at 4e {
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD1 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&usbc_int>;
+		pinctrl-names = "default";
+		status = "okay";
+		vbus-supply = <&vbus5v0_typec>;
+
+		connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			op-sink-microwatt = <10000000>;
+			power-role = "dual";
+			try-power-role  = "sink";
+
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_FIXED(9000, 2000, PDO_FIXED_USB_COMM)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs_ep: endpoint {
+						remote-endpoint = <&usb_drd0_hs_ep>;
+					};
+				};
+				port at 1 {
+					reg = <1>;
+					usbc0_ss_ep: endpoint {
+						remote-endpoint = <&usb_drd0_ss_ep>;
+					};
+				};
+				port at 2 {
+					reg = <2>;
+					usbc0_dp_ep: endpoint {
+						remote-endpoint = <&usbdp_phy_ep>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hym8563_int>;
+		wakeup-source;
+	};
+
+	/* cellwise,cw221X battery manager at 0x64 */
+};
+
+&mipidcphy {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_perstn>;
+	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_wifi>;
+	status = "okay";
+};
+
+&pinctrl {
+	audio {
+		hp_amp_enable_h: hp-amp-enable {
+			rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_det: hp-det {
+			rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	bluetooth {
+		bt_reset_gpio: bt-reset-pin {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_gpio: bt-wake-pin {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_host_irq: bt-wake-host-irq {
+			rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	charger {
+		charger_irq: charger-irq {
+			rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	display {
+		lcd_enable: lcd-enable {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		lcd_rst: lcd-rst {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	gpio-keys {
+		vol_keys_l: vol-keys_l {
+			rockchip,pins =
+				<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		gamepad_keys_l: gamepad-keys-l {
+			rockchip,pins =
+				<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	gpio-leds {
+		led_amber_h: led-amber-h {
+			rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_backlight_h: led-backlight-h {
+			rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_green_h: led-green-h {
+			rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_red_h: led-red-h {
+			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie0_perstn: pcie0-perstn {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	regulator {
+		vcc_3v3_sd_s0_h: vcc-3v3-sd-s0-h {
+			rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_sdio_h: vcc-sdio-h {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_wifi_h: vcc-wifi-h {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vdd_lcd_h: vdd-lcd-h {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtc {
+		hym8563_int: hym8563-int {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	touch {
+		touch_int: touch-int {
+			rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		usbc_int: usbc-int {
+			rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		usbc0_sbu1: usbc0-sbu1 {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		usbc0_sbu2: usbc0-sbu2 {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	wifi {
+		wifi_en_h: wifi-en-h {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sai1 {
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai6 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
+&sdio {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&sdmmc1m0_bus4>, <&sdmmc1m0_clk>,
+		    <&sdmmc1m0_cmd>, <&sdmmc1m0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vcc_sdio>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	no-sd;
+	no-sdio;
+	non-removable;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>,
+		    <&sdmmc0_cmd>, <&sdmmc0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi1 {
+	num-cs = <1>;
+	pinctrl-0 = <&spi1m2_pins>, <&spi1m2_csn0>;
+	status = "okay";
+
+	/* SPI controlled MCU for joystick and joystick LEDs. */
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_dsi: endpoint at ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi_in_vp1>;
+	};
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m1_xfer>, <&uart6m1_ctsn>, <&uart6m1_rtsn>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "realtek,rtl8822cs-bt";
+		device-wake-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		host-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&bt_reset_gpio>, <&bt_wake_gpio>, <&bt_wake_host_irq>;
+		pinctrl-names = "default";
+	};
+};
+
+&usbdp_phy {
+	mode-switch;
+	orientation-switch;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbc0_sbu1 &usbc0_sbu2>;
+	sbu1-dc-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		usbdp_phy_ep: endpoint {
+			remote-endpoint = <&usbc0_dp_ep>;
+		};
+	};
+};
+
+&usb_drd0_dwc3 {
+	usb-role-switch;
+	dr_mode = "otg";
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_drd0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_drd0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss_ep>;
+			};
+		};
+	};
+};
-- 
2.43.0



From jic23 at kernel.org  Mon Jun  1 09:39:59 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Mon, 1 Jun 2026 17:39:59 +0100
Subject: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to
 icm42607
In-Reply-To: <PH0PR19MB997338A6EE5428FC9B058F2E07A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260530031739.109063-1-macroalpha82@gmail.com>
	<20260530031739.109063-11-macroalpha82@gmail.com>
	<20260531135823.015c4fd1@jic23-huawei>
	<PH0PR19MB997338A6EE5428FC9B058F2E07A5152@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260601173959.24082b01@jic23-huawei>

On Mon, 1 Jun 2026 09:37:56 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Sun, May 31, 2026 at 01:58:23PM +0100, Jonathan Cameron wrote:
> > On Fri, 29 May 2026 22:17:37 -0500
> > Chris Morgan <macroalpha82 at gmail.com> wrote:
> >   
> > > From: Chris Morgan <macromorgan at hotmail.com>
> > > 
> > > Add gyroscope functions to the icm42607 driver.
> > > 
> > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>  
> > 
> > Hi Chris,
> > Various things inline.
> > 
> > Thanks,
> > 
> > Jonathan
> >   
> > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > > index 5b69bf895b35..c45239613344 100644
> > > --- a/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
> > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c  
> >   
> > >  int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> > >  {
> > > +	struct inv_icm42607_sensor_state *gyro_st = iio_priv(st->indio_gyro);
> > >  	struct inv_icm42607_sensor_state *accel_st = iio_priv(st->indio_accel);
> > >  	struct inv_sensors_timestamp *ts;
> > >  	int ret;
> > > @@ -491,6 +494,16 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> > >  	if (st->fifo.nb.total == 0)
> > >  		return 0;
> > >  
> > > +	/* handle gyroscope timestamp and FIFO data parsing */
> > > +	if (st->fifo.nb.gyro > 0) {
> > > +		ts = &gyro_st->ts;
> > > +		inv_sensors_timestamp_interrupt(ts, st->fifo.watermark.eff_gyro,
> > > +						st->timestamp.gyro);
> > > +		ret = inv_icm42607_gyro_parse_fifo(st->indio_gyro);
> > > +		if (ret)
> > > +			return ret;
> > > +	}
> > > +
> > >  	/* handle accelerometer timestamp and FIFO data parsing */
> > >  	if (st->fifo.nb.accel > 0) {
> > >  		ts = &accel_st->ts;
> > > @@ -507,12 +520,14 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)
> > >  int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,
> > >  				     unsigned int count)
> > >  {
> > > +	struct inv_icm42607_sensor_state *gyro_st = iio_priv(st->indio_gyro);
> > >  	struct inv_icm42607_sensor_state *accel_st = iio_priv(st->indio_accel);
> > >  	struct inv_sensors_timestamp *ts;
> > > -	s64 accel_ts;
> > > +	s64 gyro_ts, accel_ts;
> > >  	int ret;
> > >  
> > >  	accel_ts = iio_get_time_ns(st->indio_accel);
> > > +	gyro_ts = iio_get_time_ns(st->indio_gyro);  
> > 
> > Sashiko calls out correctly that there is a race with devices finishing
> > coming up that might be hit here.  Probably need some sort of presence
> > check and locking to be sure those are both valid.
> >   
> 
> While I'm not sure how to fix this exactly, I think (attempting to)
> test deadlocks I found a bigger issue... I don't think my interrupt
> line is hooked up at all...
ouch.  Wouldn't be the first time a given device has saved on pins
to the extent of not wiring any interrupts.

> 
> Assuming I should be getting interrupts when enabling the buffer
> (and also assuming I can do that with sysfs) I'm not getting any calls
> to the IRQ routine.
> 
> Would you know a better way to test the hardware buffers? Thus far
> my tests for data correctness involved either `monitor-sensor -a`
> or reading the values directly from sysfs.

There is a basic buffer example in the kernel tree under tools/iio
that should work for this. iio_generic_buffer 

> 
> Assuming I am in fact working with a device with no interrupt line, I
> can just modify this to remove the hardware buffer stuff and the IRQ
> stuff and work with an even more simplified driver. Probably going to
> miss the 7.2 merge window at this time, but still...

Indeed an option to do this as a temporary step. If we get
other users hopefully someone has the interrupt line wired!

Jonathan


From cristian.ciocaltea at collabora.com  Mon Jun  1 09:48:16 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 1 Jun 2026 19:48:16 +0300
Subject: [PATCH 0/5] drm/rockchip: vop2: Fix layer cfg done timeout on
 multi-output setups
In-Reply-To: <2d2b6308-ae46-46fd-b1ce-e4f199b6eb27@rock-chips.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
 <2d2b6308-ae46-46fd-b1ce-e4f199b6eb27@rock-chips.com>
Message-ID: <47cf1380-e36b-4e09-943d-88351cbc7915@collabora.com>

Hi Andy,

On 6/1/26 1:54 PM, Andy Yan wrote:
> Hello Cristian,
> 
> On 5/5/26 02:23, Cristian Ciocaltea wrote:
>> On RK3588/RK3568 boards with multiple active display outputs, start/stop
>> transitions may trigger a timeout during overlay layer configuration:
>>
>>    rockchip-drm display-subsystem: [drm] *ERROR* wait layer cfg done timeout
>>
>> The shared OVL_LAYER_SEL and OVL_PORT_SEL shadow registers are committed
>> to the active configuration at the vsync of whichever Video Port is
>> selected by LAYERSEL_REGDONE_SEL.  When two Video Ports race through
>> atomic commits, rk3568_vop2_setup_layer_mixer() has two issues that
>> cause the wait to poll for a value the hardware might not be able to
>> produce.
>>
>> Patch 1 fixes passing the wrong target to the wait function, since the
>> expected value was already overwritten with the current VP's new
>> layer_sel before reaching the wait.
>>
>> Patch 2 moves the wait before the LAYERSEL_REGDONE_SEL switch, so the
>> previous VP's vsync can still latch the pending configuration.
>>
>> Patches 3 through 5 contain only minor follow-up cleanup.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> 
> Thank you very much for your work, these fixes all look sensible.

Thanks for checking this out!

> However, I haven't been able to construct a scenario via weston that
> reproduce these issues. Could you please tell me how you triggered them?

It was really tricky to reproduce - a customer usecase repeatedly restarting one
of their apps under a customized Weston, and all that when having both HDMI
output ports active, where at least one drives a 4K display.

Regards,
Cristian


From sebastian.reichel at collabora.com  Mon Jun  1 10:34:13 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 1 Jun 2026 19:34:13 +0200
Subject: [PATCH] ASoC: rockchip: i2s: Use managed hclk and runtime PM
 cleanup
In-Reply-To: <20260521-asoc-rockchip-i2s-devm-cleanup-v1-1-9319bd781393@gmail.com>
References: <20260521-asoc-rockchip-i2s-devm-cleanup-v1-1-9319bd781393@gmail.com>
Message-ID: <ah3Ccc6D3c7sxg6U@venus>

Hi,

On Thu, May 21, 2026 at 11:30:07PM -0300, C?ssio Gabriel wrote:
> The Rockchip I2S driver mixes devm-managed probe resources with manual
> runtime PM and hclk cleanup.  This leaves the remove path doing runtime PM
> shutdown and clock disable before devm-managed ASoC and PCM resources are
> released.
> 
> Keep the bus clock enabled for the device lifetime with
> devm_clk_get_enabled(), and move the runtime PM teardown into devres so the
> unwind order matches the managed registrations.  This also removes the
> remove callback, which only existed for cleanup.
> 
> Use a devm action for the final runtime suspend and register it before the
> managed runtime PM action, so teardown disables runtime PM before forcing
> the device into the suspended state.
> 
> Signed-off-by: C?ssio Gabriel <cassiogabrielcontato at gmail.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

Greetings,

-- Sebastian

>  sound/soc/rockchip/rockchip_i2s.c | 68 +++++++++++++++------------------------
>  1 file changed, 26 insertions(+), 42 deletions(-)
> 
> diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
> index 49ff86b35ef1..4e3af0f37941 100644
> --- a/sound/soc/rockchip/rockchip_i2s.c
> +++ b/sound/soc/rockchip/rockchip_i2s.c
> @@ -664,6 +664,14 @@ static const struct of_device_id rockchip_i2s_match[] __maybe_unused = {
>  };
>  MODULE_DEVICE_TABLE(of, rockchip_i2s_match);
>  
> +static void rockchip_i2s_suspend(void *data)
> +{
> +	struct device *dev = data;
> +
> +	if (!pm_runtime_status_suspended(dev))
> +		i2s_runtime_suspend(dev);
> +}
> +
>  static int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res,
>  				 struct snd_soc_dai_driver **dp)
>  {
> @@ -758,37 +766,28 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
>  	}
>  
>  	/* try to prepare related clocks */
> -	i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");
> +	i2s->hclk = devm_clk_get_enabled(&pdev->dev, "i2s_hclk");
>  	if (IS_ERR(i2s->hclk)) {
>  		dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
>  		return PTR_ERR(i2s->hclk);
>  	}
> -	ret = clk_prepare_enable(i2s->hclk);
> -	if (ret) {
> -		dev_err(i2s->dev, "hclock enable failed %d\n", ret);
> -		return ret;
> -	}
>  
>  	i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
>  	if (IS_ERR(i2s->mclk)) {
>  		dev_err(&pdev->dev, "Can't retrieve i2s master clock\n");
> -		ret = PTR_ERR(i2s->mclk);
> -		goto err_clk;
> +		return PTR_ERR(i2s->mclk);
>  	}
>  
>  	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
> -	if (IS_ERR(regs)) {
> -		ret = PTR_ERR(regs);
> -		goto err_clk;
> -	}
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
>  
>  	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
>  					    &rockchip_i2s_regmap_config);
>  	if (IS_ERR(i2s->regmap)) {
>  		dev_err(&pdev->dev,
>  			"Failed to initialise managed register map\n");
> -		ret = PTR_ERR(i2s->regmap);
> -		goto err_clk;
> +		return PTR_ERR(i2s->regmap);
>  	}
>  
>  	i2s->bclk_ratio = 64;
> @@ -799,8 +798,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
>  			i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl, "bclk_off");
>  			if (IS_ERR_OR_NULL(i2s->bclk_off)) {
>  				dev_err(&pdev->dev, "failed to find i2s bclk_off\n");
> -				ret = -EINVAL;
> -				goto err_clk;
> +				return -EINVAL;
>  			}
>  		}
>  	} else {
> @@ -811,16 +809,23 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
>  
>  	dev_set_drvdata(&pdev->dev, i2s);
>  
> -	pm_runtime_enable(&pdev->dev);
> +	ret = devm_add_action(&pdev->dev, rockchip_i2s_suspend, &pdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_pm_runtime_enable(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
>  	if (!pm_runtime_enabled(&pdev->dev)) {
>  		ret = i2s_runtime_resume(&pdev->dev);
>  		if (ret)
> -			goto err_pm_disable;
> +			return ret;
>  	}
>  
>  	ret = rockchip_i2s_init_dai(i2s, res, &dai);
>  	if (ret)
> -		goto err_pm_disable;
> +		return ret;
>  
>  	ret = devm_snd_soc_register_component(&pdev->dev,
>  					      &rockchip_i2s_component,
> @@ -828,36 +833,16 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
>  
>  	if (ret) {
>  		dev_err(&pdev->dev, "Could not register DAI\n");
> -		goto err_suspend;
> +		return ret;
>  	}
>  
>  	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
>  	if (ret) {
>  		dev_err(&pdev->dev, "Could not register PCM\n");
> -		goto err_suspend;
> +		return ret;
>  	}
>  
>  	return 0;
> -
> -err_suspend:
> -	if (!pm_runtime_status_suspended(&pdev->dev))
> -		i2s_runtime_suspend(&pdev->dev);
> -err_pm_disable:
> -	pm_runtime_disable(&pdev->dev);
> -err_clk:
> -	clk_disable_unprepare(i2s->hclk);
> -	return ret;
> -}
> -
> -static void rockchip_i2s_remove(struct platform_device *pdev)
> -{
> -	struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev);
> -
> -	pm_runtime_disable(&pdev->dev);
> -	if (!pm_runtime_status_suspended(&pdev->dev))
> -		i2s_runtime_suspend(&pdev->dev);
> -
> -	clk_disable_unprepare(i2s->hclk);
>  }
>  
>  static const struct dev_pm_ops rockchip_i2s_pm_ops = {
> @@ -866,7 +851,6 @@ static const struct dev_pm_ops rockchip_i2s_pm_ops = {
>  
>  static struct platform_driver rockchip_i2s_driver = {
>  	.probe = rockchip_i2s_probe,
> -	.remove = rockchip_i2s_remove,
>  	.driver = {
>  		.name = DRV_NAME,
>  		.of_match_table = of_match_ptr(rockchip_i2s_match),
> 
> ---
> base-commit: 40cc9602caf2539369bd3dd7d66ee67e204e75ef
> change-id: 20260521-asoc-rockchip-i2s-devm-cleanup-6cade5f495e5
> 
> Best regards,
> --  
> C?ssio Gabriel <cassiogabrielcontato at gmail.com>
> 
> 
-------------- 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-rockchip/attachments/20260601/ce7bb513/attachment.sig>

From cristian.ciocaltea at collabora.com  Mon Jun  1 11:00:03 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 21:00:03 +0300
Subject: [PATCH v2 1/2] drm/rockchip: vop2: Rename CSC_BT2020 to
 CSC_BT2020L
In-Reply-To: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
Message-ID: <20260601-vop2-bg-yuv-v2-1-e5aef1d16fec@collabora.com>

Rename CSC_BT2020 to CSC_BT2020L for consistency with the other
limited-range enum members (CSC_BT601L, CSC_BT709L) and to distinguish
it from a potential future full-range BT.2020 variant.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index a160077a507f..64ac07cb1b0d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -658,7 +658,7 @@ static int vop2_convert_csc_mode(int csc_mode)
 	case V4L2_COLORSPACE_JPEG:
 		return CSC_BT601F;
 	case V4L2_COLORSPACE_BT2020:
-		return CSC_BT2020;
+		return CSC_BT2020L;
 	default:
 		return CSC_BT709L;
 	}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
index 37722652844a..ffcb39c130aa 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -373,7 +373,7 @@ enum vop_csc_format {
 	CSC_BT601L,
 	CSC_BT709L,
 	CSC_BT601F,
-	CSC_BT2020,
+	CSC_BT2020L,
 };
 
 enum src_factor_mode {

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 11:00:02 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 21:00:02 +0300
Subject: [PATCH v2 0/2] YUV support for VOP2 background color
Message-ID: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>

Since commit bec7cbfa7d4f ("drm/rockchip: vop2: Support setting custom
background color") the VOP2 display controller allows configuring the
background color of each video output port.

However, this is currently limited to RGB formats.  When operating in
YUV overlay mode, the color must be programmed using YUV format.

Add the necessary RGB-to-YCbCr conversion logic, covering all color
spaces supported by the display controller: BT601L, BT601F, BT709L and
BT2020L.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v2:
- Used vop2_convert_csc_mode() helper to address an issue reported by
  vcstate->color_space holds a V4L2 colorspace enum
- Rebased onto latest drm-misc-next
- Link to v1: https://patch.msgid.link/20260524-vop2-bg-yuv-v1-0-dcb6a52923f5 at collabora.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: kernel at collabora.com
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
Sashiko: vop2_rgb16_to_yuv16() expects an enum vop_csc_format, but

---
Cristian Ciocaltea (2):
      drm/rockchip: vop2: Rename CSC_BT2020 to CSC_BT2020L
      drm/rockchip: vop2: Add YUV support to background color

 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 155 ++++++++++++++++++++++++---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |   2 +-
 2 files changed, 140 insertions(+), 17 deletions(-)
---
base-commit: e84b07e0a30b371117f9a1120a4645c213f39cd9
change-id: 20260524-vop2-bg-yuv-1b0e6a09c579



From cristian.ciocaltea at collabora.com  Mon Jun  1 11:00:04 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 01 Jun 2026 21:00:04 +0300
Subject: [PATCH v2 2/2] drm/rockchip: vop2: Add YUV support to background
 color
In-Reply-To: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
Message-ID: <20260601-vop2-bg-yuv-v2-2-e5aef1d16fec@collabora.com>

The VOP2 background color must be programmed with 10-bit precision,
using YUV format when the overlay operates in YUV mode, and RGB
otherwise.

Add the required RGB-to-YCbCr conversion logic, covering all color
spaces supported by the display controller: BT601L, BT601F, BT709L and
BT2020L.

Since the color is currently programmed to hardware on every atomic
commit, minimize the computation cost by splitting the work across the
two paths: in atomic_enable(), perform the conversion unconditionally
(the hardware state is unknown after power-on), while in atomic_flush(),
perform it only when the DRM property has actually changed.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 153 ++++++++++++++++++++++++---
 1 file changed, 138 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 64ac07cb1b0d..9b261f0c7eec 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -728,6 +728,89 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp,
 	vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode);
 }
 
+/*
+ * RGB-to-YCbCr conversion based on color_to_ycbcr() and rgb2ycbcr() from
+ * drivers/media/common/v4l2-tpg/v4l2-tpg-core.c.
+ *
+ * Limited-range Y offset & chroma midpoint are expressed in 16-bit space.
+ */
+#define RGB2YUV_LIMITED_Y_OFFSET	(16 << 8)
+#define RGB2YUV_CHROMA_OFFSET		(128 << 8)
+#define COEFF(v, r)			((s32)(0.5 + (v) * (r) * 256.0))
+
+struct rgb2yuv_matrix {
+	s32 y_r,  y_g,  y_b;
+	s32 cb_r, cb_g, cb_b;
+	s32 cr_r, cr_g, cr_b;
+	s32 y_offset;
+};
+
+/* BT.601 Limited range */
+static const struct rgb2yuv_matrix rgb2yuv_bt601l = {
+	.y_r  = COEFF(0.299, 219),   .y_g  = COEFF(0.587, 219),   .y_b  = COEFF(0.114, 219),
+	.cb_r = COEFF(-0.1687, 224), .cb_g = COEFF(-0.3313, 224), .cb_b = COEFF(0.5, 224),
+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4187, 224), .cr_b = COEFF(-0.0813, 224),
+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
+};
+
+/* BT.601 Full range */
+static const struct rgb2yuv_matrix rgb2yuv_bt601f = {
+	.y_r  = COEFF(0.299, 255),   .y_g  = COEFF(0.587, 255),   .y_b  = COEFF(0.114, 255),
+	.cb_r = COEFF(-0.1687, 255), .cb_g = COEFF(-0.3313, 255), .cb_b = COEFF(0.5, 255),
+	.cr_r = COEFF(0.5, 255),     .cr_g = COEFF(-0.4187, 255), .cr_b = COEFF(-0.0813, 255),
+	.y_offset = 0,
+};
+
+/* BT.709 Limited range */
+static const struct rgb2yuv_matrix rgb2yuv_bt709l = {
+	.y_r  = COEFF(0.2126, 219),  .y_g  = COEFF(0.7152, 219),  .y_b  = COEFF(0.0722, 219),
+	.cb_r = COEFF(-0.1146, 224), .cb_g = COEFF(-0.3854, 224), .cb_b = COEFF(0.5, 224),
+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4542, 224), .cr_b = COEFF(-0.0458, 224),
+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
+};
+
+/* BT.2020 Limited range */
+static const struct rgb2yuv_matrix rgb2yuv_bt2020l = {
+	.y_r  = COEFF(0.2627, 219),  .y_g  = COEFF(0.6780, 219),  .y_b  = COEFF(0.0593, 219),
+	.cb_r = COEFF(-0.1396, 224), .cb_g = COEFF(-0.3604, 224), .cb_b = COEFF(0.5, 224),
+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4598, 224), .cr_b = COEFF(-0.0402, 224),
+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
+};
+
+static const struct rgb2yuv_matrix *
+vop2_rgb2yuv_get_matrix(enum vop_csc_format csc)
+{
+	switch (csc) {
+	case CSC_BT601L:
+		return &rgb2yuv_bt601l;
+	case CSC_BT601F:
+		return &rgb2yuv_bt601f;
+	case CSC_BT2020L:
+		return &rgb2yuv_bt2020l;
+	case CSC_BT709L:
+	default:
+		return &rgb2yuv_bt709l;
+	}
+}
+
+/* Convert an RGB (16bpc) to YUV444 (16bpc). */
+static void vop2_rgb16_to_yuv16(int v4l2_cs, u16 r, u16 g, u16 b,
+				u16 *y, u16 *cb, u16 *cr)
+{
+	enum vop_csc_format csc = vop2_convert_csc_mode(v4l2_cs);
+	const struct rgb2yuv_matrix *m = vop2_rgb2yuv_get_matrix(csc);
+	s64 rs = r, gs = g, bs = b;
+	s64 ys, cbs, crs;
+
+	ys  = m->y_r  * rs + m->y_g  * gs + m->y_b  * bs;
+	cbs = m->cb_r * rs + m->cb_g * gs + m->cb_b * bs;
+	crs = m->cr_r * rs + m->cr_g * gs + m->cr_b * bs;
+
+	*y  = (ys  >> 16) + m->y_offset;
+	*cb = (cbs >> 16) + RGB2YUV_CHROMA_OFFSET;
+	*cr = (crs >> 16) + RGB2YUV_CHROMA_OFFSET;
+}
+
 static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)
 {
 	struct vop2 *vop2 = vp->vop2;
@@ -1554,12 +1637,58 @@ static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
 				DITHER_DOWN_ALLEGRO);
 }
 
-static void vop2_post_config(struct drm_crtc *crtc)
+static void vop2_bgcolor_setup(struct drm_crtc *crtc, bool force,
+			       struct drm_crtc_state *new_crtc_state,
+			       struct drm_crtc_state *old_crtc_state)
+{
+	struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(new_crtc_state);
+	struct rockchip_crtc_state *old_vcstate = to_rockchip_crtc_state(old_crtc_state);
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	u64 bgcolor = new_crtc_state->background_color;
+	u16 y, cb, cr;
+	u32 val;
+
+	if (!force && old_crtc_state->background_color == bgcolor &&
+	    old_vcstate->color_space == new_vcstate->color_space)
+		return;
+
+	/*
+	 * Background color is programmed with 10 bits of precision, using YUV
+	 * format when operating in YUV overlay mode, and RGB otherwise.
+	 */
+	if (new_vcstate->yuv_overlay) {
+		vop2_rgb16_to_yuv16(new_vcstate->color_space,
+				    DRM_ARGB64_GETR(bgcolor),
+				    DRM_ARGB64_GETG(bgcolor),
+				    DRM_ARGB64_GETB(bgcolor),
+				    &y, &cb, &cr);
+
+		val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, cr >> 6);
+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, y >> 6);
+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, cb >> 6);
+	} else {
+		/*
+		 * Since performance is more important than accuracy here, make
+		 * use of the DRM_ARGB64_GET*_BPCS() helpers.
+		 */
+		val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED,
+				 DRM_ARGB64_GETR_BPCS(bgcolor, 10));
+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val,
+			     DRM_ARGB64_GETG_BPCS(bgcolor, 10));
+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val,
+			     DRM_ARGB64_GETB_BPCS(bgcolor, 10));
+	}
+
+	vop2_vp_write(vp, RK3568_VP_DSP_BG, val);
+}
+
+static void vop2_post_config(struct drm_crtc *crtc, bool force,
+			     struct drm_crtc_state *new_crtc_state,
+			     struct drm_crtc_state *old_crtc_state)
 {
 	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;
+	struct drm_display_mode *mode = &new_crtc_state->adjusted_mode;
 	u16 vtotal = mode->crtc_vtotal;
 	u16 hdisplay = mode->crtc_hdisplay;
 	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
@@ -1605,15 +1734,7 @@ static void vop2_post_config(struct drm_crtc *crtc)
 		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
 	}
 
-	/*
-	 * Background color is programmed with 10 bits of precision.
-	 * Since performance is more important than accuracy here,
-	 * make use of the DRM_ARGB64_GET*_BPCS() helpers.
-	 */
-	val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR_BPCS(bgcolor, 10));
-	FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, DRM_ARGB64_GETG_BPCS(bgcolor, 10));
-	FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, DRM_ARGB64_GETB_BPCS(bgcolor, 10));
-	vop2_vp_write(vp, RK3568_VP_DSP_BG, val);
+	vop2_bgcolor_setup(crtc, force, new_crtc_state, old_crtc_state);
 }
 
 static int us_to_vertical_line(struct drm_display_mode *mode, int us)
@@ -1628,8 +1749,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
 	struct vop2 *vop2 = vp->vop2;
 	const struct vop2_data *vop2_data = vop2->data;
 	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
-	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc_state);
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 	unsigned long clock = mode->crtc_clock * 1000;
 	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
@@ -1799,7 +1921,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
 
 	clk_set_rate(vp->dclk, clock);
 
-	vop2_post_config(crtc);
+	vop2_post_config(crtc, true, crtc_state, old_crtc_state);
 
 	vop2_cfg_done(vp);
 
@@ -1874,6 +1996,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
 				   struct drm_atomic_commit *state)
 {
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
 	struct vop2_video_port *vp = to_vop2_video_port(crtc);
 	struct vop2 *vop2 = vp->vop2;
 
@@ -1881,7 +2004,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
 	if (!drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->color_mgmt_changed)
 		vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state);
 
-	vop2_post_config(crtc);
+	vop2_post_config(crtc, false, crtc_state, old_crtc_state);
 
 	vop2_cfg_done(vp);
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 11:08:49 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 1 Jun 2026 21:08:49 +0300
Subject: [PATCH v2 0/2] YUV support for VOP2 background color
In-Reply-To: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
Message-ID: <b0a60e27-03ec-425e-8ecd-b8f9bdaadf93@collabora.com>

Something got messed by while preparing the cover letter.
Fixed manually..

On 6/1/26 9:00 PM, Cristian Ciocaltea wrote:
> Since commit bec7cbfa7d4f ("drm/rockchip: vop2: Support setting custom
> background color") the VOP2 display controller allows configuring the
> background color of each video output port.
> 
> However, this is currently limited to RGB formats.  When operating in
> YUV overlay mode, the color must be programmed using YUV format.
> 
> Add the necessary RGB-to-YCbCr conversion logic, covering all color
> spaces supported by the display controller: BT601L, BT601F, BT709L and
> BT2020L.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
> Changes in v2:
> - Used vop2_convert_csc_mode() helper to address an issue reported by
>   Sashiko: vop2_rgb16_to_yuv16() expects an enum vop_csc_format, but
>   vcstate->color_space holds a V4L2 colorspace enum
> - Rebased onto latest drm-misc-next
> - Link to v1: https://patch.msgid.link/20260524-vop2-bg-yuv-v1-0-dcb6a52923f5 at collabora.com
> 
> ---
> Cristian Ciocaltea (2):
>       drm/rockchip: vop2: Rename CSC_BT2020 to CSC_BT2020L
>       drm/rockchip: vop2: Add YUV support to background color
> 
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 155 ++++++++++++++++++++++++---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |   2 +-
>  2 files changed, 140 insertions(+), 17 deletions(-)
> ---
> base-commit: e84b07e0a30b371117f9a1120a4645c213f39cd9
> change-id: 20260524-vop2-bg-yuv-1b0e6a09c579
> 



From cristian.ciocaltea at collabora.com  Mon Jun  1 11:32:16 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Mon, 1 Jun 2026 21:32:16 +0300
Subject: [PATCH 0/2] YUV support for VOP2 background color
In-Reply-To: <8061cc0.a9f1.19e836d8cf0.Coremail.andyshrk@163.com>
References: <20260524-vop2-bg-yuv-v1-0-dcb6a52923f5@collabora.com>
 <8061cc0.a9f1.19e836d8cf0.Coremail.andyshrk@163.com>
Message-ID: <d8d7362f-4f62-44ca-895f-15f804f53b0a@collabora.com>

Hi Andy,

On 6/1/26 4:44 PM, Andy Yan wrote:
> 
> Hello Cristian,
> 
> At 2026-05-25 00:27:27, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>> Since commit bec7cbfa7d4f ("drm/rockchip: vop2: Support setting custom
>> background color") the VOP2 display controller allows configuring the
>> background color of each video output port.
>>
>> However, this is currently limited to RGB formats.  When operating in
>> YUV overlay mode, the color must be programmed using YUV format.
>>
>> Add the necessary RGB-to-YCbCr conversion logic, covering all color
>> spaces supported by the display controller: BT601L, BT601F, BT709L and
>> BT2020L.
>>
> 
> 
> Do you currently have a branch that makes dw-hdmi-qp output in YUV mode ?

Yes, please check [1] which is based on a subset of Nicolas' color format
series. 

Note I've also submitted a new revision [2] to handle the conversion from V4L2
colorspace to vop_csc_format (already included in [1]).

Quick test:

# Switch to YUV444
$ modetest -M rockchip -P 34 at 82:1920x1080+960+540 -w 82:BACKGROUND_COLOR:18446462598732840960 -w 85:'color format':2

# Switch to RGB
$ modetest -M rockchip -P 34 at 82:1920x1080+960+540 -w 82:BACKGROUND_COLOR:18446462598732840960 -w 85:'color format':1

Regards,
Cristian

[1] https://gitlab.collabora.com/cristicc/linux-next/-/commits/rk3588-yuv420
[2] https://lore.kernel.org/all/20260601-vop2-bg-yuv-v2-0-e5aef1d16fec at collabora.com/


From heiko at sntech.de  Mon Jun  1 14:14:52 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 01 Jun 2026 23:14:52 +0200
Subject: [PATCH v6 0/3] arm64: dts: rockchip: add Vicharak Axon board support
In-Reply-To: <20260601162143.170030-1-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
Message-ID: <9705193.oDFzTOozpa@phil>

Hi,

Am Montag, 1. Juni 2026, 18:21:39 Mitteleurop?ische Sommerzeit schrieb Hrushiraj Gandhi:
> This series adds initial device tree support for the Vicharak Axon
> single-board computer, which is based on the Rockchip RK3588 SoC.
> 
> The Vicharak Axon is a feature-rich SBC targeting developer and embedded
> use cases. It ships with:
> 
>   - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
>   - RK806 PMIC providing all SoC power domains
>   - eMMC 5.1 (on-board) and microSD slot
>   - Gigabit Ethernet via RGMII (RTL8211F)
>   - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
>   - PCIe 3.0 x4 and two PCIe 2.0 slots
>   - SATA 3.0
>   - USB 2.0 host ports (EHCI/OHCI)
>   - NXP PCA9554 I/O expander for status LEDs
>   - Haoyu HYM8563 RTC
> 
> Changes since v5:
> - Enabled `i2s5_8ch` and `i2s6_8ch` CPU DAIs to resolve probe deferral issues for `hdmi0_sound` and `hdmi1_sound`.

please don't flood the lists with 6 versions in a single day.
Generally we want 1-2 days betwqeen versions to give people time
to actually review them.

All changelogs contain at least some changes that should have been
caught before sending patches to the lists. So please don't iterate
by sending patches and instead test locally and make sure _everything_
works before sending patches.


Thanks
Heiko



> 
> Changes since v4:
> - Re-enabled `combphy2_psu` which is a required PHY for `pcie2x1l1`. (It was incorrectly removed in v4 during the unused PHY cleanup).
> - Fixed alphabetical sorting of `rk3588-vicharak-axon.dtb` in the Makefile.
> 
> Changes since v3:
> - Completely removed `sdio_pwrseq` and `wireless-wlan` pinctrl nodes as Wi-Fi/SDIO was already removed.
> - Removed unused `u2phy0`, `u2phy0_otg`, `u2phy1`, `u2phy1_otg` nodes to fix orphaned PHY warnings, since the USB 2.0 host ports utilize `u2phy2` and `u2phy3`.
> 
> Changes since v2:
> - Split the dt-bindings patch into two separate patches: one for the vendor prefix and one for the board binding as requested by Heiko.
> - Removed invalid `enable-gpios` property from HDMI nodes (ignored by dw-hdmi-qp binding)
> - Fixed copy-paste error in `rk806_dvs1_null` pinctrl node (gpio_pwrctrl2 -> gpio_pwrctrl1)
> 
> Changes since v1:
> - Renamed the dts file from rk3588-axon.dts to rk3588-vicharak-axon.dts
> - Added binding patches for the board (rockchip.yaml) and vendor (vendor-prefixes.yaml)
> - Renamed regulator nodes to the standard `regulator-name` pattern
> - Removed `mem-supply` properties and phandles from cpu nodes (vendor-kernel specific)
> - Fixed pcie20_avdd0v85 vin-supply mismatch
> - Removed obsolete `regulator-compatible` property
> - Removed invalid `regulator-init-microvolt` property
> - Removed dangling `enable-active-high` properties from fixed regulators
> - Cleaned up unneeded i2c3 / es8388 nodes
> - Added missing `vpcie3v3-supply` properties to PCIe nodes
> 
> Hrushiraj Gandhi (3):
>   dt-bindings: vendor-prefixes: add vicharak
>   dt-bindings: arm: rockchip: add Vicharak Axon board
>   arm64: dts: rockchip: add Vicharak Axon board
> 
>  .../devicetree/bindings/arm/rockchip.yaml     |   5 +
>  .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
>  arch/arm64/boot/dts/rockchip/Makefile         |   1 +
>  .../dts/rockchip/rk3588-vicharak-axon.dts     | 991 ++++++++++++++++++
>  4 files changed, 999 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
> 
> 






From sebastian.reichel at collabora.com  Mon Jun  1 15:08:46 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Tue, 2 Jun 2026 00:08:46 +0200
Subject: [PATCH 1/5] drm/bridge: Implement generic USB Type-C DP HPD
 bridge
In-Reply-To: <20260521032854.103-2-kernel@airkyi.com>
References: <20260521032854.103-1-kernel@airkyi.com>
 <20260521032854.103-2-kernel@airkyi.com>
Message-ID: <ah3-auKugGCVojOp@venus>

Hi,

On Thu, May 21, 2026 at 11:28:50AM +0800, Chaoyi Chen wrote:
> 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>
> ---
>  drivers/gpu/drm/bridge/Kconfig                | 10 ++++
>  drivers/gpu/drm/bridge/Makefile               |  1 +
>  .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 49 +++++++++++++++++++

Doesn't this require removing the manual registration of the HPD
auxillary bridge in the USB-C controller drivers to avoid that
two bridges are registered for them?

>  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 c3209b0f4678..d92e93875793 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 beab5b695a6e..c4761526ba0a 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));

IIUIC this is called when the USB-C controller spawns a sub-device
for the DP AltMode and then registers a HPD bridge to the USB-C
controller itself. Wouldn't that register new HPD bridges on every
USB-C replug?

Also doesn't this result in the bridge not being registered when
nothing is plugged and thus the DRM pipeline not being able to bind
properly?

Greetings,

-- Sebastian

> +
> +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.53.0
> 
> 
-------------- 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-rockchip/attachments/20260602/f937472d/attachment.sig>

From sebastian.reichel at collabora.com  Mon Jun  1 15:27:51 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Tue, 2 Jun 2026 00:27:51 +0200
Subject: [PATCH 2/5] drm/bridge: aux: Add
 drm_aux_bridge_register_from_node()
In-Reply-To: <20260521032854.103-3-kernel@airkyi.com>
References: <20260521032854.103-1-kernel@airkyi.com>
 <20260521032854.103-3-kernel@airkyi.com>
Message-ID: <ah4HP0VuZEFUaLlt@venus>

Hi,

On Thu, May 21, 2026 at 11:28:51AM +0800, Chaoyi Chen wrote:
> 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>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

Greetings,

-- Sebastian

>  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 1ed21a8713bf..f50283abed5f 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.53.0
> 
> 
-------------- 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-rockchip/attachments/20260602/f36b210d/attachment-0001.sig>

From sebastian.reichel at collabora.com  Mon Jun  1 15:28:20 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Tue, 2 Jun 2026 00:28:20 +0200
Subject: [PATCH 3/5] phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
In-Reply-To: <20260521032854.103-4-kernel@airkyi.com>
References: <20260521032854.103-1-kernel@airkyi.com>
 <20260521032854.103-4-kernel@airkyi.com>
Message-ID: <ah4Ha3Y0I68i9j1z@venus>

Hi,

On Thu, May 21, 2026 at 11:28:52AM +0800, Chaoyi Chen wrote:
> 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>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>

Greetings,

-- Sebastian

>  drivers/phy/rockchip/Kconfig              |  2 ++
>  drivers/phy/rockchip/phy-rockchip-typec.c | 13 +++++++++++--
>  2 files changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
> index 14698571b607..9173d3b4fef4 100644
> --- a/drivers/phy/rockchip/Kconfig
> +++ b/drivers/phy/rockchip/Kconfig
> @@ -119,6 +119,8 @@ config PHY_ROCKCHIP_SNPS_PCIE3
>  config PHY_ROCKCHIP_TYPEC
>  	tristate "Rockchip TYPEC PHY Driver"
>  	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
> +	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 d9701b6106d5..48070b50416e 100644
> --- a/drivers/phy/rockchip/phy-rockchip-typec.c
> +++ b/drivers/phy/rockchip/phy-rockchip-typec.c
> @@ -54,6 +54,7 @@
>  
>  #include <linux/mfd/syscon.h>
>  #include <linux/phy/phy.h>
> +#include <drm/bridge/aux-bridge.h>
>  
>  #define CMN_SSM_BANDGAP			(0x21 << 2)
>  #define CMN_SSM_BIAS			(0x22 << 2)
> @@ -1162,16 +1163,24 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
>  
>  	for_each_available_child_of_node(np, child_np) {
>  		struct phy *phy;
> +		ret = 0;
>  
> -		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"))
> +			ret = drm_aux_bridge_register_from_node(dev, child_np);
> +		} else if (of_node_name_eq(child_np, "usb3-port"))
>  			phy = devm_phy_create(dev, child_np,
>  					      &rockchip_usb3_phy_ops);
>  		else
>  			continue;
>  
> +		if (ret) {
> +			pm_runtime_disable(dev);
> +			of_node_put(child_np);
> +			return ret;
> +		}
> +
>  		if (IS_ERR(phy)) {
>  			dev_err(dev, "failed to create phy: %pOFn\n",
>  				child_np);
> -- 
> 2.53.0
> 
> 
-------------- 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-rockchip/attachments/20260602/73eb20db/attachment.sig>

From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:00 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:00 +0300
Subject: [PATCH v7 00/30] Add HDMI 2.0 support to DW HDMI QP TX
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>

Enable HDMI 2.0 display modes (e.g. 4K at 60Hz) on the Synopsys DW HDMI QP
TX controller, as found in Rockchip RK3576 & RK3588 SoCs, by adding SCDC
management for high TMDS clock ratio and scrambling.

Since SCDC state is lost on sink disconnects, the bridge driver needs to
trigger a CRTC reset during connector detection.  To support this, the
series introduces the connector and bridge scrambling infrastructure
(patches 1-8), wires it up through the bridge connector layer with an
atomic-aware detect_ctx hook (patches 9-11), then implements the SCDC
scrambling feature in the DW HDMI QP bridge driver (patches 12-15).

Patches 16-18 are minor cleanups in the Rockchip platform driver.
Patches 19-23 improve HPD handling by deferring IRQ registration until
the connector is fully initialized, adding .enable_hpd()/.disable_hpd()
PHY ops, and restricting HPD events to the affected connector.

Patches 24-25 convert vc4 HDMI to the common SCDC scrambling helpers as
a proof of reuse, replacing the driver-local scrambling implementation.

Patches 26-30 add KUnit tests: connector scrambler validation, a new
4K at 60Hz 600MHz EDID, hdmi_state_helper scrambling tests, and EDID
conformity fixes for some of the existing test blobs.

This has been tested on the following boards:

* Radxa ROCK 5B (RK3588)
* Radxa ROCK 4D (RK3576)
* Raspberry Pi 5 Model B Rev 1.1 (BCM2712 D0)

Regards,
Cristian

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v7:
- Split the scrambler_needed flag computation from the SCDC scrambling
  helpers into a standalone hdmi_state_helper patch for clarity (new
  patch 6)
- Added vc4 HDMI conversion to common TMDS char rate constants and SCDC
  scrambling helpers as a proof of reuse (new patches 24-25)
- Added KUnit tests for connector scrambler_supported/callback
  consistency validation (new patch 26)
- Added 4K at 60Hz 600MHz TMDS test EDID for high-rate scrambling coverage
  (new patch 27)
- Added KUnit tests for hdmi_state_helper scrambler_needed flag:
  low-rate, high-rate, and source-no-support cases (new patch 28)
- Fixed EDID conformity issues (edid-decode v1.33.0 failures) in the
  existing 1080p+4K YUV420 200MHz and 4K RGB/YUV 340MHz test EDIDs
  without changing the capabilities used by existing tests (new patches
  29-30)
- Rebased onto latest drm-misc-next
- Link to v6: https://patch.msgid.link/20260520-dw-hdmi-qp-scramb-v6-0-24b74603b782 at collabora.com

Changes in v6:
- Collected R-b & A-b tags from Dmitry and Heiko
- Restructured the series from 10 into 22 patches, splitting the SCDC
  scrambling helpers, connector infrastructure, bridge operations,
  bridge_connector plumbing, dw-hdmi-qp implementation, and Rockchip
  platform changes into distinct commits
- Added drm_scdc_dbg() macro to simplify debug messages (new patch)
- Added drm_scdc_start/stop/sync_status() helpers for full scrambling
  lifecycle management (reworked from v5 patch 5)
- Added drm_atomic_helper_connector_hdmi_hotplug_ctx() to propagate
  modeset acquire context for SCDC sync on hotplug (new patch)
- Added connector scrambler callbacks and SCDC work/flag infrastructure
  as a separate patch (split from v5 patch 5)
- Added DRM_BRIDGE_OP_HDMI_SCRAMBLER bridge operation with
  hdmi_scrambler_enable/disable callbacks (new patch)
- Implemented bridge_connector scrambler interface wiring (new patch)
- Added .enable_hpd()/.disable_hpd() PHY ops for dw-hdmi-qp bridge and
  Rockchip platform drivers, replacing the obsolete .setup_hpd() op
- Added dw_hdmi_qp_hpd_notify() helper for targeted connector-only HPD
  notification (split from v5 patch 10)
- Dropped drm_fb_helper_hotplug_event() unused variable (new cleanup)
- Dropped unused drm_simple_kms_helper.h include (new cleanup)
- Masked RK3576 HPD IRQ in io_init() for consistency with RK3588
- Rebased onto latest drm-misc-next
- Link to v5: https://patch.msgid.link/20260426-dw-hdmi-qp-scramb-v5-0-d778e70c317b at collabora.com

Changes in v5:
- Added new patches: 1/10, 3/10, 6/10, 7/10, 8/10
- Removed redundant no-op error check in drm_bridge_helper_reset_crtc()
  (patch 1)
- Removed the EDEADLK retry loop from the bridge .detect_ctx() callback,
  as that's already handled in the drm_bridge_detect_ctx() helper or by
  the caller when ctx is provided (patch 2)
- Refactored drm_bridge_detect() to delegate to drm_bridge_detect_ctx()
  and added a WARN_ON for unexpected negative return values (patch 2)
- Split the bridge-connector .detect_ctx() switch into a preparatory
  patch to use cached connector status in .get_modes() (patch 3)
- Improved error handling in SCDC scrambling setup: roll back high TMDS
  clock ratio on scrambling failure, reset scramb_enabled flag on
  set_scramb failure, and add SCDC version read/write error checks
  (patch 5)
- Annotated scramb_enabled with READ_ONCE/WRITE_ONCE for cross-context
  access between modeset paths and the scrambling work item (patch 5)
- Renamed SCDC_MIN_SOURCE_VERSION to SCDC_MAX_SOURCE_VERSION (patch 5)
- Rate limited i2c error messages (patch 6)
- Added missing newlines in dev_err_probe() messages (patch 7)
- Replaced indirect device pointer accesses with local dev variable in
  bind() (patch 8)
- Split the HPD connector restriction (formerly patch 4/4): register HPD
  IRQ after connector setup first (patch 9), then restrict HPD event to
  the affected connector (patch 10); also collected R-b from Heiko
- Rebased onto latest drm-misc-next
- Link to v4: https://lore.kernel.org/r/20260303-dw-hdmi-qp-scramb-v4-0-317d3b8bd219 at collabora.com

Changes in v4:
- Fixed conflicts while rebasing onto latest drm-misc-next
- Link to v3: https://lore.kernel.org/r/20260119-dw-hdmi-qp-scramb-v3-0-bd8611730fc1 at collabora.com

Changes in v3:
- Used drm_bridge_helper_reset_crtc() helper to reset the display
  pipeline and got rid of some boilerplate code (Maxime)
- Rebased onto latest drm-misc-next
- Link to v2: https://lore.kernel.org/r/20260113-dw-hdmi-qp-scramb-v2-0-ae7b2c58d24d at collabora.com

Changes in v2:
- Collected Tested-by tags from Diederik and Maud
- Rebased onto latest drm-misc-next
- Ensured the recently introduced 'no-hpd' support for dealing with
  unconnected/repurposed/broken HPD pin is limited to HDMI 1.4 rates
- Link to v1: https://lore.kernel.org/r/20251203-dw-hdmi-qp-scramb-v1-0-836fe7401a69 at collabora.com

---
Cristian Ciocaltea (30):
      drm/fb-helper: Remove unused local variable in hotplug_event()
      drm/connector: Add HDMI 2.0 scrambler infrastructure
      drm/display: scdc_helper: Add macro for connector-prefixed debug messages
      drm/display: scdc_helper: Add HDMI 2.0 scrambling management helpers
      drm/display: hdmi_state_helper: Add ctx-aware hotplug helper for SCDC sync
      drm/display: hdmi_state_helper: Plumb HDMI 2.0 source scrambling capability
      drm/bridge: Remove redundant error check in drm_bridge_helper_reset_crtc()
      drm/bridge: Add HDMI 2.0 scrambler bridge operation and callbacks
      drm/display: bridge_connector: Use cached connector status in .get_modes()
      drm/display: bridge_connector: Switch to .detect_ctx() connector helper
      drm/display: bridge_connector: Wire up HDMI 2.0 scrambler callbacks
      drm/bridge: dw-hdmi-qp: Rate limit i2c read error messages
      drm/bridge: dw-hdmi-qp: Provide .{enable|disable}_hpd() PHY ops
      drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC scrambling support
      drm/bridge: dw-hdmi-qp: Provide dw_hdmi_qp_hpd_notify() helper
      drm/rockchip: dw_hdmi_qp: Add missing newlines in dev_err_probe() messages
      drm/rockchip: dw_hdmi_qp: Use local dev variable consistently in bind()
      drm/rockchip: dw_hdmi_qp: Drop unnecessary #include
      drm/rockchip: dw_hdmi_qp: Defer HPD IRQ enable until after connector setup
      drm/rockchip: dw_hdmi_qp: Mask HPD IRQ in rk3576_io_init()
      drm/rockchip: dw_hdmi_qp: Implement .{enable|disable}_hpd() PHY ops
      drm/rockchip: dw_hdmi_qp: Switch to dw_hdmi_qp_hpd_notify()
      drm/bridge: dw-hdmi-qp: Remove obsolete .setup_hpd() phy op
      drm/vc4: hdmi: Use common TMDS char rate constants
      drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC scrambling helpers
      drm/tests: connector: Add HDMI source-side scrambler capability tests
      drm/tests: edid: Add 4K at 60Hz EDID with 600MHz TMDS
      drm/tests: hdmi_state_helper: Add HDMI 2.0 scrambling tests
      drm/tests: edid: Fix conformity for 1080p+4K YUV420 200MHz EDID
      drm/tests: edid: Fix conformity for 4K RGB/YUV 340MHz EDID

 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c       | 132 ++++++++--
 drivers/gpu/drm/display/drm_bridge_connector.c     | 119 ++++++---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c    |  55 +++-
 drivers/gpu/drm/display/drm_scdc_helper.c          | 269 ++++++++++++++++++--
 drivers/gpu/drm/drm_bridge_helper.c                |   2 -
 drivers/gpu/drm/drm_connector.c                    |  18 ++
 drivers/gpu/drm/drm_fb_helper.c                    |  11 +-
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c     | 130 +++++-----
 drivers/gpu/drm/tests/drm_connector_test.c         | 132 ++++++++++
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 219 ++++++++++++++++
 drivers/gpu/drm/tests/drm_kunit_edid.h             | 250 ++++++++++++++----
 drivers/gpu/drm/vc4/vc4_hdmi.c                     | 278 +++------------------
 drivers/gpu/drm/vc4/vc4_hdmi.h                     |   8 -
 include/drm/bridge/dw_hdmi_qp.h                    |   4 +-
 include/drm/display/drm_hdmi_state_helper.h        |   4 +
 include/drm/display/drm_scdc_helper.h              |   6 +-
 include/drm/drm_bridge.h                           |  26 ++
 include/drm/drm_connector.h                        |  81 ++++++
 18 files changed, 1285 insertions(+), 459 deletions(-)
---
base-commit: e84b07e0a30b371117f9a1120a4645c213f39cd9
change-id: 20251203-dw-hdmi-qp-scramb-cdbd8b57ccf9



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:01 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:01 +0300
Subject: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in
 hotplug_event()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>

Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
only stores a return value that is never used beyond the immediate
return statement.  This simplifies the code without behavior changes.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/drm_fb_helper.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 7b11a582f8ec..3316bb00a662 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1744,21 +1744,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
  */
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
-	int err = 0;
-
 	if (!drm_fbdev_emulation || !fb_helper)
 		return 0;
 
 	mutex_lock(&fb_helper->lock);
-	if (fb_helper->deferred_setup) {
-		err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
-		return err;
-	}
+	if (fb_helper->deferred_setup)
+		return __drm_fb_helper_initial_config_and_unlock(fb_helper);
 
 	if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
 		fb_helper->delayed_hotplug = true;
 		mutex_unlock(&fb_helper->lock);
-		return err;
+		return 0;
 	}
 
 	drm_master_internal_release(fb_helper->dev);
@@ -1802,4 +1798,3 @@ bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper,
 	return gem == obj;
 }
 EXPORT_SYMBOL_GPL(drm_fb_helper_gem_is_fb);
-

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:02 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:02 +0300
Subject: [PATCH v7 02/30] drm/connector: Add HDMI 2.0 scrambler
 infrastructure
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-2-445eb54ee1ed@collabora.com>

Add the connector-level infrastructure to support HDMI 2.0 scrambling:

- A scrambler_supported flag to indicate whether the source supports the
  scrambling capability, in which case the newly introduced
  .scrambler_{enable|disable}() callbacks in drm_connector_hdmi_funcs
  are mandatory
- A scrambler_needed flag to be managed by the hdmi state helpers based
  on the negotiated TMDS character rate and the source/sink scrambling
  capabilities
- A scrambler_enabled flag to track whether scrambling is currently
  active
- A delayed work item (scdc_work) with an associated callback (scdc_cb)
  to monitor sink-side scrambling status and retry the setup if the sink
  resets it

These are intended to be used by SCDC scrambling helpers to coordinate
scrambling setup and teardown between the source driver and the DRM
core.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/drm_connector.c | 18 +++++++++
 include/drm/drm_connector.h     | 81 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a5d13b92b665..526dc2931b8a 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
 	}
 }
 
+static void drm_connector_hdmi_scdc_work(struct work_struct *work)
+{
+	struct drm_connector *connector;
+	struct drm_connector_hdmi *hdmi;
+
+	hdmi = container_of(to_delayed_work(work), struct drm_connector_hdmi,
+			    scdc_work);
+	connector = container_of(hdmi, struct drm_connector, hdmi);
+
+	if (hdmi->scdc_cb)
+		hdmi->scdc_cb(connector);
+}
+
 static int drm_connector_init_only(struct drm_device *dev,
 				   struct drm_connector *connector,
 				   const struct drm_connector_funcs *funcs,
@@ -285,6 +298,7 @@ static int drm_connector_init_only(struct drm_device *dev,
 	mutex_init(&connector->edid_override_mutex);
 	mutex_init(&connector->hdmi.infoframes.lock);
 	mutex_init(&connector->hdmi_audio.lock);
+	INIT_DELAYED_WORK(&connector->hdmi.scdc_work, drm_connector_hdmi_scdc_work);
 	connector->edid_blob_ptr = NULL;
 	connector->epoch_counter = 0;
 	connector->tile_blob_ptr = NULL;
@@ -606,6 +620,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
 	    !hdmi_funcs->hdmi.write_infoframe)
 		return -EINVAL;
 
+	if (connector->hdmi.scrambler_supported &&
+	    (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable))
+		return -EINVAL;
+
 	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
 	if (ret)
 		return ret;
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 529755c2e862..f1c5c15a6cce 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -28,6 +28,7 @@
 #include <linux/ctype.h>
 #include <linux/hdmi.h>
 #include <linux/notifier.h>
+#include <linux/workqueue.h>
 #include <drm/drm_mode_object.h>
 #include <drm/drm_util.h>
 #include <drm/drm_property.h>
@@ -1057,6 +1058,19 @@ struct drm_connector_hdmi_state {
 	 * @tmds_char_rate: TMDS Character Rate, in Hz.
 	 */
 	unsigned long long tmds_char_rate;
+
+	/**
+	 * @scrambler_needed: Whether HDMI 2.0 SCDC scrambling is required
+	 * for the negotiated mode/bpc/format.
+	 *
+	 * Computed by drm_atomic_helper_connector_hdmi_check() from
+	 * @tmds_char_rate and the source/sink scrambling capabilities.
+	 *
+	 * Per HDMI 2.0, scrambling is mandatory above 340 MHz TMDS
+	 * character rate. Optional scrambling at lower rates is
+	 * deliberately not requested by the helper.
+	 */
+	bool scrambler_needed;
 };
 
 /**
@@ -1358,6 +1372,36 @@ struct drm_connector_hdmi_funcs {
 	 */
 	const struct drm_edid *(*read_edid)(struct drm_connector *connector);
 
+	/**
+	 * @scrambler_enable:
+	 *
+	 * This callback is invoked through @drm_scdc_start_scrambling during
+	 * a commit to setup SCDC scrambling and high TMDS clock ratio on
+	 * source side.
+	 *
+	 * The @scrambler_enable callback is mandatory if HDMI 2.0 is to be
+	 * supported.
+	 *
+	 * Returns:
+	 * 0 on success, a negative error code otherwise
+	 */
+	int (*scrambler_enable)(struct drm_connector *connector);
+
+	/**
+	 * @scrambler_disable:
+	 *
+	 * This callback is invoked through @drm_scdc_stop_scrambling during
+	 * a commit to disable SCDC scrambling and high TMDS clock ratio on
+	 * source side.
+	 *
+	 * The @scrambler_disable callback is mandatory if HDMI 2.0 is to be
+	 * supported.
+	 *
+	 * Returns:
+	 * 0 on success, a negative error code otherwise
+	 */
+	int (*scrambler_disable)(struct drm_connector *connector);
+
 	/**
 	 * @avi:
 	 *
@@ -1960,6 +2004,43 @@ struct drm_connector_hdmi {
 	 */
 	unsigned long supported_formats;
 
+	/**
+	 * @scrambler_supported: Indicates whether the HDMI controller
+	 * (source) supports HDMI 2.0 SCDC scrambling.
+	 *
+	 * When true, @drm_connector_hdmi_funcs.scrambler_enable and
+	 * @drm_connector_hdmi_funcs.scrambler_disable are mandatory.
+	 * This is enforced by drmm_connector_hdmi_init().
+	 *
+	 * For HDMI bridge based drivers using drm_bridge_connector_init(),
+	 * this is propagated automatically from bridges that set the
+	 * DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+	 * Other drivers must set this field on @connector->hdmi before calling
+	 * drmm_connector_hdmi_init().
+	 */
+	bool scrambler_supported;
+
+	/**
+	 * @scrambler_enabled: Tracks whether HDMI 2.0 scrambler is currently enabled.
+	 */
+	bool scrambler_enabled;
+
+	/**
+	 * @scdc_work: Work item currently used to monitor sink-side scrambling
+	 * status and retry setup if the sink resets it.
+	 */
+	struct delayed_work scdc_work;
+
+	/** @scdc_cb: Callback to be invoked as part of @scdc_work.
+	 *
+	 * Currently used to monitor sink-side scrambling status and retry
+	 * setup if the sink resets it.
+	 *
+	 * This is assigned by the framework when making use of
+	 * drm_scdc_start_scrambling() helper.
+	 */
+	void (*scdc_cb)(struct drm_connector *connector);
+
 	/**
 	 * @funcs: HDMI connector Control Functions
 	 */

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:03 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:03 +0300
Subject: [PATCH v7 03/30] drm/display: scdc_helper: Add macro for
 connector-prefixed debug messages
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-3-445eb54ee1ed@collabora.com>

Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
rid of the boilerplate around prefixing the debug messages with the
connector information.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_scdc_helper.c | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index df878aad4a36..cb6632346aad 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -55,6 +55,10 @@
 
 #define SCDC_I2C_SLAVE_ADDRESS 0x54
 
+#define drm_scdc_dbg(connector, fmt, ...)					\
+	drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt,			\
+		    (connector)->base.id, (connector)->name, ##__VA_ARGS__)
+
 /**
  * drm_scdc_read - read a block of data from SCDC
  * @adapter: I2C controller
@@ -158,9 +162,7 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector)
 
 	ret = drm_scdc_readb(connector->ddc, SCDC_SCRAMBLER_STATUS, &status);
 	if (ret < 0) {
-		drm_dbg_kms(connector->dev,
-			    "[CONNECTOR:%d:%s] Failed to read scrambling status: %d\n",
-			    connector->base.id, connector->name, ret);
+		drm_scdc_dbg(connector, "Failed to read scrambling status: %d\n", ret);
 		return false;
 	}
 
@@ -188,9 +190,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
 
 	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
 	if (ret < 0) {
-		drm_dbg_kms(connector->dev,
-			    "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
-			    connector->base.id, connector->name, ret);
+		drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
 		return false;
 	}
 
@@ -201,9 +201,7 @@ bool drm_scdc_set_scrambling(struct drm_connector *connector,
 
 	ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
 	if (ret < 0) {
-		drm_dbg_kms(connector->dev,
-			    "[CONNECTOR:%d:%s] Failed to enable scrambling: %d\n",
-			    connector->base.id, connector->name, ret);
+		drm_scdc_dbg(connector, "Failed to enable scrambling: %d\n", ret);
 		return false;
 	}
 
@@ -248,9 +246,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
 
 	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
 	if (ret < 0) {
-		drm_dbg_kms(connector->dev,
-			    "[CONNECTOR:%d:%s] Failed to read TMDS config: %d\n",
-			    connector->base.id, connector->name, ret);
+		drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
 		return false;
 	}
 
@@ -261,9 +257,7 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
 
 	ret = drm_scdc_writeb(connector->ddc, SCDC_TMDS_CONFIG, config);
 	if (ret < 0) {
-		drm_dbg_kms(connector->dev,
-			    "[CONNECTOR:%d:%s] Failed to set TMDS clock ratio: %d\n",
-			    connector->base.id, connector->name, ret);
+		drm_scdc_dbg(connector, "Failed to set TMDS clock ratio: %d\n", ret);
 		return false;
 	}
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:04 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:04 +0300
Subject: [PATCH v7 04/30] drm/display: scdc_helper: Add HDMI 2.0 scrambling
 management helpers
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-4-445eb54ee1ed@collabora.com>

Add helpers to manage the full lifecycle of HDMI 2.0 SCDC scrambling on
both source and sink sides:

- drm_scdc_start_scrambling(): configures SCDC scrambling and high TMDS
  clock ratio and starts a periodic work item that monitors the sink's
  SCDC scrambling status, retrying setup when the sink loses state

- drm_scdc_stop_scrambling(): tears down scrambling on both sides and
  cancels the monitoring work

- drm_scdc_sync_status(): triggers a CRTC reset on reconnection to
  restore SCDC state lost during sink disconnects within an active
  display pipeline

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_scdc_helper.c | 245 +++++++++++++++++++++++++++++-
 include/drm/display/drm_scdc_helper.h     |   6 +-
 2 files changed, 244 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_scdc_helper.c b/drivers/gpu/drm/display/drm_scdc_helper.c
index cb6632346aad..f71728e5ca81 100644
--- a/drivers/gpu/drm/display/drm_scdc_helper.c
+++ b/drivers/gpu/drm/display/drm_scdc_helper.c
@@ -21,15 +21,22 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/i2c.h>
+#include <linux/minmax.h>
 #include <linux/slab.h>
-#include <linux/delay.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_modeset_lock.h>
+#include <drm/drm_print.h>
 
 #include <drm/display/drm_scdc_helper.h>
-#include <drm/drm_connector.h>
-#include <drm/drm_device.h>
-#include <drm/drm_print.h>
 
 /**
  * DOC: scdc helpers
@@ -50,10 +57,14 @@
  * has to track the connector status changes using interrupts and
  * restore the SCDC status. The typical solution for this is to trigger an
  * empty modeset in drm_connector_helper_funcs.detect_ctx(), like what vc4 does
- * in vc4_hdmi_reset_link().
+ * in vc4_hdmi_reset_link(). Alternatively, use the HDMI connector framework
+ * which ensures drm_scdc_sync_status() is called in the context of
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx().
  */
 
-#define SCDC_I2C_SLAVE_ADDRESS 0x54
+#define SCDC_I2C_SLAVE_ADDRESS		0x54
+#define SCDC_MAX_SOURCE_VERSION		0x1
+#define SCDC_STATUS_POLL_DELAY_MS	1000
 
 #define drm_scdc_dbg(connector, fmt, ...)					\
 	drm_dbg_kms((connector)->dev, "[CONNECTOR:%d:%s] " fmt,			\
@@ -270,3 +281,225 @@ bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector,
 	return true;
 }
 EXPORT_SYMBOL(drm_scdc_set_high_tmds_clock_ratio);
+
+static int drm_scdc_try_scrambling_setup(struct drm_connector *connector)
+{
+	bool done;
+
+	done = drm_scdc_set_high_tmds_clock_ratio(connector, true);
+	if (!done)
+		return -EIO;
+
+	done = drm_scdc_set_scrambling(connector, true);
+	if (!done)
+		return -EIO;
+
+	if (READ_ONCE(connector->hdmi.scrambler_enabled))
+		schedule_delayed_work(&connector->hdmi.scdc_work,
+				      msecs_to_jiffies(SCDC_STATUS_POLL_DELAY_MS));
+
+	return 0;
+}
+
+static void drm_scdc_monitor_scrambler(struct drm_connector *connector)
+{
+	if (READ_ONCE(connector->hdmi.scrambler_enabled) &&
+	    !drm_scdc_get_scrambling_status(connector))
+		drm_scdc_try_scrambling_setup(connector);
+}
+
+static int drm_scdc_reset_crtc(struct drm_connector *connector,
+			       struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_crtc *crtc;
+	u8 config;
+	int ret;
+
+	if (!ctx)
+		return 0;
+
+	/*
+	 * This is normally part of .detect_ctx() call path, which already holds
+	 * connection_mutex through @ctx.  However, re-acquiring it with the
+	 * same context is a no-op and makes the helper safe under any caller.
+	 */
+	ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
+
+	if (!connector->state)
+		return 0;
+
+	crtc = connector->state->crtc;
+	if (!crtc)
+		return 0;
+
+	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
+	if (ret) {
+		drm_scdc_dbg(connector, "Failed to read TMDS config: %d\n", ret);
+		return ret;
+	}
+
+	if ((config & SCDC_SCRAMBLING_ENABLE) &&
+	    (config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40))
+		return 0;
+
+	/*
+	 * Reset the CRTC to suspend TMDS transmission, conforming to HDMI 2.0
+	 * spec which requires scrambled data not to be sent before the sink is
+	 * configured, and TMDS clock to be suspended while changing the clock
+	 * ratio.  The disable/re-enable cycle triggered by the reset should
+	 * call drm_scdc_start_scrambling() during re-enable, properly
+	 * configuring the sink before data transmission resumes.
+	 */
+
+	drm_scdc_dbg(connector, "Resetting CRTC to restore SCDC status\n");
+
+	ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+	if (ret && ret != -EDEADLK)
+		drm_scdc_dbg(connector, "Failed to reset CRTC: %d\n", ret);
+
+	return ret;
+}
+
+/**
+ * drm_scdc_start_scrambling - activate scrambling and monitor SCDC status
+ * @connector: connector
+ *
+ * Enables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Additionally, use a delayed work item to monitor the scrambling status on
+ * the sink side and retry the operation, as some displays refuse to set the
+ * scrambling bit right away.
+ *
+ * Returns:
+ * Zero if scrambling is set successfully, an error code otherwise.
+ */
+int drm_scdc_start_scrambling(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+	struct drm_connector_hdmi *hdmi = &connector->hdmi;
+	int ret;
+	u8 ver;
+
+	if (!hdmi->scrambler_supported) {
+		drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+		return -EINVAL;
+	}
+
+	if (!info->is_hdmi ||
+	    !info->hdmi.scdc.supported ||
+	    !info->hdmi.scdc.scrambling.supported) {
+		drm_scdc_dbg(connector, "Sink doesn't support scrambling.\n");
+		return -EINVAL;
+	}
+
+	drm_scdc_dbg(connector, "Enabling scrambling\n");
+
+	ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &ver);
+	if (ret) {
+		drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
+			      min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
+	if (ret) {
+		drm_scdc_dbg(connector, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->scdc_cb = drm_scdc_monitor_scrambler;
+	WRITE_ONCE(hdmi->scrambler_enabled, true);
+
+	ret = drm_scdc_try_scrambling_setup(connector);
+	if (!ret)
+		ret = hdmi->funcs->scrambler_enable(connector);
+
+	if (ret) {
+		WRITE_ONCE(hdmi->scrambler_enabled, false);
+		cancel_delayed_work_sync(&hdmi->scdc_work);
+		hdmi->scdc_cb = NULL;
+
+		drm_scdc_set_scrambling(connector, false);
+		drm_scdc_set_high_tmds_clock_ratio(connector, false);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_scdc_start_scrambling);
+
+/**
+ * drm_scdc_stop_scrambling - deactivate scrambling and SCDC status monitor
+ * @connector: connector
+ *
+ * Disables scrambling and high TMDS clock ratio on both source and sink sides.
+ * Also cancels the SCDC status monitoring work item, if it is still pending.
+ *
+ * Returns:
+ * Zero if scrambling is reset successfully, an error code otherwise.
+ */
+int drm_scdc_stop_scrambling(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+	struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+	if (!hdmi->scrambler_supported) {
+		drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
+		return -EINVAL;
+	}
+
+	if (!READ_ONCE(hdmi->scrambler_enabled))
+		return 0;
+
+	drm_scdc_dbg(connector, "Disabling scrambling\n");
+
+	WRITE_ONCE(hdmi->scrambler_enabled, false);
+	cancel_delayed_work_sync(&hdmi->scdc_work);
+	hdmi->scdc_cb = NULL;
+
+	if (connector->status == connector_status_connected &&
+	    info->is_hdmi && info->hdmi.scdc.supported &&
+	    info->hdmi.scdc.scrambling.supported) {
+		drm_scdc_set_scrambling(connector, false);
+		drm_scdc_set_high_tmds_clock_ratio(connector, false);
+	}
+
+	return hdmi->funcs->scrambler_disable(connector);
+}
+EXPORT_SYMBOL(drm_scdc_stop_scrambling);
+
+/**
+ * drm_scdc_sync_status - resync the sink-side SCDC upon reconnect
+ * @connector: connector
+ * @plugged: connector plugged status event
+ * @ctx: initialized lock acquisition context
+ *
+ * When receiving hotplug disconnect/reconnect event, while the display is
+ * still active (CRTC enabled), the SCDC status on the sink side is reset
+ * and must be explicitly restored.
+ *
+ * The typical solution for this is to trigger an empty modeset in
+ * drm_connector_helper_funcs.detect_ctx(), which is what this helper does
+ * by triggering a CRTC reset on reconnection.
+ *
+ * When making use of the HDMI connector framework, this is automatically
+ * triggered via drm_atomic_helper_connector_hdmi_hotplug_ctx().
+ *
+ * Returns:
+ * Zero on success, an error code otherwise, including -EDEADLK.
+ */
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+			 struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_connector_hdmi *hdmi = &connector->hdmi;
+
+	if (hdmi->scrambler_supported && plugged &&
+	    READ_ONCE(hdmi->scrambler_enabled))
+		return drm_scdc_reset_crtc(connector, ctx);
+
+	/* TODO: Also handle HDMI 2.1 FRL link training */
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_scdc_sync_status);
diff --git a/include/drm/display/drm_scdc_helper.h b/include/drm/display/drm_scdc_helper.h
index 34600476a1b9..5d9a37bbb362 100644
--- a/include/drm/display/drm_scdc_helper.h
+++ b/include/drm/display/drm_scdc_helper.h
@@ -29,6 +29,7 @@
 #include <drm/display/drm_scdc.h>
 
 struct drm_connector;
+struct drm_modeset_acquire_ctx;
 struct i2c_adapter;
 
 ssize_t drm_scdc_read(struct i2c_adapter *adapter, u8 offset, void *buffer,
@@ -76,5 +77,8 @@ bool drm_scdc_get_scrambling_status(struct drm_connector *connector);
 
 bool drm_scdc_set_scrambling(struct drm_connector *connector, bool enable);
 bool drm_scdc_set_high_tmds_clock_ratio(struct drm_connector *connector, bool set);
-
+int drm_scdc_start_scrambling(struct drm_connector *connector);
+int drm_scdc_stop_scrambling(struct drm_connector *connector);
+int drm_scdc_sync_status(struct drm_connector *connector, bool plugged,
+			 struct drm_modeset_acquire_ctx *ctx);
 #endif

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:05 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:05 +0300
Subject: [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware
 hotplug helper for SCDC sync
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-5-445eb54ee1ed@collabora.com>

Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
drm_atomic_helper_connector_hdmi_hotplug() that accepts a
drm_modeset_acquire_ctx.

This enables SCDC status synchronization on hotplug events, which
requires lock acquisition context for performing the CRTC reset
triggered by drm_scdc_sync_status().

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
 include/drm/display/drm_hdmi_state_helper.h     |  4 +++
 2 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a331ebdd65af..a96d81cbf94f 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -12,6 +12,7 @@
 #include <drm/display/drm_hdmi_cec_helper.h>
 #include <drm/display/drm_hdmi_helper.h>
 #include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/display/drm_scdc_helper.h>
 
 /**
  * DOC: hdmi helpers
@@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
 
-static void
+static int
 drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
-					enum drm_connector_status status)
+					enum drm_connector_status status,
+					struct drm_modeset_acquire_ctx *ctx)
 {
 	const struct drm_edid *drm_edid;
+	int ret = 0;
 
 	if (status == connector_status_disconnected) {
-		// TODO: also handle scramber, HDMI sink disconnected.
+		ret = drm_scdc_sync_status(connector, false, ctx);
 		drm_connector_hdmi_audio_plugged_notify(connector, false);
 		drm_edid_connector_update(connector, NULL);
 		drm_connector_cec_phys_addr_invalidate(connector);
-		return;
+		return ret;
 	}
 
 	if (connector->hdmi.funcs->read_edid)
@@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
 	drm_edid_free(drm_edid);
 
 	if (status == connector_status_connected) {
-		// TODO: also handle scramber, HDMI sink is now connected.
+		ret = drm_scdc_sync_status(connector, true, ctx);
 		drm_connector_hdmi_audio_plugged_notify(connector, true);
 		drm_connector_cec_phys_addr_set(connector);
 	}
+
+	return ret;
 }
 
 /**
@@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
 void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
 					      enum drm_connector_status status)
 {
-	drm_atomic_helper_connector_hdmi_update(connector, status);
+	drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
 
+/**
+ * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
+ * @connector: A pointer to the HDMI connector
+ * @status: Connection status
+ * @ctx: Lock acquisition context to be used for resetting CRTC
+ *
+ * This function should be called as a part of the .detect() / .detect_ctx()
+ * callbacks for all status changes.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ * If @ctx is set, it might also return -EDEADLK.
+ */
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+						 enum drm_connector_status status,
+						 struct drm_modeset_acquire_ctx *ctx)
+{
+	return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
+
 /**
  * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
  * @connector: A pointer to the HDMI connector
@@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
  */
 void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
 {
-	drm_atomic_helper_connector_hdmi_update(connector, connector->status);
+	drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
index 13375bd0f4ae..75fedd4a3ba8 100644
--- a/include/drm/display/drm_hdmi_state_helper.h
+++ b/include/drm/display/drm_hdmi_state_helper.h
@@ -7,6 +7,7 @@ struct drm_atomic_commit;
 struct drm_connector;
 struct drm_connector_state;
 struct drm_display_mode;
+struct drm_modeset_acquire_ctx;
 struct hdmi_audio_infoframe;
 
 enum drm_connector_status;
@@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
 						       struct drm_atomic_commit *state);
 void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
 					      enum drm_connector_status status);
+int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
+						 enum drm_connector_status status,
+						 struct drm_modeset_acquire_ctx *ctx);
 void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector);
 
 enum drm_mode_status

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:06 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:06 +0300
Subject: [PATCH v7 06/30] drm/display: hdmi_state_helper: Plumb HDMI 2.0
 source scrambling capability
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-6-445eb54ee1ed@collabora.com>

Toggle drm_connector_hdmi_state.scrambler_needed flag when the TMDS
character rate exceeds 340 MHz and both the source and the sink advertise
SCDC scrambling capability.  Drivers no longer need to open-code this
check.

According to HDMI 2.0 spec, scrambling is only mandatory above 340 MHz;
the optional sub-340 MHz scrambling path is intentionally not requested.

Once all drivers are converted to advertise the scrambler support, the
unsupported HDMI 2.0 modes could be simply rejected.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a96d81cbf94f..7cb880dcedfe 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -588,6 +588,21 @@ hdmi_compute_clock(const struct drm_connector *connector,
 	if (status != MODE_OK)
 		return -EINVAL;
 
+	if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+		const struct drm_display_info *info = &connector->display_info;
+
+		/*
+		 * TODO: Reject unsupported HDMI 2.0 modes once all drivers
+		 *	 advertise their scrambler capability.
+		 */
+		conn_state->hdmi.scrambler_needed = connector->hdmi.scrambler_supported &&
+						    info->is_hdmi &&
+						    info->hdmi.scdc.supported &&
+						    info->hdmi.scdc.scrambling.supported;
+	} else {
+		conn_state->hdmi.scrambler_needed = false;
+	}
+
 	conn_state->hdmi.tmds_char_rate = clock;
 
 	return 0;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:07 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:07 +0300
Subject: [PATCH v7 07/30] drm/bridge: Remove redundant error check in
 drm_bridge_helper_reset_crtc()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-7-445eb54ee1ed@collabora.com>

Remove the no-op error check after drm_atomic_helper_reset_crtc() since
the goto target is the immediately following label and the return value
is already propagated correctly without it.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/drm_bridge_helper.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
index 420f29cf3e54..0a3c8fee66b3 100644
--- a/drivers/gpu/drm/drm_bridge_helper.c
+++ b/drivers/gpu/drm/drm_bridge_helper.c
@@ -50,8 +50,6 @@ int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
 
 	crtc = connector->state->crtc;
 	ret = drm_atomic_helper_reset_crtc(crtc, ctx);
-	if (ret)
-		goto out;
 
 out:
 	drm_modeset_unlock(&dev->mode_config.connection_mutex);

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:08 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:08 +0300
Subject: [PATCH v7 08/30] drm/bridge: Add HDMI 2.0 scrambler bridge
 operation and callbacks
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-8-445eb54ee1ed@collabora.com>

Add DRM_BRIDGE_OP_HDMI_SCRAMBLER bridge operation flag and the
corresponding .hdmi_scrambler_{enable|disable}() bridge funcs callbacks.

Bridge drivers are expected to set DRM_BRIDGE_OP_HDMI_SCRAMBLER to
advertise that they implement source-side scrambling control, which the
bridge connector layer uses to wire up the connector's scrambler
callbacks.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 include/drm/drm_bridge.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 4ba3a5deef9a..f36e1e71aa86 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -667,6 +667,26 @@ struct drm_bridge_funcs {
 				     const struct drm_display_mode *mode,
 				     unsigned long long tmds_rate);
 
+	/**
+	 * @hdmi_scrambler_enable:
+	 *
+	 * Enable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_scrambler_enable)(struct drm_bridge *bridge);
+
+	/**
+	 * @hdmi_scrambler_disable:
+	 *
+	 * Disable source-side HDMI 2.0 scrambling and high TMDS clock ratio.
+	 *
+	 * This callback is optional but it must be implemented by bridges that
+	 * set the DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
+	 */
+	int (*hdmi_scrambler_disable)(struct drm_bridge *bridge);
+
 	/**
 	 * @hdmi_clear_avi_infoframe:
 	 *
@@ -1092,6 +1112,12 @@ enum drm_bridge_ops {
 	 * &drm_bridge_funcs->hdmi_clear_spd_infoframe callbacks.
 	 */
 	DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME = BIT(10),
+	/**
+	 * @DRM_BRIDGE_OP_HDMI_SCRAMBLER: The bridge supports
+	 * &drm_bridge_funcs->hdmi_scrambler_enable and
+	 * &drm_bridge_funcs->hdmi_scrambler_disable callbacks.
+	 */
+	DRM_BRIDGE_OP_HDMI_SCRAMBLER = BIT(11),
 };
 
 /**

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:09 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:09 +0300
Subject: [PATCH v7 09/30] drm/display: bridge_connector: Use cached
 connector status in .get_modes()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-9-445eb54ee1ed@collabora.com>

Replace the active drm_bridge_connector_detect() call in get_modes()
with a read of the already-cached connector->status.

The .get_modes() callback is only invoked from
drm_helper_probe_single_connector_modes(), which has already retrieved
the connector status.  Calling detect again is redundant and triggers a
duplicate hotplug event.  This is also a prerequisite for switching to
the .detect_ctx() hook, which requires a drm_modeset_acquire_ctx not
available in the .get_modes() path.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index cafa498c3848..61c2a46edaf3 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -301,12 +301,10 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
 static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
 					       struct drm_bridge *bridge)
 {
-	enum drm_connector_status status;
 	const struct drm_edid *drm_edid;
 	int n;
 
-	status = drm_bridge_connector_detect(connector, false);
-	if (status != connector_status_connected)
+	if (connector->status != connector_status_connected)
 		goto no_edid;
 
 	drm_edid = drm_bridge_edid_read(bridge, connector);

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:10 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:10 +0300
Subject: [PATCH v7 10/30] drm/display: bridge_connector: Switch to
 .detect_ctx() connector helper
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-10-445eb54ee1ed@collabora.com>

Replace the .detect() connector_funcs callback with the atomic-aware
.detect_ctx() connector_helper_funcs hook.

This propagates the modeset acquire context through
drm_atomic_helper_connector_hdmi_hotplug_ctx() to the HDMI connector
framework, enabling SCDC state recovery via CRTC reset when the sink
reconnects during an active display pipeline.

Tested-by: Diederik de Haas <diederik at cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings at hotmail.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 74 ++++++++++++++------------
 1 file changed, 40 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 61c2a46edaf3..9d21b1b57b0d 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -208,39 +208,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 =
@@ -284,7 +251,6 @@ drm_bridge_connector_create_state(struct drm_connector *connector)
 }
 
 static const struct drm_connector_funcs drm_bridge_connector_funcs = {
-	.detect = drm_bridge_connector_detect,
 	.force = drm_bridge_connector_force,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.atomic_create_state = drm_bridge_connector_create_state,
@@ -298,6 +264,45 @@ 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;
+	enum drm_connector_status status;
+	int ret;
+
+	if (detect) {
+		status = detect->funcs->detect(detect, connector);
+
+		if (hdmi) {
+			ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector,
+									   status, ctx);
+			if (ret == -EDEADLK)
+				return ret;
+		}
+
+		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 int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
 					       struct drm_bridge *bridge)
 {
@@ -389,6 +394,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.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:11 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:11 +0300
Subject: [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0
 scrambler callbacks
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-11-445eb54ee1ed@collabora.com>

Connect the bridge connector's .scrambler_{enable|disable} callbacks to
the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.

This completes the bridge connector plumbing so that the SCDC
scrambling helpers can control source-side scrambling through the
bridge chain.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 9d21b1b57b0d..d048ab49eade 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
 	return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
 }
 
+static int drm_bridge_connector_scrambler_enable(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_scrambler_enable(bridge);
+}
+
+static int drm_bridge_connector_scrambler_disable(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_scrambler_disable(bridge);
+}
+
 static const struct drm_edid *
 drm_bridge_connector_read_edid(struct drm_connector *connector)
 {
@@ -580,7 +606,7 @@ 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, hdr_drm and spd are set dynamically during init */
+	/* scrambler, audio, hdr_drm and spd are set dynamically during init */
 };
 
 static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
@@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 			     !bridge->funcs->hdmi_clear_spd_infoframe))
 				return ERR_PTR(-EINVAL);
 
+			if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
+			    (!bridge->funcs->hdmi_scrambler_enable ||
+			     !bridge->funcs->hdmi_scrambler_disable))
+				return ERR_PTR(-EINVAL);
+
 			bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
 
 			if (bridge->supported_formats)
@@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
 			bridge_connector->hdmi_funcs.spd =
 				drm_bridge_connector_hdmi_spd_infoframe;
 
+		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
+			bridge_connector->hdmi_funcs.scrambler_enable =
+				drm_bridge_connector_scrambler_enable;
+			bridge_connector->hdmi_funcs.scrambler_disable =
+				drm_bridge_connector_scrambler_disable;
+			connector->hdmi.scrambler_supported = true;
+		}
+
 		ret = drmm_connector_hdmi_init(drm, connector,
 					       bridge_connector->bridge_hdmi->vendor,
 					       bridge_connector->bridge_hdmi->product,

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:12 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:12 +0300
Subject: [PATCH v7 12/30] drm/bridge: dw-hdmi-qp: Rate limit i2c read error
 messages
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-12-445eb54ee1ed@collabora.com>

During EDID reads, repeated i2c errors can flood the kernel log:

[   25.361716] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[   25.363376] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
...
[   25.368671] dwhdmiqp-rockchip fde80000.hdmi: i2c read error
[   25.369440] dwhdmiqp-rockchip fde80000.hdmi: failed to get edid

Switch to dev_err_ratelimited() in dw_hdmi_qp_i2c_read() to reduce log
spam while still reporting the condition.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 1c214a8e6dc2..b3318655ceab 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -561,7 +561,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
 				dev_dbg_ratelimited(hdmi->dev,
 						    "i2c read timed out\n");
 			else
-				dev_err(hdmi->dev, "i2c read timed out\n");
+				dev_err_ratelimited(hdmi->dev, "i2c read timed out\n");
 			dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
 			return -EAGAIN;
 		}
@@ -572,7 +572,7 @@ static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
 				dev_dbg_ratelimited(hdmi->dev,
 						    "i2c read error\n");
 			else
-				dev_err(hdmi->dev, "i2c read error\n");
+				dev_err_ratelimited(hdmi->dev, "i2c read error\n");
 			dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0);
 			return -EIO;
 		}

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:13 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:13 +0300
Subject: [PATCH v7 13/30] drm/bridge: dw-hdmi-qp: Provide
 .{enable|disable}_hpd() PHY ops
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-13-445eb54ee1ed@collabora.com>

Implement the .hpd_enable() and .hpd_disable() bridge callbacks and
extend dw_hdmi_qp_phy_ops with corresponding hooks.

This enables the DRM core to control when HPD interrupts are armed,
which is needed to prevent premature interrupt delivery before the
connector is fully initialized, and to properly quiesce HPD during
suspend.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 18 ++++++++++++++++++
 include/drm/bridge/dw_hdmi_qp.h              |  2 ++
 2 files changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index b3318655ceab..3f72bea20ba4 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1189,6 +1189,22 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
 #define dw_hdmi_qp_cec_transmit NULL
 #endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
 
+static void dw_hdmi_qp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	if (hdmi->phy.ops->enable_hpd)
+		hdmi->phy.ops->enable_hpd(hdmi, hdmi->phy.data);
+}
+
+static void dw_hdmi_qp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	if (hdmi->phy.ops->disable_hpd)
+		hdmi->phy.ops->disable_hpd(hdmi, hdmi->phy.data);
+}
+
 static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1196,6 +1212,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
 	.atomic_enable = dw_hdmi_qp_bridge_atomic_enable,
 	.atomic_disable = dw_hdmi_qp_bridge_atomic_disable,
 	.detect = dw_hdmi_qp_bridge_detect,
+	.hpd_enable = dw_hdmi_qp_bridge_hpd_enable,
+	.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
 	.edid_read = dw_hdmi_qp_bridge_edid_read,
 	.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
 	.hdmi_clear_avi_infoframe = dw_hdmi_qp_bridge_clear_avi_infoframe,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index 6ea9c561cfef..b80fceffc315 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -17,6 +17,8 @@ struct dw_hdmi_qp_phy_ops {
 	void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
 	enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
 	void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+	void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
+	void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
 };
 
 struct dw_hdmi_qp_plat_data {

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:14 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:14 +0300
Subject: [PATCH v7 14/30] drm/bridge: dw-hdmi-qp: Add HDMI 2.0 SCDC
 scrambling support
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-14-445eb54ee1ed@collabora.com>

Enable HDMI 2.0 display modes (e.g. 4K at 60Hz) by implementing SCDC
scrambling and high TMDS clock ratio management for TMDS character
rates exceeding the 340 MHz HDMI 1.4b limit.

Reject modes requiring TMDS rates above 600 MHz since those require
HDMI 2.1 FRL which is not yet supported.  In no_hpd configurations,
further restrict to 340 MHz because SCDC requires a connected sink.

Tested-by: Diederik de Haas <diederik at cknow-tech.com>
Tested-by: Maud Spierings <maud_spierings at hotmail.com>
Acked-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 76 +++++++++++++++++++++-------
 1 file changed, 58 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 3f72bea20ba4..0250ddd8f91a 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>
@@ -15,12 +16,12 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
-#include <linux/workqueue.h>
 
 #include <drm/bridge/dw_hdmi_qp.h>
 #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>
@@ -162,6 +163,7 @@ struct dw_hdmi_qp {
 	} phy;
 
 	unsigned long ref_clk_rate;
+	struct drm_connector *curr_conn;
 	struct regmap *regm;
 	int main_irq;
 
@@ -752,26 +754,35 @@ static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge,
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 	struct drm_connector_state *conn_state;
-	struct drm_connector *connector;
 	unsigned int op_mode;
+	int ret;
 
-	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) {
-		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);
+	if (hdmi->curr_conn->display_info.is_hdmi) {
 		op_mode = 0;
 		hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
+
+		if (conn_state->hdmi.scrambler_needed) {
+			ret = drm_scdc_start_scrambling(hdmi->curr_conn);
+			if (ret)
+				dev_warn(hdmi->dev, "Failed to setup SCDC: %d\n", ret);
+		}
+
+		dev_dbg(hdmi->dev, "%s mode=HDMI %s rate=%llu bpc=%u scramb=%d\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,
+			hdmi->curr_conn->hdmi.scrambler_enabled);
 	} else {
-		dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
 		op_mode = OPMODE_DVI;
+		dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__);
 	}
 
 	hdmi->phy.ops->init(hdmi, hdmi->phy.data);
@@ -779,7 +790,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,
@@ -787,8 +798,14 @@ static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge,
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
+	if (!hdmi->curr_conn)
+		return;
+
 	hdmi->tmds_char_rate = 0;
 
+	drm_scdc_stop_scrambling(hdmi->curr_conn);
+
+	hdmi->curr_conn = NULL;
 	hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
 }
 
@@ -830,12 +847,12 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
 
-	/*
-	 * TODO: when hdmi->no_hpd is 1 we must not support modes that
-	 * require scrambling, including every mode with a clock above
-	 * HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ.
-	 */
-	if (rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+	if (hdmi->no_hpd && rate > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
+		dev_dbg(hdmi->dev, "Unsupported TMDS char rate in no_hpd mode: %lld\n", rate);
+		return MODE_CLOCK_HIGH;
+	}
+
+	if (rate > HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ) {
 		dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate);
 		return MODE_CLOCK_HIGH;
 	}
@@ -843,6 +860,26 @@ dw_hdmi_qp_bridge_tmds_char_rate_valid(const struct drm_bridge *bridge,
 	return MODE_OK;
 }
 
+static int dw_hdmi_qp_bridge_scrambler_enable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	dw_hdmi_qp_write(hdmi, 1, SCRAMB_CONFIG0);
+	dev_dbg(hdmi->dev, "scrambler enabled\n");
+
+	return 0;
+}
+
+static int dw_hdmi_qp_bridge_scrambler_disable(struct drm_bridge *bridge)
+{
+	struct dw_hdmi_qp *hdmi = bridge->driver_private;
+
+	dw_hdmi_qp_write(hdmi, 0, SCRAMB_CONFIG0);
+	dev_dbg(hdmi->dev, "scrambler disabled\n");
+
+	return 0;
+}
+
 static int dw_hdmi_qp_bridge_clear_avi_infoframe(struct drm_bridge *bridge)
 {
 	struct dw_hdmi_qp *hdmi = bridge->driver_private;
@@ -1216,6 +1253,8 @@ static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
 	.hpd_disable = dw_hdmi_qp_bridge_hpd_disable,
 	.edid_read = dw_hdmi_qp_bridge_edid_read,
 	.hdmi_tmds_char_rate_valid = dw_hdmi_qp_bridge_tmds_char_rate_valid,
+	.hdmi_scrambler_enable = dw_hdmi_qp_bridge_scrambler_enable,
+	.hdmi_scrambler_disable = dw_hdmi_qp_bridge_scrambler_disable,
 	.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,
@@ -1342,7 +1381,8 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 			   DRM_BRIDGE_OP_HDMI |
 			   DRM_BRIDGE_OP_HDMI_AUDIO |
 			   DRM_BRIDGE_OP_HDMI_HDR_DRM_INFOFRAME |
-			   DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME;
+			   DRM_BRIDGE_OP_HDMI_SPD_INFOFRAME |
+			   DRM_BRIDGE_OP_HDMI_SCRAMBLER;
 	if (!hdmi->no_hpd)
 		hdmi->bridge.ops |= DRM_BRIDGE_OP_HPD;
 	hdmi->bridge.of_node = pdev->dev.of_node;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:16 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:16 +0300
Subject: [PATCH v7 16/30] drm/rockchip: dw_hdmi_qp: Add missing newlines in
 dev_err_probe() messages
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-16-445eb54ee1ed@collabora.com>

Add the missing trailing newlines to a couple of dev_err_probe() calls
in dw_hdmi_qp_rockchip_bind().

Fixes: b6736a4ea3fa ("drm/rockchip: dw_hdmi_qp: Improve error handling with dev_err_probe()")
Fixes: e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp: Switch to drmm_encoder_init()")
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..296f9a3ba66a 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -589,14 +589,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
 	ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret)
-		return dev_err_probe(hdmi->dev, ret, "Failed to init encoder");
+		return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
 
 	platform_set_drvdata(pdev, hdmi);
 
 	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
 	if (IS_ERR(hdmi->hdmi))
 		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
-				     "Failed to bind dw-hdmi-qp");
+				     "Failed to bind dw-hdmi-qp\n");
 
 	connector = drm_bridge_connector_init(drm, encoder);
 	if (IS_ERR(connector))

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:15 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:15 +0300
Subject: [PATCH v7 15/30] drm/bridge: dw-hdmi-qp: Provide
 dw_hdmi_qp_hpd_notify() helper
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-15-445eb54ee1ed@collabora.com>

Export dw_hdmi_qp_hpd_notify() for platform drivers to report hot-plug
detection events.  Unlike drm_helper_hpd_irq_event() which polls all
connectors, this helper targets only the affected connector and ensures
.detect_ctx() is invoked on reconnection events to trigger SCDC state
recovery.

Note that this helper may sleep, so it must only be called from a
threaded HPD interrupt handler or a work function.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 31 ++++++++++++++++++++++++++++
 include/drm/bridge/dw_hdmi_qp.h              |  1 +
 2 files changed, 32 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 0250ddd8f91a..999229705ffb 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -29,6 +29,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_modes.h>
 #include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
 
 #include <media/cec.h>
 
@@ -1433,6 +1434,36 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
 
+/**
+ * dw_hdmi_qp_hpd_notify() - Notify a hot-plug detection event
+ * @hdmi: pointer to the DW HDMI QP controller
+ *
+ * Platform drivers should call this from their threaded IRQ handler or work
+ * function to notify the bridge of a connection status change.
+ * The bridge's .read_hpd() phy_ops callback is used to read the current
+ * connection status.
+ */
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi)
+{
+	enum drm_connector_status status;
+
+	status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
+	dev_dbg(hdmi->dev, "%s status=%d\n", __func__, status);
+
+	/*
+	 * When the display pipeline has been already active, switch to
+	 * drm_connector_helper_hpd_irq_event() to ensure .detect_ctx()
+	 * gets invoked, i.e. via drm_helper_probe_detect(), because
+	 * drm_bridge_hpd_notify() defers to a delayed hotplug path in
+	 * this case.
+	 */
+	if (hdmi->curr_conn && status == connector_status_connected)
+		drm_connector_helper_hpd_irq_event(hdmi->curr_conn);
+	else
+		drm_bridge_hpd_notify(&hdmi->bridge, status);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_hpd_notify);
+
 void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
 {
 	disable_irq(hdmi->main_irq);
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b80fceffc315..b4fb1c578a5b 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -36,6 +36,7 @@ struct dw_hdmi_qp_plat_data {
 struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 				   struct drm_encoder *encoder,
 				   const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_hpd_notify(struct dw_hdmi_qp *hdmi);
 void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
 void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
 #endif /* __DW_HDMI_QP__ */

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:17 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:17 +0300
Subject: [PATCH v7 17/30] drm/rockchip: dw_hdmi_qp: Use local dev variable
 consistently in bind()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-17-445eb54ee1ed@collabora.com>

Replace indirect struct device accesses via hdmi->dev and pdev->dev with
the local dev parameter already available in dw_hdmi_qp_rockchip_bind(),
for consistency and readability.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 33 +++++++++++++-------------
 1 file changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 296f9a3ba66a..46df5abe31a4 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -475,7 +475,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	struct clk *ref_clk;
 	int ret, irq, i;
 
-	if (!pdev->dev.of_node)
+	if (!dev->of_node)
 		return -ENODEV;
 
 	hdmi = drmm_kzalloc(drm, sizeof(*hdmi), GFP_KERNEL);
@@ -495,7 +495,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 		return dev_err_probe(dev, -ENODEV, "Missing platform ctrl ops\n");
 
 	hdmi->ctrl_ops = cfg->ctrl_ops;
-	hdmi->dev = &pdev->dev;
+	hdmi->dev = dev;
 	hdmi->port_id = -ENODEV;
 
 	/* Identify port ID by matching base IO address */
@@ -506,7 +506,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 		}
 	}
 	if (hdmi->port_id < 0)
-		return dev_err_probe(hdmi->dev, hdmi->port_id,
+		return dev_err_probe(dev, hdmi->port_id,
 				     "Failed to match HDMI port ID\n");
 
 	plat_data.phy_ops = cfg->phy_ops;
@@ -530,37 +530,36 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
 						       "rockchip,grf");
 	if (IS_ERR(hdmi->regmap))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->regmap),
+		return dev_err_probe(dev, PTR_ERR(hdmi->regmap),
 				     "Unable to get rockchip,grf\n");
 
 	hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
 							  "rockchip,vo-grf");
 	if (IS_ERR(hdmi->vo_regmap))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->vo_regmap),
+		return dev_err_probe(dev, PTR_ERR(hdmi->vo_regmap),
 				     "Unable to get rockchip,vo-grf\n");
 
-	ret = devm_clk_bulk_get_all_enabled(hdmi->dev, &clks);
+	ret = devm_clk_bulk_get_all_enabled(dev, &clks);
 	if (ret < 0)
-		return dev_err_probe(hdmi->dev, ret, "Failed to get clocks\n");
+		return dev_err_probe(dev, ret, "Failed to get clocks\n");
 
-	ref_clk = clk_get(hdmi->dev, "ref");
+	ref_clk = clk_get(dev, "ref");
 	if (IS_ERR(ref_clk))
-		return dev_err_probe(hdmi->dev, PTR_ERR(ref_clk),
+		return dev_err_probe(dev, PTR_ERR(ref_clk),
 				     "Failed to get ref clock\n");
 
 	plat_data.ref_clk_rate = clk_get_rate(ref_clk);
 	clk_put(ref_clk);
 
-	hdmi->frl_enable_gpio = devm_gpiod_get_optional(hdmi->dev, "frl-enable",
+	hdmi->frl_enable_gpio = devm_gpiod_get_optional(dev, "frl-enable",
 							GPIOD_OUT_LOW);
 	if (IS_ERR(hdmi->frl_enable_gpio))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->frl_enable_gpio),
+		return dev_err_probe(dev, PTR_ERR(hdmi->frl_enable_gpio),
 				     "Failed to request FRL enable GPIO\n");
 
 	hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0);
 	if (IS_ERR(hdmi->phy))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->phy),
-				     "Failed to get phy\n");
+		return dev_err_probe(dev, PTR_ERR(hdmi->phy), "Failed to get phy\n");
 
 	cfg->ctrl_ops->io_init(hdmi);
 
@@ -578,7 +577,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	if (irq < 0)
 		return irq;
 
-	ret = devm_request_threaded_irq(hdmi->dev, irq,
+	ret = devm_request_threaded_irq(dev, irq,
 					cfg->ctrl_ops->hardirq_callback,
 					cfg->ctrl_ops->irq_callback,
 					IRQF_SHARED, "dw-hdmi-qp-hpd",
@@ -589,18 +588,18 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
 	ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret)
-		return dev_err_probe(hdmi->dev, ret, "Failed to init encoder\n");
+		return dev_err_probe(dev, ret, "Failed to init encoder\n");
 
 	platform_set_drvdata(pdev, hdmi);
 
 	hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data);
 	if (IS_ERR(hdmi->hdmi))
-		return dev_err_probe(hdmi->dev, PTR_ERR(hdmi->hdmi),
+		return dev_err_probe(dev, PTR_ERR(hdmi->hdmi),
 				     "Failed to bind dw-hdmi-qp\n");
 
 	connector = drm_bridge_connector_init(drm, encoder);
 	if (IS_ERR(connector))
-		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
+		return dev_err_probe(dev, PTR_ERR(connector),
 				     "Failed to init bridge connector\n");
 
 	return 0;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:19 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:19 +0300
Subject: [PATCH v7 19/30] drm/rockchip: dw_hdmi_qp: Defer HPD IRQ enable
 until after connector setup
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-19-445eb54ee1ed@collabora.com>

Request the HPD IRQ early in bind() with IRQF_NO_AUTOEN, keeping it
disabled until all DRM resources are fully initialized, at which point
enable_irq() arms it.  This prevents premature interrupt delivery
without forcing devm_request_threaded_irq() to the very end of the
initialization sequence, which would complicate error unwinding.

Note that IRQF_NO_AUTOEN is incompatible with IRQF_SHARED; the latter is
dropped as this IRQ has no other users.

Suggested-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 8d64b76a1aa5..27342094958c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -579,7 +579,7 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	ret = devm_request_threaded_irq(dev, irq,
 					cfg->ctrl_ops->hardirq_callback,
 					cfg->ctrl_ops->irq_callback,
-					IRQF_SHARED, "dw-hdmi-qp-hpd",
+					IRQF_NO_AUTOEN, "dw-hdmi-qp-hpd",
 					hdmi);
 	if (ret)
 		return ret;
@@ -601,6 +601,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 		return dev_err_probe(dev, PTR_ERR(connector),
 				     "Failed to init bridge connector\n");
 
+	enable_irq(irq);
+
 	return 0;
 }
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:18 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:18 +0300
Subject: [PATCH v7 18/30] drm/rockchip: dw_hdmi_qp: Drop unnecessary
 #include
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-18-445eb54ee1ed@collabora.com>

Remove superfluous drm_simple_kms_helper.h include, which has no users
in this file since commit e1f7b7cbd74c ("drm/rockchip: dw_hdmi_qp:
Switch to drmm_encoder_init()").

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 46df5abe31a4..8d64b76a1aa5 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:20 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:20 +0300
Subject: [PATCH v7 20/30] drm/rockchip: dw_hdmi_qp: Mask HPD IRQ in
 rk3576_io_init()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-20-445eb54ee1ed@collabora.com>

Mask the RK3576 HPD interrupt in io_init() so it starts disabled,
matching the RK3588 behavior.  This prevents spurious interrupts before
the bridge framework enables HPD via the .hpd_enable() callback.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 27342094958c..62ea5c7cbbe6 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -346,7 +346,7 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
 
 	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
 
-	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
+	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
 }
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:22 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:22 +0300
Subject: [PATCH v7 22/30] drm/rockchip: dw_hdmi_qp: Switch to
 dw_hdmi_qp_hpd_notify()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-22-445eb54ee1ed@collabora.com>

Switch from drm_helper_hpd_irq_event(), which polls all connectors, to
the recently introduced dw_hdmi_qp_hpd_notify() helper, which runs the
detect cycle only on the affected connector.

This avoids unnecessary work and redundant detect calls on unrelated
connectors.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index b9e0ea56efd8..666631fc9162 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -23,7 +23,6 @@
 #include <drm/drm_bridge_connector.h>
 #include <drm/drm_managed.h>
 #include <drm/drm_of.h>
-#include <drm/drm_probe_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -273,14 +272,8 @@ 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;
 
-	if (drm) {
-		changed = drm_helper_hpd_irq_event(drm);
-		if (changed)
-			dev_dbg(hdmi->dev, "connector status changed\n");
-	}
+	dw_hdmi_qp_hpd_notify(hdmi->hdmi);
 }
 
 static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
@@ -645,8 +638,7 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
 
 	dw_hdmi_qp_resume(dev, hdmi->hdmi);
 
-	if (hdmi->encoder.encoder.dev)
-		drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev);
+	dw_hdmi_qp_hpd_notify(hdmi->hdmi);
 
 	return 0;
 }

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:21 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:21 +0300
Subject: [PATCH v7 21/30] drm/rockchip: dw_hdmi_qp: Implement
 .{enable|disable}_hpd() PHY ops
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-21-445eb54ee1ed@collabora.com>

Implement .enable_hpd() and .disable_hpd() phy ops for RK3576 and RK3588
SoCs, used by the corresponding bridge callbacks for HPD activation
control.

Consolidate the interrupt clear-and-unmask sequence into enable_hpd()
and the mask-only operation into disable_hpd(), replacing the open-coded
register writes in the interrupt handlers and io_init().

The .setup_hpd() phy op, which was previously called from
dw_hdmi_qp_init_hw(), is no longer needed and its users are removed.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 78 +++++++++++++-------------
 1 file changed, 38 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 62ea5c7cbbe6..b9e0ea56efd8 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -193,7 +193,7 @@ dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 	return val ? connector_status_connected : connector_status_disconnected;
 }
 
-static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3588_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 {
 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
 	u32 val;
@@ -208,11 +208,25 @@ static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
 }
 
+static void dw_hdmi_qp_rk3588_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+	u32 val;
+
+	if (hdmi->port_id)
+		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
+	else
+		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
+
+	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+}
+
 static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = {
 	.init		= dw_hdmi_qp_rk3588_phy_init,
 	.disable	= dw_hdmi_qp_rk3588_phy_disable,
 	.read_hpd	= dw_hdmi_qp_rk3588_read_hpd,
-	.setup_hpd	= dw_hdmi_qp_rk3588_setup_hpd,
+	.enable_hpd	= dw_hdmi_qp_rk3588_enable_hpd,
+	.disable_hpd	= dw_hdmi_qp_rk3588_disable_hpd,
 };
 
 static enum drm_connector_status
@@ -227,7 +241,7 @@ dw_hdmi_qp_rk3576_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 		connector_status_connected : connector_status_disconnected;
 }
 
-static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+static void dw_hdmi_qp_rk3576_enable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 {
 	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
 	u32 val;
@@ -236,14 +250,22 @@ static void dw_hdmi_qp_rk3576_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
 	       FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0));
 
 	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
-	regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+}
+
+static void dw_hdmi_qp_rk3576_disable_hpd(struct dw_hdmi_qp *dw_hdmi, void *data)
+{
+	struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data;
+
+	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0,
+		     FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1));
 }
 
 static const struct dw_hdmi_qp_phy_ops rk3576_hdmi_phy_ops = {
 	.init		= dw_hdmi_qp_rk3588_phy_init,
 	.disable	= dw_hdmi_qp_rk3588_phy_disable,
 	.read_hpd	= dw_hdmi_qp_rk3576_read_hpd,
-	.setup_hpd	= dw_hdmi_qp_rk3576_setup_hpd,
+	.enable_hpd	= dw_hdmi_qp_rk3576_enable_hpd,
+	.disable_hpd	= dw_hdmi_qp_rk3576_disable_hpd,
 };
 
 static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
@@ -264,13 +286,12 @@ static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work)
 static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_id;
-	u32 intr_stat, val;
+	u32 intr_stat;
 
 	regmap_read(hdmi->regmap, RK3576_IOC_HDMI_HPD_STATUS, &intr_stat);
-	if (intr_stat) {
-		val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
 
-		regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+	if (intr_stat) {
+		dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
 		return IRQ_WAKE_THREAD;
 	}
 
@@ -280,15 +301,11 @@ static irqreturn_t dw_hdmi_qp_rk3576_hardirq(int irq, void *dev_id)
 static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_id;
-	u32 val;
 
-	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_CLR, 1);
-	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
 	mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
 			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
 
-	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 0);
-	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+	dw_hdmi_qp_rk3576_enable_hpd(NULL, hdmi);
 
 	return IRQ_HANDLED;
 }
@@ -296,16 +313,12 @@ static irqreturn_t dw_hdmi_qp_rk3576_irq(int irq, void *dev_id)
 static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_id;
-	u32 intr_stat, val;
+	u32 intr_stat;
 
 	regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat);
 
 	if (intr_stat) {
-		if (hdmi->port_id)
-			val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
-		else
-			val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
-		regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+		dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
 		return IRQ_WAKE_THREAD;
 	}
 
@@ -315,22 +328,11 @@ static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id)
 static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id)
 {
 	struct rockchip_hdmi_qp *hdmi = dev_id;
-	u32 val;
-
-	if (hdmi->port_id)
-		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_CLR, 1);
-	else
-		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_CLR, 1);
-	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
 
 	mod_delayed_work(system_percpu_wq, &hdmi->hpd_work,
 			 msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
 
-	if (hdmi->port_id)
-		val |= FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 0);
-	else
-		val |= FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 0);
-	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+	dw_hdmi_qp_rk3588_enable_hpd(NULL, hdmi);
 
 	return IRQ_HANDLED;
 }
@@ -343,11 +345,11 @@ static void dw_hdmi_qp_rk3576_io_init(struct rockchip_hdmi_qp *hdmi)
 	      FIELD_PREP_WM16(RK3576_SDAIN_MASK, 1) |
 	      FIELD_PREP_WM16(RK3576_HDMI_GRANT_SEL, 1) |
 	      FIELD_PREP_WM16(RK3576_I2S_SEL_MASK, 1);
-
 	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON14, val);
 
-	val = FIELD_PREP_WM16(RK3576_HDMI_HPD_INT_MSK, 1);
-	regmap_write(hdmi->regmap, RK3576_IOC_MISC_CON0, val);
+	regmap_write(hdmi->regmap, 0xa404, 0xffff0102);
+
+	dw_hdmi_qp_rk3576_disable_hpd(NULL, hdmi);
 }
 
 static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
@@ -372,11 +374,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
 		val = FIELD_PREP_WM16(RK3588_HDMI0_GRANT_SEL, 1);
 	regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val);
 
-	if (hdmi->port_id)
-		val = FIELD_PREP_WM16(RK3588_HDMI1_HPD_INT_MSK, 1);
-	else
-		val = FIELD_PREP_WM16(RK3588_HDMI0_HPD_INT_MSK, 1);
-	regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val);
+	dw_hdmi_qp_rk3588_disable_hpd(NULL, hdmi);
 }
 
 static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:23 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:23 +0300
Subject: [PATCH v7 23/30] drm/bridge: dw-hdmi-qp: Remove obsolete
 .setup_hpd() phy op
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-23-445eb54ee1ed@collabora.com>

With the transition to .{enable|disable}_hpd() phy ops complete in both
the bridge and platform drivers, .setup_hpd() has no remaining callers.
Drop it.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 3 ---
 include/drm/bridge/dw_hdmi_qp.h              | 1 -
 2 files changed, 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 999229705ffb..3cb06fe43087 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1318,9 +1318,6 @@ static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi)
 	/* Clear DONE and ERROR interrupts */
 	dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR,
 			 MAINUNIT_1_INT_CLEAR);
-
-	if (hdmi->phy.ops->setup_hpd)
-		hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
 }
 
 struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h
index b4fb1c578a5b..ad33f9cafdeb 100644
--- a/include/drm/bridge/dw_hdmi_qp.h
+++ b/include/drm/bridge/dw_hdmi_qp.h
@@ -16,7 +16,6 @@ struct dw_hdmi_qp_phy_ops {
 	int (*init)(struct dw_hdmi_qp *hdmi, void *data);
 	void (*disable)(struct dw_hdmi_qp *hdmi, void *data);
 	enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data);
-	void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data);
 	void (*enable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
 	void (*disable_hpd)(struct dw_hdmi_qp *hdmi, void *data);
 };

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:24 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:24 +0300
Subject: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate
 constants
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-24-445eb54ee1ed@collabora.com>

Replace HDMI_14_MAX_TMDS_CLK defined locally with
HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h.  Note this
incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
rate was actually introduced in HDMI 1.3.

Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
magic number.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 74dce4be0c00..046ac4f43ba8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -45,6 +45,7 @@
 #include <linux/clk.h>
 #include <linux/component.h>
 #include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
 #include <linux/i2c.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -113,8 +114,6 @@
 #define HSM_MIN_CLOCK_FREQ	120000000
 #define CEC_CLOCK_FREQ 40000
 
-#define HDMI_14_MAX_TMDS_CLK   (340 * 1000 * 1000)
-
 static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
 {
 	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
@@ -137,7 +136,7 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
 {
 	unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
 
-	return clock > HDMI_14_MAX_TMDS_CLK;
+	return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
 }
 
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
@@ -1727,7 +1726,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
 	if (clock > vc4_hdmi->variant->max_pixel_clock)
 		return MODE_CLOCK_HIGH;
 
-	if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+	if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
 		return MODE_CLOCK_HIGH;
 
 	/* 4096x2160 at 60 is not reliable without overclocking core */
@@ -3253,7 +3252,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
 	 * vc4_hdmi_disable_scrambling() will thus run at boot, make
 	 * sure it's disabled, and avoid any inconsistency.
 	 */
-	if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+	if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
 		vc4_hdmi->scdc_enabled = true;
 
 	ret = variant->init_resources(drm, vc4_hdmi);
@@ -3383,7 +3382,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI0,
 	.debugfs_name		= "hdmi0_regs",
 	.card_name		= "vc4-hdmi-0",
-	.max_pixel_clock	= 600000000,
+	.max_pixel_clock	= HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
 	.registers		= vc5_hdmi_hdmi0_fields,
 	.num_registers		= ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
 	.phy_lane_mapping	= {
@@ -3412,7 +3411,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI1,
 	.debugfs_name		= "hdmi1_regs",
 	.card_name		= "vc4-hdmi-1",
-	.max_pixel_clock	= HDMI_14_MAX_TMDS_CLK,
+	.max_pixel_clock	= HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
 	.registers		= vc5_hdmi_hdmi1_fields,
 	.num_registers		= ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
 	.phy_lane_mapping	= {
@@ -3441,7 +3440,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI0,
 	.debugfs_name		= "hdmi0_regs",
 	.card_name		= "vc4-hdmi-0",
-	.max_pixel_clock	= 600000000,
+	.max_pixel_clock	= HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
 	.registers		= vc6_hdmi_hdmi0_fields,
 	.num_registers		= ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
 	.phy_lane_mapping	= {
@@ -3468,7 +3467,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
 	.encoder_type		= VC4_ENCODER_TYPE_HDMI1,
 	.debugfs_name		= "hdmi1_regs",
 	.card_name		= "vc4-hdmi-1",
-	.max_pixel_clock	= 600000000,
+	.max_pixel_clock	= HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
 	.registers		= vc6_hdmi_hdmi1_fields,
 	.num_registers		= ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
 	.phy_lane_mapping	= {

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:27 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:27 +0300
Subject: [PATCH v7 27/30] drm/tests: edid: Add 4K@60Hz EDID with 600MHz
 TMDS
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-27-445eb54ee1ed@collabora.com>

Add a new test EDID advertising the following capabilities:

Max resolution: 3840x2160 at 60Hz with RGB, YUV444, YUV422, YUV420
Max BPC:        16
Max TMDS clock: 600 MHz

This is needed to exercise the new HDMI infrastructure that decides
whether scrambling needs to be enabled for a given display mode and
to validate that high-rate modes are properly rejected/accepted
depending on the source/sink scrambling capability.

The EDID is derived from test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz
with the following changes:

- Upgraded the first DTD from 3840x2160 at 30 (297 MHz) to 3840x2160 at 60
  (594 MHz).  The H/V totals (4400x2250) and porches already match the
  HDMI 2.0 4K at 60Hz standard timing, so only the pixel clock had to be
  bumped.
- Widened Display Range Limits descriptor to cover the new timing, i.e.
  24-140 kHz H, max dotclock 600 MHz.
- Updated CTA-861 Video Data Block to advertise VIC 97 (4K at 60Hz) instead
  of VIC 95 (4k30).
- Bumped HF-VSDB Max TMDS Character Rate to 600 MHz, keeping
  SCDC_Present set so that the sink advertises scrambling support.
- Cleared HDMI VSDB Max TMDS clock byte, as required by HDMI 2.0 when
  the HF-VSDB declares a Max TMDS Character Rate above 340 MHz.
- Provided a Video Capability Data Block advertising selectable RGB and
  YCC quantization range plus underscan for IT/CE formats; also set the
  'IT Video Formats Underscanned' bit in the CTA-861 extension header to
  match.
- Aligned base block image size with the DTD (160x90 cm) and replaced
  the bogus 'Week of Manufacture = 0xff' with the Model Year code, both
  fixing inherited EDID conformity warnings.
- Dropped the empty YCbCr 4:2:0 Video Data Block inherited from the
  parent EDID, which is flagged as a failure by edid-decode v1.33.0

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/tests/drm_kunit_edid.h | 128 +++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index f4923157f5bf..9b318f7d364e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -980,4 +980,132 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
 	0x00, 0x00, 0x00, 0x84
 };
 
+/*
+ * Max resolution: 3840x2160 at 60Hz with RGB, YUV444, YUV422, YUV420
+ * Max BPC:        16 for all modes
+ * Max TMDS clock: 600 MHz
+ *
+ * edid-decode (hex):
+ *
+ * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
+ * 00 23 01 03 80 a0 5a 78 0f ee 91 a3 54 4c 99 26
+ * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
+ * 01 01 01 01 01 01 08 e8 00 30 f2 70 5a 80 b0 58
+ * 8a 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 18
+ * 55 18 8c 3c 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 a9
+ *
+ * 02 03 28 b1 41 61 6c 03 0c 00 10 00 78 00 20 00
+ * 00 01 03 6d d8 5d c4 01 78 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 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 54
+ *
+ * ----------------
+ *
+ * Block 0, Base EDID:
+ *   EDID Structure Version & Revision: 1.3
+ *   Vendor & Product Identification:
+ *     Manufacturer: LNX
+ *     Model: 52
+ *     Made in: 2025
+ *   Basic Display Parameters & Features:
+ *     Digital display
+ *     Maximum image size: 160 cm x 90 cm
+ *     Gamma: 2.20
+ *     RGB color display
+ *     Default (sRGB) color space is primary color space
+ *     First detailed timing is the preferred timing
+ *     Supports GTF timings within operating range
+ *   Color Characteristics:
+ *     Red  : 0.6396, 0.3300
+ *     Green: 0.2998, 0.5996
+ *     Blue : 0.1503, 0.0595
+ *     White: 0.3125, 0.3291
+ *   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:  3840x2160   60.000000 Hz  16:9    135.000 kHz    594.000000 MHz (1600 mm x 900 mm)
+ *                  Hfront  176 Hsync  88 Hback  296 Hpol P
+ *                  Vfront    8 Vsync  10 Vback   72 Vpol P
+ *     Display Product Name: 'Test EDID'
+ *     Display Range Limits:
+ *       Monitor ranges (GTF): 24-85 Hz V, 24-140 kHz H, max dotclock 600 MHz
+ *     Dummy Descriptor:
+ *   Extension blocks: 1
+ * Checksum: 0xa9
+ *
+ * ----------------
+ *
+ * Block 1, CTA-861 Extension Block:
+ *   Revision: 3
+ *   Underscans IT Video Formats by default
+ *   Supports YCbCr 4:4:4
+ *   Supports YCbCr 4:2:2
+ *   Native detailed modes: 1
+ *   Video Data Block:
+ *     VIC  97:  3840x2160   60.000000 Hz  16:9    135.000 kHz    594.000000 MHz
+ *   Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
+ *     Source physical address: 1.0.0.0
+ *     DC_48bit
+ *     DC_36bit
+ *     DC_30bit
+ *     DC_Y444
+ *     Maximum TMDS clock: 0 MHz
+ *     Extended HDMI video details:
+ *   Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
+ *     Version: 1
+ *     Maximum TMDS Character Rate: 600 MHz
+ *     SCDC Present
+ *     Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
+ *     Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
+ *     Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ *     VRRmin: 0 Hz
+ *     VRRmax: 0 Hz
+ *   Video Capability Data Block:
+ *     YCbCr quantization: Selectable (via AVI YQ)
+ *     RGB quantization: Selectable (via AVI Q)
+ *     PT scan behavior: No Data
+ *     IT scan behavior: Always Underscanned
+ *     CE scan behavior: Always Underscanned
+ *   YCbCr 4:2:0 Capability Map Data Block:
+ *     VIC  97:  3840x2160   60.000000 Hz  16:9    135.000 kHz    594.000000 MHz
+ * Checksum: 0x54  Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * EDID conformity: PASS
+ */
+static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz[] = {
+	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0xa0, 0x5a, 0x78,
+	0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
+	0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xe8, 0x00, 0x30, 0xf2, 0x70,
+	0x5a, 0x80, 0xb0, 0x58, 0x8a, 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, 0x18,
+	0x55, 0x18, 0x8c, 0x3c, 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, 0xa9, 0x02, 0x03, 0x28, 0xb1,
+	0x41, 0x61, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x00, 0x20, 0x00,
+	0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x78, 0x80, 0x07, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 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, 0x54,
+};
+
 #endif // DRM_KUNIT_EDID_H_

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:26 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:26 +0300
Subject: [PATCH v7 26/30] drm/tests: connector: Add HDMI source-side
 scrambler capability tests
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-26-445eb54ee1ed@collabora.com>

Add KUnit tests covering the consistency validation between HDMI
connector's scrambler_supported flag and the .scrambler_{enable,disable}
HDMI connector callbacks that drmm_connector_hdmi_init() performs.

The four added cases cover the validation matrix:

- scrambler_supported = true with both callbacks set: success
- scrambler_supported = true with no callbacks: failure
- scrambler_supported = true with only one callback: failure
- scrambler_supported = false with both callbacks: success (callbacks
                        ignored)

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/tests/drm_connector_test.c | 132 +++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_connector_test.c b/drivers/gpu/drm/tests/drm_connector_test.c
index beb1d50a6646..b79b75be18c4 100644
--- a/drivers/gpu/drm/tests/drm_connector_test.c
+++ b/drivers/gpu/drm/tests/drm_connector_test.c
@@ -47,6 +47,41 @@ static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs = {
 	},
 };
 
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static const struct drm_connector_hdmi_funcs dummy_hdmi_funcs_scrambler = {
+	.scrambler_enable = accept_scrambler_enable,
+	.scrambler_disable = accept_scrambler_disable,
+	.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_hdmi_funcs dummy_hdmi_funcs_scrambler_partial = {
+	.scrambler_enable = accept_scrambler_enable,
+	.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 = {
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
@@ -1254,6 +1289,99 @@ KUNIT_ARRAY_PARAM(drm_connector_hdmi_init_type_invalid,
 		  drm_connector_hdmi_init_type_invalid_tests,
 		  drm_connector_hdmi_init_type_desc);
 
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support succeeds when the .scrambler_{enable|disable} callbacks
+ * are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_valid(struct kunit *test)
+{
+	struct drm_connector_init_priv *priv = test->priv;
+	int ret;
+
+	priv->connector.hdmi.scrambler_supported = true;
+
+	ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+				       "Vendor", "Product",
+				       &dummy_funcs,
+				       &dummy_hdmi_funcs_scrambler,
+				       DRM_MODE_CONNECTOR_HDMIA,
+				       &priv->ddc,
+				       BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				       8);
+	KUNIT_EXPECT_EQ(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when the .scrambler_{enable|disable} callbacks
+ * are not provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_no_callbacks(struct kunit *test)
+{
+	struct drm_connector_init_priv *priv = test->priv;
+	int ret;
+
+	priv->connector.hdmi.scrambler_supported = true;
+
+	ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+				       "Vendor", "Product",
+				       &dummy_funcs,
+				       &dummy_hdmi_funcs,
+				       DRM_MODE_CONNECTOR_HDMIA,
+				       &priv->ddc,
+				       BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				       8);
+	KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector advertising source-side
+ * scrambling support fails when only one of the .scrambler_{enable|disable}
+ * callbacks are provided.
+ */
+static void drm_test_connector_hdmi_init_scrambler_partial_callbacks(struct kunit *test)
+{
+	struct drm_connector_init_priv *priv = test->priv;
+	int ret;
+
+	priv->connector.hdmi.scrambler_supported = true;
+
+	ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+				       "Vendor", "Product",
+				       &dummy_funcs,
+				       &dummy_hdmi_funcs_scrambler_partial,
+				       DRM_MODE_CONNECTOR_HDMIA,
+				       &priv->ddc,
+				       BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				       8);
+	KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+/*
+ * Test that the registration of an HDMI connector not advertising source-side
+ * scrambling support succeeds, even when the .scrambler_{enable|disable}
+ * callbacks are provided, i.e. they are ignored.
+ */
+static void drm_test_connector_hdmi_init_scrambler_ignored_callbacks(struct kunit *test)
+{
+	struct drm_connector_init_priv *priv = test->priv;
+	int ret;
+
+	priv->connector.hdmi.scrambler_supported = false;
+
+	ret = drmm_connector_hdmi_init(&priv->drm, &priv->connector,
+				       "Vendor", "Product",
+				       &dummy_funcs,
+				       &dummy_hdmi_funcs_scrambler,
+				       DRM_MODE_CONNECTOR_HDMIA,
+				       &priv->ddc,
+				       BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				       8);
+	KUNIT_EXPECT_EQ(test, ret, 0);
+	KUNIT_EXPECT_EQ(test, priv->connector.hdmi.scrambler_supported, false);
+}
+
 static struct kunit_case drmm_connector_hdmi_init_tests[] = {
 	KUNIT_CASE(drm_test_connector_hdmi_init_valid),
 	KUNIT_CASE(drm_test_connector_hdmi_init_bpc_8),
@@ -1278,6 +1406,10 @@ static struct kunit_case drmm_connector_hdmi_init_tests[] = {
 			 drm_connector_hdmi_init_type_valid_gen_params),
 	KUNIT_CASE_PARAM(drm_test_connector_hdmi_init_type_invalid,
 			 drm_connector_hdmi_init_type_invalid_gen_params),
+	KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_valid),
+	KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_no_callbacks),
+	KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_partial_callbacks),
+	KUNIT_CASE(drm_test_connector_hdmi_init_scrambler_ignored_callbacks),
 	{ }
 };
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:30 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:30 +0300
Subject: [PATCH v7 30/30] drm/tests: edid: Fix conformity for 4K RGB/YUV
 340MHz EDID
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-30-445eb54ee1ed@collabora.com>

The test EDID added by commit 54a5f1c4d5f8 ("drm/tests: hdmi: Provide
EDID supporting 4K at 30Hz with RGB/YUV") fails 'edid-decode --check'
(v1.33.0) with the following issues:

  Warnings:

  Block 1, CTA-861 Extension Block:
    IT Video Formats are overscanned by default, but normally this should be underscanned.
    YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
      (which requires an RGB timings pixel rate >= 590 MHz).

  Failures:

  Block 0, Base EDID:
    Vendor & Product Identification: EDID 1.3 does not support week 0xff.
    Detailed Timing Descriptor #1: Mismatch of image size 1600x900 mm vs display size 960x540 mm.
  Block 1, CTA-861 Extension Block:
    Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
    YCbCr 4:2:0 Video Data Block: This Data Block is empty.
    Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
  EDID:
    Base EDID: The DTD max image size is 1600x900mm, which is larger than the display size 960.0x540.0mm.

Address them while preserving the advertised maximum resolution, BPC and
TMDS clock used by the existing KUnit tests:

- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
  year field becomes a regular Year of Manufacture.
- Align the DTD image size with the Basic Display Parameters maximum
  image size (96 cm x 54 cm).
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
  above 340 MHz is supported.  The HDMI VSDB still advertises 340 MHz as
  Max TMDS Clock.
- Drop the empty YCbCr 4:2:0 Video Data Block.  VIC 95 (3840x2160 at 30Hz)
  remains advertised as YUV420-capable via the YCbCr 4:2:0 Capability
  Map Data Block, which references the corresponding entry in the
  regular Video Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
  quantization range plus underscan for IT/CE formats; also set the 'IT
  Video Formats Underscanned' bit in the CTA-861 extension header to
  match.

The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/tests/drm_kunit_edid.h | 57 ++++++++++++++++++++++------------
 1 file changed, 38 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 618b42d2fd8e..9a326c9e3f7b 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -891,22 +891,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
  * edid-decode (hex):
  *
  * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
  * 0f 50 54 20 00 00 01 01 01 01 01 01 01 01 01 01
  * 01 01 01 01 01 01 04 74 00 30 f2 70 5a 80 b0 58
- * 8a 00 40 84 63 00 00 1e 00 00 00 fc 00 54 65 73
+ * 8a 00 c0 1c 32 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 18
  * 55 18 5e 22 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 ce
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 e6
  *
- * 02 03 27 31 41 5f 6c 03 0c 00 10 00 78 44 20 00
- * 00 01 03 6d d8 5d c4 01 44 80 07 00 00 00 00 00
- * 00 e3 0f 01 00 e1 0e 00 00 00 00 00 00 00 00 00
+ * 02 03 28 b1 41 5f 6c 03 0c 00 10 00 78 44 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e3 0f 01 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 84
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8a
  *
  * ----------------
  *
@@ -915,7 +915,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
  *   Vendor & Product Identification:
  *     Manufacturer: LNX
  *     Model: 52
- *     Model year: 2025
+ *     Made in: 2025
  *   Basic Display Parameters & Features:
  *     Digital display
  *     Maximum image size: 96 cm x 54 cm
@@ -933,7 +933,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
  *     DMT 0x04:   640x480    59.940476 Hz   4:3     31.469 kHz     25.175000 MHz
  *   Standard Timings: none
  *   Detailed Timing Descriptors:
- *     DTD 1:  3840x2160   30.000000 Hz  16:9     67.500 kHz    297.000000 MHz (1600 mm x 900 mm)
+ *     DTD 1:  3840x2160   30.000000 Hz  16:9     67.500 kHz    297.000000 MHz (960 mm x 540 mm)
  *                  Hfront  176 Hsync  88 Hback  296 Hpol P
  *                  Vfront    8 Vsync  10 Vback   72 Vpol P
  *     Display Product Name: 'Test EDID'
@@ -941,12 +941,13 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
  *       Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 340 MHz
  *     Dummy Descriptor:
  *   Extension blocks: 1
- * Checksum: 0xce
+ * Checksum: 0xe6
  *
  * ----------------
  *
  * Block 1, CTA-861 Extension Block:
  *   Revision: 3
+ *   Underscans IT Video Formats by default
  *   Supports YCbCr 4:4:4
  *   Supports YCbCr 4:2:2
  *   Native detailed modes: 1
@@ -962,31 +963,49 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[
  *     Extended HDMI video details:
  *   Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
  *     Version: 1
- *     Maximum TMDS Character Rate: 340 MHz
  *     SCDC Present
  *     Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
  *     Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
  *     Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
+ *     VRRmin: 0 Hz
+ *     VRRmax: 0 Hz
+ *   Video Capability Data Block:
+ *     YCbCr quantization: Selectable (via AVI YQ)
+ *     RGB quantization: Selectable (via AVI Q)
+ *     PT scan behavior: No Data
+ *     IT scan behavior: Always Underscanned
+ *     CE scan behavior: Always Underscanned
  *   YCbCr 4:2:0 Capability Map Data Block:
  *     VIC  95:  3840x2160   30.000000 Hz  16:9     67.500 kHz    297.000000 MHz
- *   YCbCr 4:2:0 Video Data Block:
- * Checksum: 0x84
+ * Checksum: 0x8a  Unused space in Extension Block: 87 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ *   YCbCr 4:2:0 Capability Map Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ *     (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
  */
 static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
 	0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0x20,
 	0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x74, 0x00, 0x30, 0xf2, 0x70,
-	0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0x40, 0x84, 0x63, 0x00, 0x00, 0x1e,
+	0x5a, 0x80, 0xb0, 0x58, 0x8a, 0x00, 0xc0, 0x1c, 0x32, 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, 0x18,
 	0x55, 0x18, 0x5e, 0x22, 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, 0xce, 0x02, 0x03, 0x27, 0x31,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe6, 0x02, 0x03, 0x28, 0xb1,
 	0x41, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x44, 0x20, 0x00,
-	0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x44, 0x80, 0x07, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x01, 0x00, 0xe1, 0x0e, 0x00,
+	0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x0f, 0x01, 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,
@@ -994,7 +1013,7 @@ static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
 	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, 0x84
+	0x00, 0x00, 0x00, 0x8a,
 };
 
 /*

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:25 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:25 +0300
Subject: [PATCH v7 25/30] drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC
 scrambling helpers
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-25-445eb54ee1ed@collabora.com>

Replace the vc4-local scrambling implementation with the newly
introduced DRM common SCDC scrambling infrastructure:

- Advertise source-side scrambling support by setting
  connector->hdmi.scrambling_supported based on the variant's
  max_pixel_clock before drmm_connector_hdmi_init().

- Provide minimal .scrambler_{enable|disable} connector callbacks that
  only toggle the VC5 HDMI_SCRAMBLER_CTL register.  Sink-side SCDC
  programming and periodic status monitoring are now delegated to
  drm_scdc_{start|stop}_scrambling().

- Replace vc4_hdmi_enable_scrambling() with a conditional call to
  drm_scdc_start_scrambling() in post_crtc_enable, gated on
  conn_state->hdmi.scrambler_needed (computed by the HDMI state helper).

- Replace vc4_hdmi_disable_scrambling() with drm_scdc_stop_scrambling()
  in post_crtc_disable.

- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
  the .detect_ctx() path to
  drm_atomic_helper_connector_hdmi_hotplug_ctx() which internally calls
  drm_scdc_sync_status() to trigger a CRTC reset on reconnection.

- Drop the local scrambling_work delayed workqueue and scdc_enabled
  flag, now tracked by the common drm_connector_hdmi layer.

- Drop vc4_hdmi_supports_scrambling() and
  vc4_hdmi_mode_needs_scrambling() helpers, inlining the remaining 4KP60
  warning with an explicit drm_hdmi_compute_mode_clock() check.

- Seed connector->hdmi.scrambler_enabled = true in connector_init() to
  ensure drm_scdc_stop_scrambling() runs at boot and disables any stale
  scrambling state left by the bootloader.

No functional change is expected for the supported modes.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 265 ++++++-----------------------------------
 drivers/gpu/drm/vc4/vc4_hdmi.h |   8 --
 2 files changed, 35 insertions(+), 238 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 046ac4f43ba8..02f6ca6ab52b 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -114,31 +114,6 @@
 #define HSM_MIN_CLOCK_FREQ	120000000
 #define CEC_CLOCK_FREQ 40000
 
-static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
-{
-	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
-	lockdep_assert_held(&vc4_hdmi->mutex);
-
-	if (!display->is_hdmi)
-		return false;
-
-	if (!display->hdmi.scdc.supported ||
-	    !display->hdmi.scdc.scrambling.supported)
-		return false;
-
-	return true;
-}
-
-static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
-					   unsigned int bpc,
-					   enum drm_output_color_format fmt)
-{
-	unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
-
-	return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
-}
-
 static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
 {
 	struct drm_debugfs_entry *entry = m->private;
@@ -272,124 +247,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
 static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
 #endif
 
-static int vc4_hdmi_reset_link(struct drm_connector *connector,
-			       struct drm_modeset_acquire_ctx *ctx)
-{
-	struct drm_device *drm;
-	struct vc4_hdmi *vc4_hdmi;
-	struct drm_connector_state *conn_state;
-	struct drm_crtc_state *crtc_state;
-	struct drm_crtc *crtc;
-	bool scrambling_needed;
-	u8 config;
-	int ret;
-
-	if (!connector)
-		return 0;
-
-	drm = connector->dev;
-	ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
-	if (ret)
-		return ret;
-
-	conn_state = connector->state;
-	crtc = conn_state->crtc;
-	if (!crtc)
-		return 0;
-
-	ret = drm_modeset_lock(&crtc->mutex, ctx);
-	if (ret)
-		return ret;
-
-	crtc_state = crtc->state;
-	if (!crtc_state->active)
-		return 0;
-
-	vc4_hdmi = connector_to_vc4_hdmi(connector);
-	mutex_lock(&vc4_hdmi->mutex);
-
-	if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
-		mutex_unlock(&vc4_hdmi->mutex);
-		return 0;
-	}
-
-	scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
-							   vc4_hdmi->output_bpc,
-							   vc4_hdmi->output_format);
-	if (!scrambling_needed) {
-		mutex_unlock(&vc4_hdmi->mutex);
-		return 0;
-	}
-
-	if (conn_state->commit &&
-	    !try_wait_for_completion(&conn_state->commit->hw_done)) {
-		mutex_unlock(&vc4_hdmi->mutex);
-		return 0;
-	}
-
-	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
-	if (ret < 0) {
-		drm_err(drm, "Failed to read TMDS config: %d\n", ret);
-		mutex_unlock(&vc4_hdmi->mutex);
-		return 0;
-	}
-
-	if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
-		mutex_unlock(&vc4_hdmi->mutex);
-		return 0;
-	}
-
-	mutex_unlock(&vc4_hdmi->mutex);
-
-	/*
-	 * HDMI 2.0 says that one should not send scrambled data
-	 * prior to configuring the sink scrambling, and that
-	 * TMDS clock/data transmission should be suspended when
-	 * changing the TMDS clock rate in the sink. So let's
-	 * just do a full modeset here, even though some sinks
-	 * would be perfectly happy if were to just reconfigure
-	 * the SCDC settings on the fly.
-	 */
-	return drm_atomic_helper_reset_crtc(crtc, ctx);
-}
-
-static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
-				    struct drm_modeset_acquire_ctx *ctx,
-				    enum drm_connector_status status)
-{
-	struct drm_connector *connector = &vc4_hdmi->connector;
-	int ret;
-
-	/*
-	 * NOTE: This function should really be called with vc4_hdmi->mutex
-	 * held, but doing so results in reentrancy issues since
-	 * cec_s_phys_addr() might call .adap_enable, which leads to that
-	 * funtion being called with our mutex held.
-	 *
-	 * A similar situation occurs with vc4_hdmi_reset_link() that
-	 * will call into our KMS hooks if the scrambling was enabled.
-	 *
-	 * Concurrency isn't an issue at the moment since we don't share
-	 * any state with any of the other frameworks so we can ignore
-	 * the lock for now.
-	 */
-
-	drm_atomic_helper_connector_hdmi_hotplug(connector, status);
-
-	if (status != connector_status_connected)
-		return;
-
-	for (;;) {
-		ret = vc4_hdmi_reset_link(connector, ctx);
-		if (ret == -EDEADLK) {
-			drm_modeset_backoff(ctx);
-			continue;
-		}
-
-		break;
-	}
-}
-
 static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
 					 struct drm_modeset_acquire_ctx *ctx,
 					 bool force)
@@ -401,8 +258,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
 	/*
 	 * NOTE: This function should really take vc4_hdmi->mutex, but
 	 * doing so results in reentrancy issues since
-	 * vc4_hdmi_handle_hotplug() can call into other functions that
-	 * would take the mutex while it's held here.
+	 * drm_atomic_helper_connector_hdmi_hotplug_ctx() can call into other
+	 * functions that would take the mutex while it's held here.
 	 *
 	 * Concurrency isn't an issue at the moment since we don't share
 	 * any state with any of the other frameworks so we can ignore
@@ -425,10 +282,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
 			status = connector_status_connected;
 	}
 
-	vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+	ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector, status, ctx);
+
 	pm_runtime_put(&vc4_hdmi->pdev->dev);
 
-	return status;
+	return ret == -EDEADLK ? ret : status;
 }
 
 static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -441,9 +299,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
 	if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
 		struct drm_device *drm = connector->dev;
 		const struct drm_display_mode *mode;
+		unsigned long long clock;
 
 		list_for_each_entry(mode, &connector->probed_modes, head) {
-			if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+			clock = drm_hdmi_compute_mode_clock(mode, 8,
+							    DRM_OUTPUT_COLOR_FORMAT_RGB444);
+			if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
 				drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
 				drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
 			}
@@ -540,6 +401,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
 	if (vc4_hdmi->variant->supports_hdr)
 		max_bpc = 12;
 
+	connector->hdmi.scrambler_supported =
+		vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
+
 	ret = drmm_connector_hdmi_init(dev, connector,
 				       "Broadcom", "Videocore",
 				       &vc4_hdmi_connector_funcs,
@@ -561,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
 
 	drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
 
+	/*
+	 * Since we don't know the state of the controller and its
+	 * display (if any), let's assume it's always enabled.
+	 * drm_scdc_stop_scrambling() will thus run at boot, make
+	 * sure it's disabled, and avoid any inconsistency.
+	 */
+	connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
+
 	/*
 	 * Some of the properties below require access to state, like bpc.
 	 * Allocate some default initial connector state with our reset helper.
@@ -786,93 +658,30 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
 					buffer, len);
 }
 
-#define SCRAMBLING_POLLING_DELAY_MS	1000
-
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
 {
-	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
-	struct drm_connector *connector = &vc4_hdmi->connector;
-	struct drm_device *drm = connector->dev;
-	const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
+	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
 	unsigned long flags;
-	int idx;
-
-	lockdep_assert_held(&vc4_hdmi->mutex);
-
-	if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
-		return;
-
-	if (!vc4_hdmi_mode_needs_scrambling(mode,
-					    vc4_hdmi->output_bpc,
-					    vc4_hdmi->output_format))
-		return;
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
-
-	drm_scdc_set_high_tmds_clock_ratio(connector, true);
-	drm_scdc_set_scrambling(connector, true);
 
 	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
 		   VC5_HDMI_SCRAMBLER_CTL_ENABLE);
 	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 
-	drm_dev_exit(idx);
-
-	vc4_hdmi->scdc_enabled = true;
-
-	queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
-			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+	return 0;
 }
 
-static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
 {
-	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
-	struct drm_connector *connector = &vc4_hdmi->connector;
-	struct drm_device *drm = connector->dev;
+	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
 	unsigned long flags;
-	int idx;
-
-	lockdep_assert_held(&vc4_hdmi->mutex);
-
-	if (!vc4_hdmi->scdc_enabled)
-		return;
-
-	vc4_hdmi->scdc_enabled = false;
-
-	if (delayed_work_pending(&vc4_hdmi->scrambling_work))
-		cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
 
 	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
 	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
 		   ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
 	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 
-	drm_scdc_set_scrambling(connector, false);
-	drm_scdc_set_high_tmds_clock_ratio(connector, false);
-
-	drm_dev_exit(idx);
-}
-
-static void vc4_hdmi_scrambling_wq(struct work_struct *work)
-{
-	struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
-						 struct vc4_hdmi,
-						 scrambling_work);
-	struct drm_connector *connector = &vc4_hdmi->connector;
-
-	if (drm_scdc_get_scrambling_status(connector))
-		return;
-
-	drm_scdc_set_high_tmds_clock_ratio(connector, true);
-	drm_scdc_set_scrambling(connector, true);
-
-	queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
-			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+	return 0;
 }
 
 static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -917,7 +726,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
 		spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
 	}
 
-	vc4_hdmi_disable_scrambling(encoder);
+	drm_scdc_stop_scrambling(&vc4_hdmi->connector);
 
 	drm_dev_exit(idx);
 
@@ -1625,6 +1434,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
 	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
 	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
 	bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+	struct drm_connector_state *conn_state;
 	unsigned long flags;
 	int ret;
 	int idx;
@@ -1693,7 +1503,10 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
 	}
 
 	vc4_hdmi_recenter_fifo(vc4_hdmi);
-	vc4_hdmi_enable_scrambling(encoder);
+
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	if (conn_state && conn_state->hdmi.scrambler_needed)
+		drm_scdc_start_scrambling(connector);
 
 	drm_dev_exit(idx);
 
@@ -1739,7 +1552,9 @@ 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,
+	.tmds_char_rate_valid	 = vc4_hdmi_connector_clock_valid,
+	.scrambler_enable	 = vc4_hdmi_scrambler_enable,
+	.scrambler_disable	 = vc4_hdmi_scrambler_disable,
 	.avi = {
 		.clear_infoframe = vc4_hdmi_clear_avi_infoframe,
 		.write_infoframe = vc4_hdmi_write_avi_infoframe,
@@ -3233,7 +3048,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 
 	spin_lock_init(&vc4_hdmi->hw_lock);
-	INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
 
 	dev_set_drvdata(dev, vc4_hdmi);
 	encoder = &vc4_hdmi->encoder.base;
@@ -3246,15 +3060,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
 	vc4_hdmi->pdev = pdev;
 	vc4_hdmi->variant = variant;
 
-	/*
-	 * Since we don't know the state of the controller and its
-	 * display (if any), let's assume it's always enabled.
-	 * vc4_hdmi_disable_scrambling() will thus run at boot, make
-	 * sure it's disabled, and avoid any inconsistency.
-	 */
-	if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
-		vc4_hdmi->scdc_enabled = true;
-
 	ret = variant->init_resources(drm, vc4_hdmi);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..58c92ebc2677 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -118,8 +118,6 @@ struct vc4_hdmi {
 	struct vc4_encoder encoder;
 	struct drm_connector connector;
 
-	struct delayed_work scrambling_work;
-
 	struct i2c_adapter *ddc;
 	void __iomem *hdmicore_regs;
 	void __iomem *hd_regs;
@@ -193,12 +191,6 @@ struct vc4_hdmi {
 	 */
 	bool packet_ram_enabled;
 
-	/**
-	 * @scdc_enabled: Is the HDMI controller currently running with
-	 * the scrambler on? Protected by @mutex.
-	 */
-	bool scdc_enabled;
-
 	/**
 	 * @output_bpc: Copy of @drm_connector_state.hdmi.output_bpc for
 	 * use outside of KMS hooks. Protected by @mutex.

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:29 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:29 +0300
Subject: [PATCH v7 29/30] drm/tests: edid: Fix conformity for 1080p+4K
 YUV420 200MHz EDID
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-29-445eb54ee1ed@collabora.com>

The test EDID added by commit 58fe1d78605e ("drm/tests: hdmi: Provide
EDID supporting 4K at 30Hz with YUV420 only") fails 'edid-decode --check'
(v1.33.0) with the following issues:

  Warnings:

  Block 1, CTA-861 Extension Block:
    IT Video Formats are overscanned by default, but normally this should be underscanned.
    YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
      (which requires an RGB timings pixel rate >= 590 MHz).
  EDID:
    Base EDID: Some timings are out of range of the Monitor Ranges:
      Maximum Clock: 297.000 MHz (Monitor: 170.000 MHz)
    CTA-861: Multiple native progressive timings are defined.

  Failures:

  Block 0, Base EDID:
    Vendor & Product Identification: EDID 1.3 does not support week 0xff.
  Block 1, CTA-861 Extension Block:
    Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8: Max TMDS rate is > 0 and <= 340 or > 600.
    YCbCr 4:2:0 Capability Map Data Block: Empty Capability Map.
    YCbCr 4:2:0 Video Data Block: YCbCr 4:2:0-only VIC 95 is also a regular VIC.
    Missing VCDB, needed for Set Selectable RGB Quantization to avoid interop issues.
  EDID:
    CTA-861: The maximum HDMI TMDS clock is 200000 kHz, but one or more video timings go up to 297000 kHz.

Address them while preserving the advertised maximum resolutions, BPC
and TMDS clock used by the existing KUnit tests:

- Week 0xff is not valid for EDID 1.3; set it to 0x00 so that the Model
  year field becomes a regular Year of Manufacture.
- The HDMI Forum VSDB Max TMDS Character Rate must be 0 when no rate
  above 340 MHz is supported.  The HDMI VSDB still advertises 200 MHz as
  Max TMDS Clock.
- VIC 95 (3840x2160 at 30Hz) was reported as YUV420-only but was listed in
  both the regular Video Data Block and the YCbCr 4:2:0 Video Data
  Block.  Drop it from the regular VDB (so it stays advertised in the
  4:2:0 VDB only) and remove the now unnecessary empty YCbCr 4:2:0
  Capability Map Data Block.
- Add a Video Capability Data Block advertising selectable RGB and YCC
  quantization range plus underscan for IT/CE formats; also set the 'IT
  Video Formats Underscanned' bit in the CTA-861 extension header to
  match.
- Bump the Display Range Limits max pixel clock from 170 MHz to 300 MHz
  so it covers the 297 MHz pixel rate of VIC 95.
- Drop the 'native' flag from VIC 16 in the Video Data Block so it is no
  longer flagged as a second native progressive timing alongside the
  preferred DTD.

The only remaining warning is HDMI 2.1 related and can be ignored, as it
requires that any mode listed in the YCbCr 4:2:0 Video Data Block must
have a corresponding RGB pixel clock >= 590 MHz.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/tests/drm_kunit_edid.h | 65 +++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/tests/drm_kunit_edid.h b/drivers/gpu/drm/tests/drm_kunit_edid.h
index 9b318f7d364e..618b42d2fd8e 100644
--- a/drivers/gpu/drm/tests/drm_kunit_edid.h
+++ b/drivers/gpu/drm/tests/drm_kunit_edid.h
@@ -758,22 +758,22 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
  * edid-decode (hex):
  *
  * 00 ff ff ff ff ff ff 00 31 d8 34 00 00 00 00 00
- * ff 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
+ * 00 23 01 03 80 60 36 78 0f ee 91 a3 54 4c 99 26
  * 0f 50 54 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 c0 1c 32 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 18
- * 55 18 5e 11 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 bb
+ * 55 18 5e 1e 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 ad
  *
- * 02 03 29 31 42 90 5f 6c 03 0c 00 10 00 78 28 20
- * 00 00 01 03 6d d8 5d c4 01 28 80 07 00 00 00 00
- * 00 00 e3 0f 00 00 e2 0e 5f 00 00 00 00 00 00 00
+ * 02 03 27 b1 41 10 6c 03 0c 00 10 00 78 28 20 00
+ * 00 01 03 6d d8 5d c4 01 00 80 07 00 00 00 00 00
+ * 00 e2 00 ca e2 0e 5f 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 ca
+ * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9a
  *
  * ----------------
  *
@@ -782,7 +782,7 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
  *   Vendor & Product Identification:
  *     Manufacturer: LNX
  *     Model: 52
- *     Model year: 2025
+ *     Made in: 2025
  *   Basic Display Parameters & Features:
  *     Digital display
  *     Maximum image size: 96 cm x 54 cm
@@ -805,21 +805,21 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
  *                  Vfront    4 Vsync   5 Vback   36 Vpol P
  *     Display Product Name: 'Test EDID'
  *     Display Range Limits:
- *       Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 170 MHz
+ *       Monitor ranges (GTF): 24-85 Hz V, 24-94 kHz H, max dotclock 300 MHz
  *     Dummy Descriptor:
  *   Extension blocks: 1
- * Checksum: 0xbb
+ * Checksum: 0xad
  *
  * ----------------
  *
  * Block 1, CTA-861 Extension Block:
  *   Revision: 3
+ *   Underscans IT Video Formats by default
  *   Supports YCbCr 4:4:4
  *   Supports YCbCr 4:2:2
  *   Native detailed modes: 1
  *   Video Data Block:
- *     VIC  16:  1920x1080   60.000000 Hz  16:9     67.500 kHz    148.500000 MHz (native)
- *     VIC  95:  3840x2160   30.000000 Hz  16:9     67.500 kHz    297.000000 MHz
+ *     VIC  16:  1920x1080   60.000000 Hz  16:9     67.500 kHz    148.500000 MHz
  *   Vendor-Specific Data Block (HDMI), OUI 00-0C-03:
  *     Source physical address: 1.0.0.0
  *     DC_48bit
@@ -830,40 +830,57 @@ static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
  *     Extended HDMI video details:
  *   Vendor-Specific Data Block (HDMI Forum), OUI C4-5D-D8:
  *     Version: 1
- *     Maximum TMDS Character Rate: 200 MHz
  *     SCDC Present
  *     Supports 16-bits/component Deep Color 4:2:0 Pixel Encoding
  *     Supports 12-bits/component Deep Color 4:2:0 Pixel Encoding
  *     Supports 10-bits/component Deep Color 4:2:0 Pixel Encoding
- *   YCbCr 4:2:0 Capability Map Data Block:
- *     Empty Capability Map
+ *     VRRmin: 0 Hz
+ *     VRRmax: 0 Hz
+ *   Video Capability Data Block:
+ *     YCbCr quantization: Selectable (via AVI YQ)
+ *     RGB quantization: Selectable (via AVI Q)
+ *     PT scan behavior: No Data
+ *     IT scan behavior: Always Underscanned
+ *     CE scan behavior: Always Underscanned
  *   YCbCr 4:2:0 Video Data Block:
  *     VIC  95:  3840x2160   30.000000 Hz  16:9     67.500 kHz    297.000000 MHz
- * Checksum: 0xca
+ * Checksum: 0x9a  Unused space in Extension Block: 88 bytes
+ *
+ * ----------------
+ *
+ * edid-decode 1.33.0
+ *
+ * Warnings:
+ *
+ * Block 1, CTA-861 Extension Block:
+ *   YCbCr 4:2:0 Video Data Block: Some YCbCr 4:2:0 timings are invalid for HDMI 2.1
+ *     (which requires an RGB timings pixel rate >= 590 MHz).
+ *
+ * EDID conformity: PASS
  */
 static const unsigned char test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz[] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x31, 0xd8, 0x34, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xff, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78,
 	0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 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, 0xc0, 0x1c, 0x32, 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, 0x18,
-	0x55, 0x18, 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x55, 0x18, 0x5e, 0x1e, 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, 0xbb, 0x02, 0x03, 0x29, 0x31,
-	0x42, 0x90, 0x5f, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20,
-	0x00, 0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x28, 0x80, 0x07,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x0f, 0x00, 0x00, 0xe2, 0x0e,
-	0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xad, 0x02, 0x03, 0x27, 0xb1,
+	0x41, 0x10, 0x6c, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x78, 0x28, 0x20, 0x00,
+	0x00, 0x01, 0x03, 0x6d, 0xd8, 0x5d, 0xc4, 0x01, 0x00, 0x80, 0x07, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe2, 0x0e, 0x5f, 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, 0xca
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x9a,
 };
 
 /*

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Mon Jun  1 15:44:28 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Tue, 02 Jun 2026 01:44:28 +0300
Subject: [PATCH v7 28/30] drm/tests: hdmi_state_helper: Add HDMI 2.0
 scrambling tests
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
Message-ID: <20260602-dw-hdmi-qp-scramb-v7-28-445eb54ee1ed@collabora.com>

Cover the newly introduced HDMI 2.0 source-scrambler plumbing in the
drm_hdmi_state_helper code with the following KUnit tests:

- drm_test_check_scrambler_needed_low_rate verifies that a mode with
  TMDS rate <= 340 MHz never sets conn_state->hdmi.scrambler_needed,
  even when both endpoints advertise scrambling support.

- drm_test_check_scrambler_needed_high_rate verifies that a mode with
  TMDS rate > 340 MHz makes the helper set scrambler_needed.

- drm_test_check_scrambler_needed_high_rate_no_adv verifies that a mode
  with TMDS rate > 340 MHz never sets scrambler_needed when source does
  not advertise scrambling support, regardless of sink scrambling
  advertisement.

To match the behaviour drm_bridge_connector_init() applies to bridges
that implement source-scrambling callbacks, the __connector_hdmi_init()
helper now infers connector->hdmi.scrambling_supported from the presence
of .scrambler_enable and .scrambler_disable in the supplied
drm_connector_hdmi_funcs, mirroring how connector capability should be
wired up in real drivers.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 219 +++++++++++++++++++++
 1 file changed, 219 insertions(+)

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 e89e1af7a811..98cd42f429cb 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -20,6 +20,8 @@
 #include <drm/display/drm_hdmi_helper.h>
 #include <drm/display/drm_hdmi_state_helper.h>
 
+#include <linux/hdmi.h>
+
 #include "../drm_crtc_internal.h"
 
 #include <kunit/test.h>
@@ -140,6 +142,29 @@ static const struct drm_connector_hdmi_funcs reject_100mhz_connector_hdmi_funcs
 	},
 };
 
+static int accept_scrambler_enable(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static int accept_scrambler_disable(struct drm_connector *connector)
+{
+	return 0;
+}
+
+static const struct drm_connector_hdmi_funcs scrambler_connector_hdmi_funcs = {
+	.scrambler_enable	 = accept_scrambler_enable,
+	.scrambler_disable	 = accept_scrambler_disable,
+	.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)
 {
 	struct drm_atomic_helper_connector_hdmi_priv *priv =
@@ -240,6 +265,8 @@ __connector_hdmi_init(struct kunit *test,
 
 	conn = &priv->connector;
 	conn->ycbcr_420_allowed = !!(formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+	conn->hdmi.scrambler_supported = hdmi_funcs->scrambler_enable &&
+					 hdmi_funcs->scrambler_disable;
 
 	ret = drmm_connector_hdmi_init(drm, conn,
 				       "Vendor", "Product",
@@ -2198,6 +2225,195 @@ static void drm_test_check_disable_connector(struct kunit *test)
 	drm_modeset_acquire_fini(&ctx);
 }
 
+/*
+ * Test that a sub-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed, even when the source
+ * and the sink both support scrambling.
+ */
+static void drm_test_check_scrambler_needed_low_rate(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_connector_state *conn_state;
+	struct drm_display_info *info;
+	struct drm_display_mode *low_rate_mode;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	unsigned long long rate;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				8,
+				&scrambler_connector_hdmi_funcs,
+				test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+	info = &conn->display_info;
+	KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+	KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+	low_rate_mode = drm_kunit_display_mode_from_cea_vic(test, drm, 16);
+	KUNIT_ASSERT_NOT_NULL(test, low_rate_mode);
+
+	rate = drm_hdmi_compute_mode_clock(low_rate_mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+	KUNIT_ASSERT_LT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+						     low_rate_mode, &ctx);
+	if (ret == -EDEADLK) {
+		ret = drm_modeset_backoff(&ctx);
+		if (!ret)
+			goto retry_conn_enable;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	conn_state = conn->state;
+	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+	KUNIT_EXPECT_LE(test, conn_state->hdmi.tmds_char_rate,
+			HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+	KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate sets
+ * conn_state->hdmi.scrambler_needed when both source
+ * and sink advertise scrambling support.
+ */
+static void drm_test_check_scrambler_needed_high_rate(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_connector_state *conn_state;
+	struct drm_display_info *info;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	unsigned long long rate;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				8,
+				&scrambler_connector_hdmi_funcs,
+				test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+	info = &conn->display_info;
+	KUNIT_ASSERT_TRUE(test, conn->hdmi.scrambler_supported);
+	KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+	KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+						     preferred, &ctx);
+	if (ret == -EDEADLK) {
+		ret = drm_modeset_backoff(&ctx);
+		if (!ret)
+			goto retry_conn_enable;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	conn_state = conn->state;
+	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+	KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+			HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+	KUNIT_EXPECT_TRUE(test, conn_state->hdmi.scrambler_needed);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that an over-340 MHz TMDS character rate does not set
+ * conn_state->hdmi.scrambler_needed when the source does not
+ * advertise scrambling support, even if the sink does.
+ */
+static void drm_test_check_scrambler_needed_high_rate_no_adv(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_connector_state *conn_state;
+	struct drm_display_info *info;
+	struct drm_display_mode *preferred;
+	struct drm_connector *conn;
+	struct drm_device *drm;
+	struct drm_crtc *crtc;
+	unsigned long long rate;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444),
+				8,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_4k_rgb_yuv420_dc_max_600mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm = &priv->drm;
+	crtc = priv->crtc;
+	conn = &priv->connector;
+	info = &conn->display_info;
+	KUNIT_ASSERT_FALSE(test, conn->hdmi.scrambler_supported);
+	KUNIT_ASSERT_TRUE(test, info->is_hdmi);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.supported);
+	KUNIT_ASSERT_TRUE(test, info->hdmi.scdc.scrambling.supported);
+
+	preferred = find_preferred_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, preferred);
+
+	rate = drm_hdmi_compute_mode_clock(preferred, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+	KUNIT_ASSERT_GT(test, rate, HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn_enable:
+	ret = drm_kunit_helper_enable_crtc_connector(test, drm, crtc, conn,
+						     preferred, &ctx);
+	if (ret == -EDEADLK) {
+		ret = drm_modeset_backoff(&ctx);
+		if (!ret)
+			goto retry_conn_enable;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	conn_state = conn->state;
+	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+
+	KUNIT_EXPECT_GT(test, conn_state->hdmi.tmds_char_rate,
+			HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ);
+	KUNIT_EXPECT_FALSE(test, conn_state->hdmi.scrambler_needed);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
 	KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
 	KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
@@ -2227,6 +2443,9 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+	KUNIT_CASE(drm_test_check_scrambler_needed_low_rate),
+	KUNIT_CASE(drm_test_check_scrambler_needed_high_rate),
+	KUNIT_CASE(drm_test_check_scrambler_needed_high_rate_no_adv),
 	/*
 	 * TODO: We should have tests to check that a change in the
 	 * format triggers a CRTC mode change just like we do for the

-- 
2.54.0



From chaoyi.chen at rock-chips.com  Mon Jun  1 18:28:32 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Tue, 2 Jun 2026 09:28:32 +0800
Subject: [PATCH 1/5] drm/bridge: Implement generic USB Type-C DP HPD
 bridge
In-Reply-To: <ah3-auKugGCVojOp@venus>
References: <20260521032854.103-1-kernel@airkyi.com>
 <20260521032854.103-2-kernel@airkyi.com> <ah3-auKugGCVojOp@venus>
Message-ID: <bee9fdba-536f-4296-a9be-db35ab8d4172@rock-chips.com>

Hi Sebastian,

On 6/2/2026 6:08 AM, Sebastian Reichel wrote:
> Hi,
> 
> On Thu, May 21, 2026 at 11:28:50AM +0800, Chaoyi Chen wrote:
>> 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>
>> ---
>>  drivers/gpu/drm/bridge/Kconfig                | 10 ++++
>>  drivers/gpu/drm/bridge/Makefile               |  1 +
>>  .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 49 +++++++++++++++++++
> 
> Doesn't this require removing the manual registration of the HPD
> auxillary bridge in the USB-C controller drivers to avoid that
> two bridges are registered for them?
> 

I believe this will not affect existing controller drivers,
as they call drm_bridge_attach during registration. Of course,
while it won't affect the main bridge chain, you'll still see
an additional HPD bridge.

>>  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 c3209b0f4678..d92e93875793 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 beab5b695a6e..c4761526ba0a 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));
> 
> IIUIC this is called when the USB-C controller spawns a sub-device
> for the DP AltMode and then registers a HPD bridge to the USB-C
> controller itself. Wouldn't that register new HPD bridges on every
> USB-C replug?
> 
> Also doesn't this result in the bridge not being registered when
> nothing is plugged and thus the DRM pipeline not being able to bind
> properly?
>

That's a good question. The port altmode device here is only registered
once during initialization. While the parnter altmode device will
register and unregister during the plugging and unplugging process.
So you don't need to worry about that :)

https://lore.kernel.org/all/4fddba9a-b073-4bca-bd13-64a415f4bc47 at rock-chips.com/

-- 
Best, 
Chaoyi


From chaoyi.chen at rock-chips.com  Tue Jun  2 01:30:59 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Tue, 2 Jun 2026 16:30:59 +0800
Subject: [PATCH v2 07/12] drm/rockchip: dw_dp: Implement out-of-band HPD
 handling
In-Reply-To: <20260501-synopsys-dw-dp-improvements-v2-7-d7e7f6bac77f@collabora.com>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-7-d7e7f6bac77f@collabora.com>
Message-ID: <4f4ff085-80ae-4144-b040-be9b136574ee@rock-chips.com>

Hi Sebastian,

On 5/1/2026 6:20 AM, Sebastian Reichel wrote:
> Implement out-of-band hotplug handling, which will be used to receive
> external hotplug information from the USB-C state machine. This is
> currently handled by the USBDP PHY, which brings quite some trouble
> as the register being accessed requires the power-domain from the DP
> controller and also requires custom TypeC HPD info parsing in the
> USBDP PHY driver.
> 
> In contrast to the USBDP PHY this does not just enable the hotplug
> signal when a DP AltMode capable adapter is plugged in, but instead
> properly detects if a cable is plugged in for things like USB-C to
> HDMI adapters.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>

[...]

> +static void dw_dp_rockchip_hpd_sw_cfg(void *data, bool hpd)
> +{
> +	struct rockchip_dw_dp *dp = data;
> +	u32 hpd_reg = dp->pdata->hpd_reg[dp->id];
> +
> +	dev_dbg(dp->dev, "Force HPD connected=%s\n", str_yes_no(hpd));
> +
> +	dp->hpd_cfg = hpd;
> +
> +	regmap_write(dp->vo_grf, hpd_reg,
> +		     FIELD_PREP_WM16_CONST(ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG, dp->hpd_cfg));

FIELD_PREP_WM16() should be used here because "dp->hpd_cfg" is not a
constant expression.

Other patches in this series have similar issues. Doesn't your compiler
warn you about this? Thanks.

-- 
Best, 
Chaoyi


From joro at 8bytes.org  Tue Jun  2 01:44:52 2026
From: joro at 8bytes.org (Joerg Roedel)
Date: Tue, 2 Jun 2026 10:44:52 +0200
Subject: [PATCH v2] iommu/rockchip: disable fetch dte time limit
In-Reply-To: <20260428-spu-iommudtefix-v2-1-f592f579e508@pengutronix.de>
References: <20260428-spu-iommudtefix-v2-1-f592f579e508@pengutronix.de>
Message-ID: <ah6X68serZREQxJn@8bytes.org>

On Tue, Apr 28, 2026 at 06:05:31PM +0200, Sven P?schel wrote:
>  drivers/iommu/rockchip-iommu.c | 8 ++++++++
>  1 file changed, 8 insertions(+)

Applied, thanks.


From phucduc.bui at gmail.com  Tue Jun  2 03:16:03 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:03 +0700
Subject: [PATCH v2 0/5] ASoC: rockchip: Reorder clock enable sequence
Message-ID: <20260602101608.45137-1-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Hi all,

This series reorders the runtime resume clock enable sequence in the 
Rockchip SPDIF and PDM drivers to enable the bus clock before the 
functional controller clock.

It also updates the SPDIF DT binding clock descriptions to match the 
actual clock usage in the driver.

Additionally, this v2 adds two new patches addressing issues reported 
by the Sashiko AI Review tool regarding regcache sync failure handling 
and runtime PM resume status validation.

Testing:
  - Patch 1: Verified (dt_binding_check passed).
  - Patches 2 to 5: Compile tested only. Please help test if you have 
    the relevant Rockchip hardware.

Changes in v2:
  - Include two new patches to handle runtime PM resume and regcache sync 
    failures based on Sashiko AI Review.
  - Update commit message based on Krzysztof's review
  - Clarify in the commit message that the resume sequence becomes the
    reverse of the suspend sequence.


Best Regards,
Phuc

bui duc phuc (5):
  ASoC: dt-bindings: rockchip-spdif: Correct SPDIF clock descriptions
  ASoC: rockchip: spdif: Reorder clock enable sequence
  ASoC: rockchip: rockchip_pdm: Reorder clock enable sequence
  ASoC: rockchip: spdif: Restore regcache cache-only mode on sync
    failure
  ASoC: rockchip: rockchip_pdm: Handle runtime PM resume failures in
    set_fmt

 .../bindings/sound/rockchip-spdif.yaml           |  2 +-
 sound/soc/rockchip/rockchip_pdm.c                | 16 ++++++++++------
 sound/soc/rockchip/rockchip_spdif.c              | 11 ++++++-----
 3 files changed, 17 insertions(+), 12 deletions(-)

-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 03:16:04 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:04 +0700
Subject: [PATCH v2 1/5] ASoC: dt-bindings: rockchip-spdif: Correct SPDIF clock descriptions
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <20260602101608.45137-2-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Update the binding descriptions to match the actual clock usage, where
'mclk' is the controller clock and 'hclk' is the bus clock.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

Changes in v2:
  - Update commit message based on Krzysztof's review

 Documentation/devicetree/bindings/sound/rockchip-spdif.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
index 502907dd28b3..b174d7498029 100644
--- a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
+++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml
@@ -45,8 +45,8 @@ properties:
 
   clocks:
     items:
-      - description: clock for SPDIF bus
       - description: clock for SPDIF controller
+      - description: clock for SPDIF bus
 
   clock-names:
     items:
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 03:16:05 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:05 +0700
Subject: [PATCH v2 2/5] ASoC: rockchip: spdif: Reorder clock enable sequence
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <20260602101608.45137-3-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Enable the 'hclk' bus clock before the 'mclk' controller clock during
runtime resume.
The bus clock provides the register access interface, so enable it before
the controller clock. This also makes the resume sequence the reverse of
the suspend sequence, which keeps the clock ordering consistent.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only. Please help test if you have 
    the relevant Rockchip hardware.
Changes in v2:
  - Clarify in the commit message that the resume sequence becomes the
    reverse of the suspend sequence.

 sound/soc/rockchip/rockchip_spdif.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 581624f2682e..8de5b76cfe79 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -76,16 +76,16 @@ static int rk_spdif_runtime_resume(struct device *dev)
 	struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
 	int ret;
 
-	ret = clk_prepare_enable(spdif->mclk);
+	ret = clk_prepare_enable(spdif->hclk);
 	if (ret) {
-		dev_err(spdif->dev, "mclk clock enable failed %d\n", ret);
+		dev_err(spdif->dev, "hclk clock enable failed %d\n", ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(spdif->hclk);
+	ret = clk_prepare_enable(spdif->mclk);
 	if (ret) {
-		clk_disable_unprepare(spdif->mclk);
-		dev_err(spdif->dev, "hclk clock enable failed %d\n", ret);
+		clk_disable_unprepare(spdif->hclk);
+		dev_err(spdif->dev, "mclk clock enable failed %d\n", ret);
 		return ret;
 	}
 
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 03:16:06 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:06 +0700
Subject: [PATCH v2 3/5] ASoC: rockchip: rockchip_pdm: Reorder clock enable sequence
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <20260602101608.45137-4-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Enable the 'hclk' bus clock before the 'clk' controller clock during
runtime resume.
The bus clock provides the register access interface, so enable it before
the controller clock. This also makes the resume sequence the reverse of
the suspend sequence, which keeps the clock ordering consistent.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only. Please help test if you have 
    the relevant Rockchip hardware.
Changes in v2:
  - Clarify in the commit message that the resume sequence becomes the
    reverse of the suspend sequence.

 sound/soc/rockchip/rockchip_pdm.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c69cdd6f2499..8f78f7bc1806 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -422,16 +422,16 @@ static int rockchip_pdm_runtime_resume(struct device *dev)
 	struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
 	int ret;
 
-	ret = clk_prepare_enable(pdm->clk);
+	ret = clk_prepare_enable(pdm->hclk);
 	if (ret) {
-		dev_err(pdm->dev, "clock enable failed %d\n", ret);
+		dev_err(pdm->dev, "hclock enable failed %d\n", ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(pdm->hclk);
+	ret = clk_prepare_enable(pdm->clk);
 	if (ret) {
-		clk_disable_unprepare(pdm->clk);
-		dev_err(pdm->dev, "hclock enable failed %d\n", ret);
+		clk_disable_unprepare(pdm->hclk);
+		dev_err(pdm->dev, "clock enable failed %d\n", ret);
 		return ret;
 	}
 
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 03:16:07 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:07 +0700
Subject: [PATCH v2 4/5] ASoC: rockchip: spdif: Restore regcache cache-only mode on sync failure
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <20260602101608.45137-5-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

If regcache_sync() fails during runtime resume, the driver disables the
clocks and returns an error. However, the regmap cache-only mode is left
disabled.
Restore cache-only mode in the error path so subsequent register accesses
continue to use the cache while the device is inactive.

Reported-by: Sashiko AI Review <sashiko-bot at kernel.org>
Closes: https://lore.kernel.org/all/20260522103713.6C09D1F000E9 at smtp.kernel.org/
Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only. Please help test if you have 
    the relevant Rockchip hardware.

 sound/soc/rockchip/rockchip_spdif.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 8de5b76cfe79..7f15bc7f8f35 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -94,6 +94,7 @@ static int rk_spdif_runtime_resume(struct device *dev)
 
 	ret = regcache_sync(spdif->regmap);
 	if (ret) {
+		regcache_cache_only(spdif->regmap, true);
 		clk_disable_unprepare(spdif->mclk);
 		clk_disable_unprepare(spdif->hclk);
 	}
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 03:16:08 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Tue,  2 Jun 2026 17:16:08 +0700
Subject: [PATCH v2 5/5] ASoC: rockchip: rockchip_pdm: Handle runtime PM resume failures in set_fmt
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <20260602101608.45137-6-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

rockchip_pdm_set_fmt() calls pm_runtime_get_sync() before accessing
hardware registers, but ignores its return value.
If the runtime resume fails, the function continues to perform register
accesses while the device state is undefined.
Replace pm_runtime_get_sync() with pm_runtime_resume_and_get() and
return early on failure to avoid unpowered register accesses.

Reported-by: Sashiko AI Review <sashiko-bot at kernel.org>
Closes: https://lore.kernel.org/all/20260522110302.349421F000E9 at smtp.kernel.org/
Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only. Please help test if you have 
    the relevant Rockchip hardware.

 sound/soc/rockchip/rockchip_pdm.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index 8f78f7bc1806..115e90d3bbfe 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -321,6 +321,7 @@ static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai,
 {
 	struct rk_pdm_dev *pdm = to_info(cpu_dai);
 	unsigned int mask = 0, val = 0;
+	int ret;
 
 	mask = PDM_CKP_MSK;
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -334,7 +335,10 @@ static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai,
 		return -EINVAL;
 	}
 
-	pm_runtime_get_sync(cpu_dai->dev);
+	ret = pm_runtime_resume_and_get(cpu_dai->dev);
+	if (ret)
+		return ret;
+
 	regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val);
 	pm_runtime_put(cpu_dai->dev);
 
-- 
2.43.0



From andyshrk at 163.com  Tue Jun  2 06:25:47 2026
From: andyshrk at 163.com (Andy Yan)
Date: Tue, 2 Jun 2026 21:25:47 +0800 (CST)
Subject: [PATCH v2 2/2] drm/rockchip: vop2: Add YUV support to background
 color
In-Reply-To: <20260601-vop2-bg-yuv-v2-2-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
 <20260601-vop2-bg-yuv-v2-2-e5aef1d16fec@collabora.com>
Message-ID: <6909deb4.a38b.19e888300fe.Coremail.andyshrk@163.com>


Hello,

At 2026-06-02 02:00:04, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>The VOP2 background color must be programmed with 10-bit precision,
>using YUV format when the overlay operates in YUV mode, and RGB
>otherwise.
>
>Add the required RGB-to-YCbCr conversion logic, covering all color
>spaces supported by the display controller: BT601L, BT601F, BT709L and
>BT2020L.
>
>Since the color is currently programmed to hardware on every atomic
>commit, minimize the computation cost by splitting the work across the
>two paths: in atomic_enable(), perform the conversion unconditionally
>(the hardware state is unknown after power-on), while in atomic_flush(),
>perform it only when the DRM property has actually changed.
>
>Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>


    Acked-by: Andy Yan <andyshrk at 163.com>

    Thanks.

>---
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 153 ++++++++++++++++++++++++---
> 1 file changed, 138 insertions(+), 15 deletions(-)
>
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>index 64ac07cb1b0d..9b261f0c7eec 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>@@ -728,6 +728,89 @@ static void vop2_setup_csc_mode(struct vop2_video_port *vp,
> 	vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode);
> }
> 
>+/*
>+ * RGB-to-YCbCr conversion based on color_to_ycbcr() and rgb2ycbcr() from
>+ * drivers/media/common/v4l2-tpg/v4l2-tpg-core.c.
>+ *
>+ * Limited-range Y offset & chroma midpoint are expressed in 16-bit space.
>+ */
>+#define RGB2YUV_LIMITED_Y_OFFSET	(16 << 8)
>+#define RGB2YUV_CHROMA_OFFSET		(128 << 8)
>+#define COEFF(v, r)			((s32)(0.5 + (v) * (r) * 256.0))
>+
>+struct rgb2yuv_matrix {
>+	s32 y_r,  y_g,  y_b;
>+	s32 cb_r, cb_g, cb_b;
>+	s32 cr_r, cr_g, cr_b;
>+	s32 y_offset;
>+};
>+
>+/* BT.601 Limited range */
>+static const struct rgb2yuv_matrix rgb2yuv_bt601l = {
>+	.y_r  = COEFF(0.299, 219),   .y_g  = COEFF(0.587, 219),   .y_b  = COEFF(0.114, 219),
>+	.cb_r = COEFF(-0.1687, 224), .cb_g = COEFF(-0.3313, 224), .cb_b = COEFF(0.5, 224),
>+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4187, 224), .cr_b = COEFF(-0.0813, 224),
>+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
>+};
>+
>+/* BT.601 Full range */
>+static const struct rgb2yuv_matrix rgb2yuv_bt601f = {
>+	.y_r  = COEFF(0.299, 255),   .y_g  = COEFF(0.587, 255),   .y_b  = COEFF(0.114, 255),
>+	.cb_r = COEFF(-0.1687, 255), .cb_g = COEFF(-0.3313, 255), .cb_b = COEFF(0.5, 255),
>+	.cr_r = COEFF(0.5, 255),     .cr_g = COEFF(-0.4187, 255), .cr_b = COEFF(-0.0813, 255),
>+	.y_offset = 0,
>+};
>+
>+/* BT.709 Limited range */
>+static const struct rgb2yuv_matrix rgb2yuv_bt709l = {
>+	.y_r  = COEFF(0.2126, 219),  .y_g  = COEFF(0.7152, 219),  .y_b  = COEFF(0.0722, 219),
>+	.cb_r = COEFF(-0.1146, 224), .cb_g = COEFF(-0.3854, 224), .cb_b = COEFF(0.5, 224),
>+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4542, 224), .cr_b = COEFF(-0.0458, 224),
>+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
>+};
>+
>+/* BT.2020 Limited range */
>+static const struct rgb2yuv_matrix rgb2yuv_bt2020l = {
>+	.y_r  = COEFF(0.2627, 219),  .y_g  = COEFF(0.6780, 219),  .y_b  = COEFF(0.0593, 219),
>+	.cb_r = COEFF(-0.1396, 224), .cb_g = COEFF(-0.3604, 224), .cb_b = COEFF(0.5, 224),
>+	.cr_r = COEFF(0.5, 224),     .cr_g = COEFF(-0.4598, 224), .cr_b = COEFF(-0.0402, 224),
>+	.y_offset = RGB2YUV_LIMITED_Y_OFFSET,
>+};
>+
>+static const struct rgb2yuv_matrix *
>+vop2_rgb2yuv_get_matrix(enum vop_csc_format csc)
>+{
>+	switch (csc) {
>+	case CSC_BT601L:
>+		return &rgb2yuv_bt601l;
>+	case CSC_BT601F:
>+		return &rgb2yuv_bt601f;
>+	case CSC_BT2020L:
>+		return &rgb2yuv_bt2020l;
>+	case CSC_BT709L:
>+	default:
>+		return &rgb2yuv_bt709l;
>+	}
>+}
>+
>+/* Convert an RGB (16bpc) to YUV444 (16bpc). */
>+static void vop2_rgb16_to_yuv16(int v4l2_cs, u16 r, u16 g, u16 b,
>+				u16 *y, u16 *cb, u16 *cr)
>+{
>+	enum vop_csc_format csc = vop2_convert_csc_mode(v4l2_cs);
>+	const struct rgb2yuv_matrix *m = vop2_rgb2yuv_get_matrix(csc);
>+	s64 rs = r, gs = g, bs = b;
>+	s64 ys, cbs, crs;
>+
>+	ys  = m->y_r  * rs + m->y_g  * gs + m->y_b  * bs;
>+	cbs = m->cb_r * rs + m->cb_g * gs + m->cb_b * bs;
>+	crs = m->cr_r * rs + m->cr_g * gs + m->cr_b * bs;
>+
>+	*y  = (ys  >> 16) + m->y_offset;
>+	*cb = (cbs >> 16) + RGB2YUV_CHROMA_OFFSET;
>+	*cr = (crs >> 16) + RGB2YUV_CHROMA_OFFSET;
>+}
>+
> static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq)
> {
> 	struct vop2 *vop2 = vp->vop2;
>@@ -1554,12 +1637,58 @@ static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
> 				DITHER_DOWN_ALLEGRO);
> }
> 
>-static void vop2_post_config(struct drm_crtc *crtc)
>+static void vop2_bgcolor_setup(struct drm_crtc *crtc, bool force,
>+			       struct drm_crtc_state *new_crtc_state,
>+			       struct drm_crtc_state *old_crtc_state)
>+{
>+	struct rockchip_crtc_state *new_vcstate = to_rockchip_crtc_state(new_crtc_state);
>+	struct rockchip_crtc_state *old_vcstate = to_rockchip_crtc_state(old_crtc_state);
>+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
>+	u64 bgcolor = new_crtc_state->background_color;
>+	u16 y, cb, cr;
>+	u32 val;
>+
>+	if (!force && old_crtc_state->background_color == bgcolor &&
>+	    old_vcstate->color_space == new_vcstate->color_space)
>+		return;
>+
>+	/*
>+	 * Background color is programmed with 10 bits of precision, using YUV
>+	 * format when operating in YUV overlay mode, and RGB otherwise.
>+	 */
>+	if (new_vcstate->yuv_overlay) {
>+		vop2_rgb16_to_yuv16(new_vcstate->color_space,
>+				    DRM_ARGB64_GETR(bgcolor),
>+				    DRM_ARGB64_GETG(bgcolor),
>+				    DRM_ARGB64_GETB(bgcolor),
>+				    &y, &cb, &cr);
>+
>+		val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, cr >> 6);
>+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, y >> 6);
>+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, cb >> 6);
>+	} else {
>+		/*
>+		 * Since performance is more important than accuracy here, make
>+		 * use of the DRM_ARGB64_GET*_BPCS() helpers.
>+		 */
>+		val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED,
>+				 DRM_ARGB64_GETR_BPCS(bgcolor, 10));
>+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val,
>+			     DRM_ARGB64_GETG_BPCS(bgcolor, 10));
>+		FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val,
>+			     DRM_ARGB64_GETB_BPCS(bgcolor, 10));
>+	}
>+
>+	vop2_vp_write(vp, RK3568_VP_DSP_BG, val);
>+}
>+
>+static void vop2_post_config(struct drm_crtc *crtc, bool force,
>+			     struct drm_crtc_state *new_crtc_state,
>+			     struct drm_crtc_state *old_crtc_state)
> {
> 	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;
>+	struct drm_display_mode *mode = &new_crtc_state->adjusted_mode;
> 	u16 vtotal = mode->crtc_vtotal;
> 	u16 hdisplay = mode->crtc_hdisplay;
> 	u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start;
>@@ -1605,15 +1734,7 @@ static void vop2_post_config(struct drm_crtc *crtc)
> 		vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val);
> 	}
> 
>-	/*
>-	 * Background color is programmed with 10 bits of precision.
>-	 * Since performance is more important than accuracy here,
>-	 * make use of the DRM_ARGB64_GET*_BPCS() helpers.
>-	 */
>-	val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR_BPCS(bgcolor, 10));
>-	FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, DRM_ARGB64_GETG_BPCS(bgcolor, 10));
>-	FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, DRM_ARGB64_GETB_BPCS(bgcolor, 10));
>-	vop2_vp_write(vp, RK3568_VP_DSP_BG, val);
>+	vop2_bgcolor_setup(crtc, force, new_crtc_state, old_crtc_state);
> }
> 
> static int us_to_vertical_line(struct drm_display_mode *mode, int us)
>@@ -1628,8 +1749,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
> 	struct vop2 *vop2 = vp->vop2;
> 	const struct vop2_data *vop2_data = vop2->data;
> 	const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
>+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
> 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
>-	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
>+	struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc_state);
> 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> 	unsigned long clock = mode->crtc_clock * 1000;
> 	u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
>@@ -1799,7 +1921,7 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
> 
> 	clk_set_rate(vp->dclk, clock);
> 
>-	vop2_post_config(crtc);
>+	vop2_post_config(crtc, true, crtc_state, old_crtc_state);
> 
> 	vop2_cfg_done(vp);
> 
>@@ -1874,6 +1996,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
> 				   struct drm_atomic_commit *state)
> {
> 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
>+	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);
> 	struct vop2_video_port *vp = to_vop2_video_port(crtc);
> 	struct vop2 *vop2 = vp->vop2;
> 
>@@ -1881,7 +2004,7 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
> 	if (!drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->color_mgmt_changed)
> 		vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state);
> 
>-	vop2_post_config(crtc);
>+	vop2_post_config(crtc, false, crtc_state, old_crtc_state);
> 
> 	vop2_cfg_done(vp);
> 
>
>-- 
>2.54.0

From andyshrk at 163.com  Tue Jun  2 06:25:03 2026
From: andyshrk at 163.com (Andy Yan)
Date: Tue, 2 Jun 2026 21:25:03 +0800 (CST)
Subject: [PATCH v2 1/2] drm/rockchip: vop2: Rename CSC_BT2020 to
 CSC_BT2020L
In-Reply-To: <20260601-vop2-bg-yuv-v2-1-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
 <20260601-vop2-bg-yuv-v2-1-e5aef1d16fec@collabora.com>
Message-ID: <7bca6efb.a37a.19e88825619.Coremail.andyshrk@163.com>


Hello Cristian?

At 2026-06-02 02:00:03, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>Rename CSC_BT2020 to CSC_BT2020L for consistency with the other
>limited-range enum members (CSC_BT601L, CSC_BT709L) and to distinguish
>it from a potential future full-range BT.2020 variant.
>
>Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>---
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +-
> drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>index a160077a507f..64ac07cb1b0d 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
>@@ -658,7 +658,7 @@ static int vop2_convert_csc_mode(int csc_mode)
> 	case V4L2_COLORSPACE_JPEG:
> 		return CSC_BT601F;
> 	case V4L2_COLORSPACE_BT2020:
>-		return CSC_BT2020;
>+		return CSC_BT2020L;
> 	default:
> 		return CSC_BT709L;
> 	}
>diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>index 37722652844a..ffcb39c130aa 100644
>--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
>@@ -373,7 +373,7 @@ enum vop_csc_format {
> 	CSC_BT601L,
> 	CSC_BT709L,
> 	CSC_BT601F,
>-	CSC_BT2020,
>+	CSC_BT2020L,
> };



  Acked-by: Andy Yan <andyshrk at 163.com>


> 
> enum src_factor_mode {
>
>-- 
>2.54.0

From heiko at sntech.de  Tue Jun  2 08:02:54 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 17:02:54 +0200
Subject: [PATCH 63/76] drm/rockchip: rk3066_hdmi: Switch to atomic_create_state
In-Reply-To: <20260530-drm-no-more-bridge-reset-v1-63-875d828d31bc@kernel.org>
References: <20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc@kernel.org>
 <20260530-drm-no-more-bridge-reset-v1-63-875d828d31bc@kernel.org>
Message-ID: <3645200.7aRn1RRit1@phil>

Am Samstag, 30. Mai 2026, 16:00:08 Mitteleurop?ische Sommerzeit schrieb Maxime Ripard:
> The drm_bridge_funcs.atomic_reset callback and its
> drm_atomic_helper_bridge_reset() helper are deprecated.
> 
> Switch to the atomic_create_state callback and its
> drm_atomic_helper_bridge_create_state() counterpart.
> 
> Signed-off-by: Maxime Ripard <mripard at kernel.org>

having looked at the first parts of the series adding
the new functionality, this change looks good:

Reviewed-by: Heiko Stuebner <heiko at sntech.de>





From heiko at sntech.de  Tue Jun  2 08:02:37 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 17:02:37 +0200
Subject: [PATCH 62/76] drm/rockchip: cdn-dp: Switch to atomic_create_state
In-Reply-To: <20260530-drm-no-more-bridge-reset-v1-62-875d828d31bc@kernel.org>
References: <20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc@kernel.org>
 <20260530-drm-no-more-bridge-reset-v1-62-875d828d31bc@kernel.org>
Message-ID: <4650339.9PvXe5no7K@phil>

Am Samstag, 30. Mai 2026, 16:00:07 Mitteleurop?ische Sommerzeit schrieb Maxime Ripard:
> The drm_bridge_funcs.atomic_reset callback and its
> drm_atomic_helper_bridge_reset() helper are deprecated.
> 
> Switch to the atomic_create_state callback and its
> drm_atomic_helper_bridge_create_state() counterpart.
> 
> Signed-off-by: Maxime Ripard <mripard at kernel.org>

having looked at the first parts of the series adding
the new functionality, this change looks good:

Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> 
> ---
> 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>
> Cc: dri-devel at lists.freedesktop.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org
> ---
>  drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> index 190cce9530c8..e159e1627f3c 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> @@ -823,11 +823,11 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge,
>  }
>  
>  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,
> -	.atomic_reset = drm_atomic_helper_bridge_reset,
> +	.atomic_create_state = drm_atomic_helper_bridge_create_state,
>  	.detect = cdn_dp_bridge_detect,
>  	.edid_read = cdn_dp_bridge_edid_read,
>  	.atomic_enable = cdn_dp_bridge_atomic_enable,
>  	.atomic_disable = cdn_dp_bridge_atomic_disable,
>  	.mode_valid = cdn_dp_bridge_mode_valid,
> 
> 






From heiko at sntech.de  Tue Jun  2 08:03:13 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 17:03:13 +0200
Subject: [PATCH 64/76] drm/rockchip: lvds: Switch to atomic_create_state
In-Reply-To: <20260530-drm-no-more-bridge-reset-v1-64-875d828d31bc@kernel.org>
References: <20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc@kernel.org>
 <20260530-drm-no-more-bridge-reset-v1-64-875d828d31bc@kernel.org>
Message-ID: <8196895.2l3rmUXbR5@phil>

Am Samstag, 30. Mai 2026, 16:00:09 Mitteleurop?ische Sommerzeit schrieb Maxime Ripard:
> The drm_bridge_funcs.atomic_reset callback and its
> drm_atomic_helper_bridge_reset() helper are deprecated.
> 
> Switch to the atomic_create_state callback and its
> drm_atomic_helper_bridge_create_state() counterpart.
> 
> Signed-off-by: Maxime Ripard <mripard at kernel.org>

having looked at the first parts of the series adding
the new functionality, this change looks good:

Reviewed-by: Heiko Stuebner <heiko at sntech.de>





From robh at kernel.org  Tue Jun  2 08:47:24 2026
From: robh at kernel.org (Rob Herring)
Date: Tue, 2 Jun 2026 10:47:24 -0500
Subject: [PATCH v6 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601162143.170030-2-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
 <20260601162143.170030-2-hrushirajg23@gmail.com>
Message-ID: <20260602154724.GA399800-robh@kernel.org>

On Mon, Jun 01, 2026 at 09:51:40PM +0530, Hrushiraj Gandhi wrote:
> Add the vendor prefix for Vicharak Computers Pvt. Ltd.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>

Missing tags. Perhaps because you are sending new versions before we can 
look at prior versions.

> ---
>  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 28784d66ae7b..504a691a33b9 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -1791,6 +1791,8 @@ patternProperties:
>      description: VIA Technologies, Inc.
>    "^vialab,.*":
>      description: VIA Labs, Inc.
> +  "^vicharak,.*":
> +    description: Vicharak Computers Pvt. Ltd.
>    "^vicor,.*":
>      description: Vicor Corporation
>    "^videostrong,.*":
> -- 
> 2.47.3
> 


From alchark at flipper.net  Tue Jun  2 10:00:38 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Tue, 02 Jun 2026 21:00:38 +0400
Subject: [PATCH 0/2] drm/rockchip: dw_hdmi_qp: Add support for HDMI
 overscan compensation
Message-ID: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>

When using a TV as a display, output image may be cropped due to overscan.
Rockchip VOP2 supports post-composition scaling in hardware, which can be
used to compensate for the overscan.

This adds the necessary pixel margin fields to the CRTC state, and sets
them from the TV overscan property of the connector which is understood
by the userspace (tested with KWin's display configuration module).

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
Alexey Charkov (2):
      drm/rockchip: vop2: honor TV margins from CRTC state for overscan compensation
      drm/rockchip: dw_hdmi_qp: expose "overscan" property

 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h    |  2 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c   | 17 +++++++++++------
 3 files changed, 29 insertions(+), 6 deletions(-)
---
base-commit: 08484c504b55a98bd100527fbe10a3caf55ff3ff
change-id: 20260602-hdmi-overscan-4f0d89bfd981

Best regards,
-- 
Alexey Charkov <alchark at flipper.net>



From alchark at flipper.net  Tue Jun  2 10:00:39 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Tue, 02 Jun 2026 21:00:39 +0400
Subject: [PATCH 1/2] drm/rockchip: vop2: honor TV margins from CRTC state
 for overscan compensation
In-Reply-To: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
Message-ID: <20260602-hdmi-overscan-v1-1-31f71b817c80@flipper.net>

Replace the hard-coded percent values with pixel margins carried in struct
rockchip_crtc_state, sourced from the standard DRM "left/right/top/bottom
margin" connector properties (struct drm_connector_tv_margins) to pave way
for HDMI overscan compensation support.

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h  |  2 ++
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 17 +++++++++++------
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 2e86ad00979c..83f8ec4f3319 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -10,6 +10,7 @@
 #define _ROCKCHIP_DRM_DRV_H
 
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_connector.h>
 #include <drm/drm_gem.h>
 
 #include <linux/bits.h>
@@ -53,6 +54,7 @@ struct rockchip_crtc_state {
 	u32 bus_format;
 	u32 bus_flags;
 	int color_space;
+	struct drm_connector_tv_margins tv_margins;
 };
 #define to_rockchip_crtc_state(s) \
 		container_of(s, struct rockchip_crtc_state, base)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index a160077a507f..55307b8493ae 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1558,30 +1558,35 @@ 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 rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state);
 	struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+	const struct drm_connector_tv_margins *m = &vcstate->tv_margins;
 	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;
 	u16 vdisplay = mode->crtc_vdisplay;
 	u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start;
-	u32 left_margin = 100, right_margin = 100;
-	u32 top_margin = 100, bottom_margin = 100;
-	u16 hsize = hdisplay * (left_margin + right_margin) / 200;
-	u16 vsize = vdisplay * (top_margin + bottom_margin) / 200;
+	u16 hsize = hdisplay;
+	u16 vsize = vdisplay;
 	u16 hact_end, vact_end;
 	u32 val;
 
 	vop2->ops->setup_bg_dly(vp);
 
+	if (m->left + m->right < hdisplay)
+		hsize = hdisplay - m->left - m->right;
+	if (m->top + m->bottom < vdisplay)
+		vsize = vdisplay - m->top - m->bottom;
+
 	vsize = rounddown(vsize, 2);
 	hsize = rounddown(hsize, 2);
-	hact_st += hdisplay * (100 - left_margin) / 200;
+	hact_st += m->left;
 	hact_end = hact_st + hsize;
 	val = hact_st << 16;
 	val |= hact_end;
 	vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val);
-	vact_st += vdisplay * (100 - top_margin) / 200;
+	vact_st += m->top;
 	vact_end = vact_st + vsize;
 	val = vact_st << 16;
 	val |= vact_end;

-- 
2.52.0



From alchark at flipper.net  Tue Jun  2 10:00:40 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Tue, 02 Jun 2026 21:00:40 +0400
Subject: [PATCH 2/2] drm/rockchip: dw_hdmi_qp: expose "overscan" property
In-Reply-To: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
Message-ID: <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>

Expose the "overscan" connector property as recognized by KWin and the
likes to compensate for TV overscan cropping.

The CRTC will use the margin values derived from this overscan percentage
in its post-composition scaler to add appropriate blank margins on all
sides of the output image so that the TV doesn't eat up visible content.

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..fae44d11dbef 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -137,10 +137,18 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
 					 struct drm_connector_state *conn_state)
 {
 	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
+	const struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
 	union phy_configure_opts phy_cfg = {};
+	unsigned int overscan;
 	int ret;
 
+	overscan = min(conn_state->tv.overscan, 100u);
+	s->tv_margins.left   = adj_mode->hdisplay * overscan / 200;
+	s->tv_margins.right  = s->tv_margins.left;
+	s->tv_margins.top    = adj_mode->vdisplay * overscan / 200;
+	s->tv_margins.bottom = s->tv_margins.top;
+
 	if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
 	    s->output_bpc == conn_state->hdmi.output_bpc)
 		return 0;
@@ -603,6 +611,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
 				     "Failed to init bridge connector\n");
 
+	ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to create TV connector properties\n");
+
+	drm_object_attach_property(&connector->base,
+				   drm->mode_config.tv_overscan_property, 0);
+
 	return 0;
 }
 

-- 
2.52.0



From conor at kernel.org  Tue Jun  2 10:01:45 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 2 Jun 2026 18:01:45 +0100
Subject: [PATCH v10 01/11] dt-bindings: display: rockchip: analogix-dp:
 Fix hclk as third clock for RK3588
In-Reply-To: <20260601065100.1103873-2-damon.ding@rock-chips.com>
References: <20260601065100.1103873-1-damon.ding@rock-chips.com>
 <20260601065100.1103873-2-damon.ding@rock-chips.com>
Message-ID: <20260602-cranial-aerobics-9db5af2159ec@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-rockchip/attachments/20260602/dc3cedc3/attachment.sig>

From heiko at sntech.de  Tue Jun  2 11:47:41 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 20:47:41 +0200
Subject: [PATCH v2 0/2] YUV support for VOP2 background color
In-Reply-To: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
References: <20260601-vop2-bg-yuv-v2-0-e5aef1d16fec@collabora.com>
Message-ID: <178042605608.614111.131135337224991312.b4-ty@sntech.de>


On Mon, 01 Jun 2026 21:00:02 +0300, Cristian Ciocaltea wrote:
> Since commit bec7cbfa7d4f ("drm/rockchip: vop2: Support setting custom
> background color") the VOP2 display controller allows configuring the
> background color of each video output port.
> 
> However, this is currently limited to RGB formats.  When operating in
> YUV overlay mode, the color must be programmed using YUV format.
> 
> [...]

Applied, thanks!

[1/2] drm/rockchip: vop2: Rename CSC_BT2020 to CSC_BT2020L
      commit: 09dfa47fc557f945871dcf279c8e687e55d3550d
[2/2] drm/rockchip: vop2: Add YUV support to background color
      commit: 28e670a0885cf2501fd51189ce7b6f5b7cacebf9

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 11:48:29 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 20:48:29 +0200
Subject: [PATCH 1/1] arm64: dts: rockchip: enable button for Radxa E25
In-Reply-To: <20260601101000.2076721-1-amadeus@jmu.edu.cn>
References: <20260601101000.2076721-1-amadeus@jmu.edu.cn>
Message-ID: <178042610721.614536.13908287937215191728.b4-ty@sntech.de>


On Mon, 01 Jun 2026 18:10:00 +0800, Chukun Pan wrote:
> The Radxa E25 board has an ADC button. Enable it.
> 
> 

Applied, thanks!

[1/1] arm64: dts: rockchip: enable button for Radxa E25
      commit: dc98bd71f41db3666aa8505cc8c72d02653d2980

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 12:31:43 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 21:31:43 +0200
Subject: [PATCH v4 0/3] Rockchip DRM use-after-free & null-ptr-deref fixes
In-Reply-To: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
Message-ID: <178042869904.638042.16054419218883756618.b4-ty@sntech.de>


On Mon, 01 Jun 2026 19:13:43 +0300, Cristian Ciocaltea wrote:
> The first three patches in the series are fixes for use-after-free &
> null-ptr-deref related issues found in dw_dp and inno-hdmi Rockchip DRM
> drivers.
> 
> The following three patches provide a few minor improvements to dw_dp
> and dw_hdmi_qp, while the remaining two address use-after-free and
> memory allocation in DW DP core library.
> 
> [...]

Applied, thanks!

[1/3] drm/bridge: synopsys: dw-dp: Support unregistering the AUX channel
      commit: ed04e8e2307f35b3d8d49a554faf5e72d3d224e6
[2/3] drm/rockchip: dw_dp: Add missing newline in dev_err_probe() message
      commit: 0a01412178047bf3ff351c7e75d373e411072a87
[3/3] drm/rockchip: dw_dp: Release core resources
      commit: cc6d7aca2f37a1525a94ef97eb3ce361732c876c

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 12:44:19 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 21:44:19 +0200
Subject: [PATCH 0/5] drm/rockchip: vop2: Fix layer cfg done timeout on multi-output setups
In-Reply-To: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
References: <20260504-vop2-layer-cfg-tmout-v1-0-730226a7331e@collabora.com>
Message-ID: <178042945330.650189.17239358036514651129.b4-ty@sntech.de>


On Mon, 04 May 2026 21:23:58 +0300, Cristian Ciocaltea wrote:
> On RK3588/RK3568 boards with multiple active display outputs, start/stop
> transitions may trigger a timeout during overlay layer configuration:
> 
>   rockchip-drm display-subsystem: [drm] *ERROR* wait layer cfg done timeout
> 
> The shared OVL_LAYER_SEL and OVL_PORT_SEL shadow registers are committed
> to the active configuration at the vsync of whichever Video Port is
> selected by LAYERSEL_REGDONE_SEL.  When two Video Ports race through
> atomic commits, rk3568_vop2_setup_layer_mixer() has two issues that
> cause the wait to poll for a value the hardware might not be able to
> produce.
> 
> [...]

Applied, thanks!

[1/5] drm/rockchip: vop2: Fix wrong wait target in layer cfg done check
      commit: 9f5670802df085ad343146561e69bac43e9905d2
[2/5] drm/rockchip: vop2: Wait for layer cfg done before switching LAYERSEL_REGDONE_SEL
      commit: d1ad644e572c0647ad8428439eafea0aacfccf9e
[3/5] drm/rockchip: vop2: Delay old_{layer|port}_sel updates in setup_layer_mixer()
      commit: 6a2f7339191b652f7ff998595df90987b33c3fda
[4/5] drm/rockchip: vop2: Drop redundant zero-init in setup_layer_mixer()
      commit: bc5ffd6fc30cc52983d95fbe8783bb4233db6f86
[5/5] drm/rockchip: vop2: Use vop2->old_layer_sel directly in wait_for_layer_cfg_done()
      commit: dc3de97433db03157ba6f87b6494ff1ad416a5a8

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 12:48:11 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 21:48:11 +0200
Subject: [PATCH v2 01/12] drm/bridge: synopsys: dw-dp: Support unregistering the
 AUX channel
In-Reply-To: <20260501-synopsys-dw-dp-improvements-v2-1-d7e7f6bac77f@collabora.com>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-1-d7e7f6bac77f@collabora.com>
Message-ID: <8220078.YiXZdWvhHV@phil>

Am Freitag, 1. Mai 2026, 00:20:28 Mitteleurop?ische Sommerzeit schrieb Sebastian Reichel:
> From: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> The DisplayPort AUX channel gets initialized and registered during
> dw_dp_bind(), but it is never unregistered, which may lead to resource
> leaks and/or use-after-free.
> 
> Add the missing dw_dp_unbind() function to allow the users of the
> library to handle the required cleanup, i.e. unregister the AUX adapter.
> 
> Fixes: 86eecc3a9c2e ("drm/bridge: synopsys: Add DW DPTX Controller support library")
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>

picked the same one from Cristian's series




From heiko at sntech.de  Tue Jun  2 12:48:35 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 21:48:35 +0200
Subject: [PATCH v2 02/12] drm/rockchip: dw_dp: Release core resources
In-Reply-To: <20260501-synopsys-dw-dp-improvements-v2-2-d7e7f6bac77f@collabora.com>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-2-d7e7f6bac77f@collabora.com>
Message-ID: <27595863.kmuVQn2iE0@phil>

Am Freitag, 1. Mai 2026, 00:20:29 Mitteleurop?ische Sommerzeit schrieb Sebastian Reichel:
> From: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> Core resources such as the DisplayPort AUX channel get initialized and
> registered during dw_dp_bind(), but are never unregistered, which may
> lead to memory leaks and/or use-after-free:
> 
> [  224.661371] BUG: KASAN: slab-use-after-free in device_is_dependent+0xe0/0x2b0
> [  224.662015] Read of size 8 at addr ffff00011aee8550 by task modprobe/658
> [  224.662612]
> [  224.662752] CPU: 7 UID: 0 PID: 658 Comm: modprobe Not tainted 7.0.0-rc2-next-20260305 #14 PREEMPT
> [  224.662759] Hardware name: Radxa ROCK 5B (DT)
> [  224.662762] Call trace:
> [  224.662764]  show_stack+0x20/0x38 (C)
> [  224.662772]  dump_stack_lvl+0x6c/0x98
> [  224.662777]  print_report+0x160/0x4b8
> [  224.662783]  kasan_report+0xb4/0xe0
> [  224.662790]  __asan_report_load8_noabort+0x20/0x30
> [  224.662796]  device_is_dependent+0xe0/0x2b0
> [  224.662802]  device_is_dependent+0x108/0x2b0
> [  224.662808]  device_link_add+0x1f8/0x10b0
> [  224.662813]  devm_of_phy_get_by_index+0x120/0x200
> [  224.662819]  dw_dp_bind+0x34c/0xb10 [dw_dp]
> [  224.662830]  dw_dp_rockchip_bind+0x194/0x250 [rockchipdrm]
> [  224.662864]  component_bind_all+0x3a8/0x720
> [  224.662869]  rockchip_drm_bind+0x120/0x390 [rockchipdrm]
> [  224.662899]  try_to_bring_up_aggregate_device+0x76c/0x838
> [  224.662904]  component_master_add_with_match+0x1f4/0x230
> [  224.662909]  rockchip_drm_platform_probe+0x420/0x538 [rockchipdrm]
> [  224.662939]  platform_probe+0xe8/0x168
> [  224.662945]  really_probe+0x340/0x828
> [  224.662950]  __driver_probe_device+0x2e0/0x350
> [  224.662954]  driver_probe_device+0x80/0x140
> [  224.662959]  __driver_attach+0x398/0x460
> [  224.662964]  bus_for_each_dev+0xe0/0x198
> [  224.662968]  driver_attach+0x50/0x68
> [  224.662972]  bus_add_driver+0x2a0/0x4c0
> [  224.662977]  driver_register+0x294/0x360
> [  224.662982]  __platform_driver_register+0x7c/0x98
> [  224.662987]  rockchip_drm_init+0xc4/0xff8 [rockchipdrm]
> 
> Since a previous commit exported dw_dp_unbind() function in DW DP core
> library to take care of the necessary cleanup, use this in the
> component's unbind() callback, as well as in its bind() error path.
> 
> Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>

picked the same one from Cristian's series




From heiko at sntech.de  Tue Jun  2 13:05:40 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 22:05:40 +0200
Subject: (subset) [PATCH v10 00/11] Add eDP support for RK3576
In-Reply-To: <20260601065100.1103873-1-damon.ding@rock-chips.com>
References: <20260601065100.1103873-1-damon.ding@rock-chips.com>
Message-ID: <178043072949.664369.15843941283523280742.b4-ty@sntech.de>


On Mon, 01 Jun 2026 14:50:49 +0800, Damon Ding wrote:
> Patch 1-5 are to add missing clock "hclk" for RK3588 eDP nodes.
> Patch 6 is to use automatic cleanup to fix OF node reference leak
>         reported by Sashiko.
> Patch 7-8 are to add the RK3576 eDP node.
> Patch 9-11 are to support the RK3576 Analogix DP controller.
> 
> Damon Ding (11):
>   dt-bindings: display: rockchip: analogix-dp: Fix hclk as third clock
>     for RK3588
>   dt-bindings: display: rockchip: analogix-dp: Add per-clock
>     descriptions
>   arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
>   arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
>   drm/rockchip: analogix_dp: Enable hclk for RK3588
>   drm/rockchip: analogix_dp: Fix OF node reference leak via auto cleanup
>   dt-bindings: display: rockchip: analogix-dp: Add support for RK3576
>   arm64: dts: rockchip: Add eDP node for RK3576
>   drm/bridge: analogix_dp: Rename and simplify is_rockchip()
>   drm/bridge: analogix_dp: Add support for RK3576
>   drm/rockchip: analogix_dp: Add support for RK3576
> 
> [...]

Applied, thanks!

[01/11] dt-bindings: display: rockchip: analogix-dp: Fix hclk as third clock for RK3588
        commit: 826ab13cf73e7bd5b268085c9594850f6a7fc7fd
[02/11] dt-bindings: display: rockchip: analogix-dp: Add per-clock descriptions
        commit: 38f41d4e704c2a9bfc025bb17594d53be010a629
[05/11] drm/rockchip: analogix_dp: Enable hclk for RK3588
        commit: 104f20616d72825fdcf56cfdc5f89f4e96fd8dbe
[06/11] drm/rockchip: analogix_dp: Fix OF node reference leak via auto cleanup
        commit: 87e060521371257ddbb77964b66e60d80afcc7b2

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 13:39:07 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 22:39:07 +0200
Subject: [PATCH v2 00/11] drm/rockchip: dw_hdmi: Misc cleanup and propagate bus format
In-Reply-To: <20260518193748.2482823-1-jonas@kwiboo.se>
References: <20260518193748.2482823-1-jonas@kwiboo.se>
Message-ID: <178043273743.699871.14907494731416478776.b4-ty@sntech.de>


On Mon, 18 May 2026 19:37:34 +0000, Jonas Karlman wrote:
> This series include misc cleanup of the dwhdmi-rockchip driver and
> prepares for future support of YCbCr output and Deep Color modes.
> 
> Patch 1-7 cleanup and changes to use drmres helpers for the encoder.
> Patch 8 prepare for use of a display-connector bridge for RK3568/RK3566.
> Patch 9-10 prepares for future support of YCbCr and Deep Color modes.
> Patch 11 changes to use resume_early pm ops for system suspend.
> 
> [...]

Applied, thanks!

[01/11] drm/rockchip: dw_hdmi: Use of_device_get_match_data() to get match data
        commit: 1965bd5479655362f316035e16a49f4598526b37
[02/11] drm/rockchip: dw_hdmi: Use local dev variable consistently in bind()
        commit: 9cefcd0e83a38d9ede0bea988b4f7b2f01511e28
[03/11] drm/rockchip: dw_hdmi: Use drmres helpers for encoder resources
        commit: 3de723684be5c13517dea3dba287d06e12678c86
[04/11] drm/rockchip: dw_hdmi: Inline resource lookup into bind()
        commit: c19830fba394f3566cf763864dec44cfd357325f
[05/11] drm/rockchip: dw_hdmi: Hold a reference to the dw-hdmi bridge
        commit: f80fa5817952a24f45659b1377aa5da31941eab5
[06/11] drm/rockchip: dw_hdmi: Remove empty encoder helper funcs
        commit: f98f2ef3ad28ea09cbb1d3706dc59e84668f3fdb
[07/11] drm/rockchip: dw_hdmi: Clean up whitespace
        commit: 2ca256b5fe2325d0f1134789b507a621775b385e
[08/11] drm/rockchip: dw_hdmi: Set output_port for RK3568/RK3566
        commit: 1481cc03cc63fc0f6990956264cbb16c8f65f28e
[09/11] drm/rockchip: dw_hdmi: Configure HDMI PHY in atomic_mode_set()
        commit: e54d6ed9a0a967ada1e7222d7485e0cbb0e1f563
[10/11] drm/rockchip: dw_hdmi: Propagate bus format to display driver
        commit: dc70272cc184b945cf526a23999fc8645e76bbed
[11/11] drm/rockchip: dw_hdmi: Use resume_early pm ops for system suspend
        commit: af3a9eadc11896f6677bcb7102bfb7c84be48d2d

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 13:41:33 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 22:41:33 +0200
Subject: (subset) [PATCH v10 00/11] Add eDP support for RK3576
In-Reply-To: <20260601065100.1103873-1-damon.ding@rock-chips.com>
References: <20260601065100.1103873-1-damon.ding@rock-chips.com>
Message-ID: <178043288414.700628.1161981255624036929.b4-ty@sntech.de>


On Mon, 01 Jun 2026 14:50:49 +0800, Damon Ding wrote:
> Patch 1-5 are to add missing clock "hclk" for RK3588 eDP nodes.
> Patch 6 is to use automatic cleanup to fix OF node reference leak
>         reported by Sashiko.
> Patch 7-8 are to add the RK3576 eDP node.
> Patch 9-11 are to support the RK3576 Analogix DP controller.
> 
> Damon Ding (11):
>   dt-bindings: display: rockchip: analogix-dp: Fix hclk as third clock
>     for RK3588
>   dt-bindings: display: rockchip: analogix-dp: Add per-clock
>     descriptions
>   arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
>   arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
>   drm/rockchip: analogix_dp: Enable hclk for RK3588
>   drm/rockchip: analogix_dp: Fix OF node reference leak via auto cleanup
>   dt-bindings: display: rockchip: analogix-dp: Add support for RK3576
>   arm64: dts: rockchip: Add eDP node for RK3576
>   drm/bridge: analogix_dp: Rename and simplify is_rockchip()
>   drm/bridge: analogix_dp: Add support for RK3576
>   drm/rockchip: analogix_dp: Add support for RK3576
> 
> [...]

Applied, thanks!

[07/11] dt-bindings: display: rockchip: analogix-dp: Add support for RK3576
        commit: 473e50b27b0020ade5fd97ca04d941e448c5659a
[09/11] drm/bridge: analogix_dp: Rename and simplify is_rockchip()
        commit: 709445fb6fc57aa96d48c8492e84ed4b2a9a4b5e
[10/11] drm/bridge: analogix_dp: Add support for RK3576
        commit: 5442cdc38470ecd6b51562d378b6ed852a4d9d45
[11/11] drm/rockchip: analogix_dp: Add support for RK3576
        commit: 7e60c4e19fd3d3f1203fbb1fdd9b2bb1a1201e65

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 13:59:38 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 22:59:38 +0200
Subject: [PATCH 1/2] drm/rockchip: dsi: Add maximum per lane bit rate calculation
In-Reply-To: <20260324085838.90-1-kernel@airkyi.com>
References: <20260324085838.90-1-kernel@airkyi.com>
Message-ID: <4888940.6M6d0yLqnL@phil>

Am Dienstag, 24. M?rz 2026, 09:58:37 Mitteleurop?ische Sommerzeit schrieb Chaoyi Chen:
> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
> 
> Different chips have varying support for the maximum bit rate per lane.
> 
> Add calculation for the maximum per lane bit rate for various chip
> platforms, and relax the bandwidth margin requirements.
> 
> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
> ---
>  .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 21 +++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> index 3547d91b25d3..d3bacfae174e 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> @@ -268,6 +268,7 @@ struct rockchip_dw_dsi_chip_data {
>  
>  	unsigned int flags;
>  	unsigned int max_data_lanes;
> +	unsigned long max_bit_rate_per_lane;
>  };
>  
>  struct dw_mipi_dsi_rockchip {
> @@ -565,7 +566,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>  	int bpp;
>  	unsigned long mpclk, tmp;
>  	unsigned int target_mbps = 1000;
> -	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
> +	unsigned int max_mbps;
>  	unsigned long best_freq = 0;
>  	unsigned long fvco_min, fvco_max, fin, fout;
>  	unsigned int min_prediv, max_prediv;
> @@ -573,6 +574,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>  	unsigned long _fbdiv, best_fbdiv;
>  	unsigned long min_delta = ULONG_MAX;
>  
> +	max_mbps = dsi->cdata->max_bit_rate_per_lane;

I may be blind, but how do the values come together?
In the dppa_map table we have mbps values of 89 to 1500
(MHz)

While below the values set are
	.max_bit_rate_per_lane = 1500000000UL,
in Hz I guess

And I don't see the needed conversion somehow.


>  	dsi->format = format;
>  	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
>  	if (bpp < 0) {
> @@ -584,8 +586,8 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>  
>  	mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
>  	if (mpclk) {
> -		/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
> -		tmp = mpclk * (bpp / lanes) * 10 / 8;
> +		/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
> +		tmp = mpclk * (bpp / lanes) * 10 / 9;

Please do this in a separate patch, especially as I would expect some
sort of explanation on why this is ok to do.

Thanks
Heiko

>  		if (tmp < max_mbps)
>  			target_mbps = tmp;
>  		else
> @@ -595,7 +597,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>  
>  	/* for external phy only a the mipi_dphy_config is necessary */
>  	if (dsi->phy) {
> -		phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8,
> +		phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 9,
>  						 bpp, lanes,
>  						 &dsi->phy_opts.mipi_dphy);
>  		dsi->lane_mbps = target_mbps;
> @@ -1503,6 +1505,7 @@ static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = {
>  						PX30_DSI_FORCETXSTOPMODE), 0),
>  
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1000000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1515,6 +1518,7 @@ static const struct rockchip_dw_dsi_chip_data rk3128_chip_data[] = {
>  						RK3128_DSI_FORCERXMODE |
>  						RK3128_DSI_FORCETXSTOPMODE), 0),
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1000000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1527,6 +1531,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
>  		.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI0_LCDC_SEL, 1),
>  
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  	},
>  	{
>  		.reg = 0xff964000,
> @@ -1535,6 +1540,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
>  		.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI1_LCDC_SEL, 1),
>  
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1547,6 +1553,7 @@ static const struct rockchip_dw_dsi_chip_data rk3368_chip_data[] = {
>  						RK3368_DSI_FORCETXSTOPMODE |
>  						RK3368_DSI_FORCERXMODE), 0),
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1634,6 +1641,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
>  
>  		.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  	},
>  	{
>  		.reg = 0xff968000,
> @@ -1658,6 +1666,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
>  
>  		.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  
>  		.dphy_rx_init = rk3399_dphy_tx1rx1_init,
>  		.dphy_rx_power_on = rk3399_dphy_tx1rx1_power_on,
> @@ -1674,6 +1683,7 @@ static const struct rockchip_dw_dsi_chip_data rk3506_chip_data[] = {
>  			     FIELD_PREP_WM16_CONST(RK3506_DSI_FORCERXMODE, 0) |
>  			     FIELD_PREP_WM16_CONST(RK3506_DSI_FORCETXSTOPMODE, 0)),
>  		.max_data_lanes = 2,
> +		.max_bit_rate_per_lane = 1500000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1687,6 +1697,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
>  			     FIELD_PREP_WM16_CONST(RK3568_DSI0_TURNDISABLE, 0) |
>  			     FIELD_PREP_WM16_CONST(RK3568_DSI0_FORCERXMODE, 0)),
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1200000000UL,
>  	},
>  	{
>  		.reg = 0xfe070000,
> @@ -1696,6 +1707,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
>  			     FIELD_PREP_WM16_CONST(RK3568_DSI1_TURNDISABLE, 0) |
>  			     FIELD_PREP_WM16_CONST(RK3568_DSI1_FORCERXMODE, 0)),
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1200000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> @@ -1708,6 +1720,7 @@ static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = {
>  			     FIELD_PREP_WM16_CONST(RV1126_DSI_FORCERXMODE, 0) |
>  			     FIELD_PREP_WM16_CONST(RV1126_DSI_FORCETXSTOPMODE, 0)),
>  		.max_data_lanes = 4,
> +		.max_bit_rate_per_lane = 1000000000UL,
>  	},
>  	{ /* sentinel */ }
>  };
> 






From heiko at sntech.de  Tue Jun  2 14:02:13 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 23:02:13 +0200
Subject: [PATCH 2/2] drm/rockchip: dsi: Add dphy_get_timing support for multiple
 PHY types
In-Reply-To: <20260324085838.90-2-kernel@airkyi.com>
References: <20260324085838.90-1-kernel@airkyi.com>
 <20260324085838.90-2-kernel@airkyi.com>
Message-ID: <7091445.e8TTKsaY2g@phil>

Am Dienstag, 24. M?rz 2026, 09:58:38 Mitteleurop?ische Sommerzeit schrieb Chaoyi Chen:
> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
> 
> Currently, there are generally two types of DPHY for Rockchip. One is
> the DPHY used by RK3288/RK3399, whose timing is described by Table A-3
> High-Speed Transition Times in the databook. The other is the DPHY used
> by PX30 and its successors. If its timing is still described using
> RK3288/RK3399, it may not perform correctly on some DSI panel.
> 
> Add dphy_get_timing for different D-PHY types to adapt to timing
> differences.
> 
> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
> ---
>  .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 45 ++++++++++++++++++-
>  1 file changed, 43 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> index d3bacfae174e..2d1c9e54ff85 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> @@ -247,6 +247,7 @@ enum {
>  	BIASEXTR_127_7,
>  };
>  
> +struct dw_mipi_dsi_rockchip;
>  struct rockchip_dw_dsi_chip_data {
>  	u32 reg;
>  
> @@ -262,6 +263,9 @@ struct rockchip_dw_dsi_chip_data {
>  	u32 lanecfg2_grf_reg;
>  	u32 lanecfg2;
>  
> +	int (*dphy_get_timing)(struct dw_mipi_dsi_rockchip *dsi, unsigned int lane_mbps,
> +			       struct dw_mipi_dsi_dphy_timing *timing);
> +
>  	int (*dphy_rx_init)(struct phy *phy);
>  	int (*dphy_rx_power_on)(struct phy *phy);
>  	int (*dphy_rx_power_off)(struct phy *phy);
> @@ -721,8 +725,9 @@ static struct hstt hstt_table[] = {
>  };
>  
>  static int
> -dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
> -			   struct dw_mipi_dsi_dphy_timing *timing)
> +dw_mipi_dsi_phy_rk3288_get_timing(struct dw_mipi_dsi_rockchip *dsi,
> +				  unsigned int lane_mbps,
> +				  struct dw_mipi_dsi_dphy_timing *timing)
>  {
>  	int i;
>  
> @@ -738,6 +743,32 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
>  	return 0;
>  }
>  
> +static const struct dw_mipi_dsi_dphy_timing dphy_timing_px30 = {
> +	.clk_lp2hs = 0x40,
> +	.clk_hs2lp = 0x40,
> +	.data_lp2hs = 0x10,
> +	.data_hs2lp = 0x14,
> +};

so just to make sure, the timing on the px30 (and later) variant is the
same for all lane speeds?

Please include that bit in the commit description

Thanks
Heiko




From heiko at sntech.de  Tue Jun  2 14:08:20 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 02 Jun 2026 23:08:20 +0200
Subject: [PATCH] arm64: dts: rockchip: fix emmc reset polarity on px30-cobra
In-Reply-To: <20260512092225.34835-1-jakob.unterwurzacher@cherry.de>
References: <20260512092225.34835-1-jakob.unterwurzacher@cherry.de>
Message-ID: <3631825.d7IHhHJzqS@phil>

Am Dienstag, 12. Mai 2026, 11:22:09 Mitteleurop?ische Sommerzeit schrieb Jakob Unterwurzacher:
> Technically, the reset signal is active low - it's called RST_n after all.
> 
> But it is ignored completely unless RST_n_FUNCTION=1 (byte 162 in extcsd)
> is set in the emmc. It is 0 per default.
> 
> For emmcs that have RST_n_FUNCTION=1 we failed like this:
> 
> 	[    3.074480] mmc1: Failed to initialize a non-removable card
> 
> With this change they work normally.
> 
> Cc: stable at vger.kernel.org
> Fixes: bb510ddc9d3e ("arm64: dts: rockchip: add px30-cobra base dtsi and board variants")
> Signed-off-by: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>

as Quentin remarked, author (@gmail) and signed-off-by do not match.
While I'm generally open to fixing things, when it touches the DCO this
isn't the case.

So please resend this with the correct author.

In general "git send-email" will do the correct thing (that From: line),
when patch author and email-id do not match.


Thanks
Heiko

> ---
>  arch/arm64/boot/dts/rockchip/px30-cobra.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
> index b7e669d8ba4d..90751b04f95c 100644
> --- a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
> @@ -35,7 +35,7 @@ emmc_pwrseq: emmc-pwrseq {
>  		compatible = "mmc-pwrseq-emmc";
>  		pinctrl-0 = <&emmc_reset>;
>  		pinctrl-names = "default";
> -		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
> +		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
>  	};
>  
>  	gpio-leds {
> 






From heiko at sntech.de  Tue Jun  2 14:14:56 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 23:14:56 +0200
Subject: [PATCH v4 0/5] rockchip: add USB nodes for RK3528
In-Reply-To: <20260529190355.4148175-1-heiko@sntech.de>
References: <20260529190355.4148175-1-heiko@sntech.de>
Message-ID: <178043489360.713702.10193094828449758923.b4-ty@sntech.de>


On Fri, 29 May 2026 21:03:50 +0200, Heiko Stuebner wrote:
> This adds the USB nodes to RK3528 and therefore needs both the dwc3
> compatible [0], as well as the phy support [1] to be merged first.
> 
> changes in v4:
> - phy-supply not vbus-supply on armsom sige1
> - adapt e20c commit message explaining the hub
> - describe my changes to the original patches inside them
> 
> [...]

Applied, thanks!

[1/5] arm64: dts: rockchip: Add USB nodes for RK3528
      commit: 5f3ae9b12a6c523992a7216bbc4420ac33450b79
[2/5] arm64: dts: rockchip: Enable USB 2.0 ports on Radxa E20C
      commit: e897bcf81dd920bf80ace6d98ec6f9645c5b50f2
[3/5] arm64: dts: rockchip: Enable USB ports on Radxa ROCK 2A/2F
      commit: 4e55d52f5f3b333a9ff5103099df97291aaeb083
[4/5] arm64: dts: rockchip: Enable USB 2.0 ports on ArmSoM Sige1
      commit: b6b74087f90a201cfdd6da6a43e7b92dba8370e3
[5/5] arm64: dts: rockchip: Enable USB 2.0 ports on NanoPi Zero2
      commit: ff660109f4129a13bbdc31bc14ca233ebf0c9450

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From heiko at sntech.de  Tue Jun  2 14:14:57 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue,  2 Jun 2026 23:14:57 +0200
Subject: [PATCH] arm64: dts: rockchip: Fix vcc_sdio regulator max voltage on Pinebook Pro
In-Reply-To: <20260519094439.7918-1-hugo@whynothugo.nl>
References: <20260519094439.7918-1-hugo@whynothugo.nl>
Message-ID: <178043489362.713702.703857469309199514.b4-ty@sntech.de>


On Tue, 19 May 2026 11:44:39 +0200, Hugo Osvaldo Barrera wrote:
> The vcc_sdio regulator supports 1.8V to 3.4V output range according to
> its datasheet.
> 
> The current DT incorrectly limits the max voltage to 3.0V. This limit
> causes issues issues downstream with u-boot, which refuses to apply the
> out-of range value, and falls back to the minimum in that range: 1.8V.
> This is insufficient to power the SD card, so driver initialisation
> fails and booting from it does not work.
> 
> [...]

Applied, thanks!

[1/1] arm64: dts: rockchip: Fix vcc_sdio regulator max voltage on Pinebook Pro
      commit: 8545eda00fdf3d7e17933ce0f706d005b1bad42d

Best regards,
-- 
Heiko Stuebner <heiko at sntech.de>


From cristian.ciocaltea at collabora.com  Tue Jun  2 14:25:01 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 3 Jun 2026 00:25:01 +0300
Subject: [PATCH v3] drm/bridge: dw-hdmi-qp: use drm_hdmi_acr_get_n_cts()
 helper for audio N/CTS
In-Reply-To: <86fcf349-0a7a-4618-9001-612371b0f71b@symple.nz>
References: <86fcf349-0a7a-4618-9001-612371b0f71b@symple.nz>
Message-ID: <92ac1962-e43a-45a0-958e-e32385af098c@collabora.com>

Hi Simon,

On 5/21/26 10:36 AM, Simon Wright wrote:
> dw_hdmi_qp_set_sample_rate() open-coded its own N and CTS lookup
> tables and search/compute helpers, but it lacked the out-of-table
> CTS fallback needed by strict HDMI sinks at TMDS rates not in the
> table.  The original LG G3 OLED audio mute (linux-rockchip 070633)
> was caused by dw_hdmi_qp_find_cts() returning 0 at 185.625 MHz,
> leaving AUDPKT_ACR_CTS_OVR_EN clear and falling back to the
> controller's internal CTS auto-measurement, which produces incorrect
> timing on the wire at out-of-table rates.
> 
> The shared drm_hdmi_acr_get_n_cts() helper in
> drivers/gpu/drm/display/drm_hdmi_helper.c already implements the
> correct behaviour: it has the HDMI 1.4b spec N/CTS tables, and for
> TMDS rates not in the table it computes CTS = (TMDS * N) / (128 * Fs)
> inline (the canonical HDMI spec formula).  It is already used by
> drivers/gpu/drm/msm/hdmi/hdmi_audio.c.
> 
> Convert dw_hdmi_qp_set_sample_rate() to call the helper.  This
> removes ~200 lines of open-coded tables and search functions
> (dw_hdmi_qp_find_n, _compute_n, _find_cts, _audio_math_diff,
> _match_tmds_n_table, common_tmds_n_table[], common_tmds_cts_table[])
> and fixes the strict-sink audio mute as a side effect of using the
> helper's complete N+CTS path.
> 
> Tested on R76S (RK3576) running Linux 7.0.1, against the LG G3 OLED
> (the sink that originally reported the mute in linux-rockchip
> 070633) at four TMDS rates spanning HDMI 1.4 and HDMI 2.0:
> 
>   TMDS         Mode              Audio with v3
>   148.5 MHz    1080p60   8-bit   plays
>   185.625 MHz  1080p60  10-bit   plays
>   297 MHz      1080p100  8-bit   plays
>   594 MHz      3840p60   8-bit   plays
> 
> Without this change, the LG G3 mutes audio at 185.625, 297, and
> 594 MHz (every rate outside dw-hdmi-qp's open-coded CTS table,
> which contained only 148.5 MHz and below).  With this change,
> drm_hdmi_acr_get_n_cts() supplies the correct CTS at every rate --
> table-canonical at 148.5 / 297 / 594 MHz, and computed via the
> HDMI 1.4b formula at 185.625 MHz.  The 148.5 MHz row is a
> regression check confirming the in-table path is unchanged.
> 
> The Kogan KALED43XU9210STA (a permissive HDMI 2.0 sink that plays
> audio at all rates with or without this change) was used as a
> no-regression control: audio plays at 594 MHz with v3 loaded.
> 
> The open-coded N table in dw-hdmi-qp included optimised N values
> for some TMDS rates that are not in the helper's table (e.g.
> various non-CEA rates between 28-162 MHz).  For those rates the
> helper's fallback returns N = 128 * Fs / 1000, which is the same
> value dw_hdmi_qp_compute_n() returned when no table optimisation
> was needed; no audio regression has been observed at the rates
> tested above.
> 
> Reported-by: Simon Wright <simon at symple.nz>
> Closes: https://lore.kernel.org/linux-rockchip/ME3P282MB21960D9D68BFF520316BDFCEA83E2 at ME3P282MB2196.AUSP282.PROD.OUTLOOK.COM/
> Suggested-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> Suggested-by: Jonas Karlman <jonas at kwiboo.se>
> Tested-by: Simon Wright <simon at symple.nz>

I think T-b can be dropped, as the commit description implies you've actually
tested this before submitting.

> Assisted-by: Claude:claude-opus-4-7
> Signed-off-by: Simon Wright <simon at symple.nz>

The patch looks good to me. 

I'm unable to reproduce the reported issues, but I can confirm audio continues
to work as expected on my end.  

Feel free to include:

Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Tested-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

Regards,
Cristian


From macroalpha82 at gmail.com  Tue Jun  2 14:25:06 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:06 -0500
Subject: [PATCH V4 0/6] Add Anbernic RG Vita-Pro
Message-ID: <20260602212512.418166-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the Anbernic RG Vita-Pro, based on the Rockchip RK3576 SoC.

Changes Since V1:
 - Updated documentation filename to matche compatible string.
 - Corrected order of allocating IRQ in charger driver and switched
   to using devm managed function to allocate work queue.

Changes Since V2:
 - Corrected issue with naming of panel binding document and added
   fallback compatible string.
 - Switched to devm helpers in panel driver. Note that
   devm_drm_panel_add() is currently only in the drm-next branch.
 - Optimized setting GPIOs for panel driver.

Changes Since V3:
 - Fixed numerous issues identifed by Sashiko bot, mainly relating
   to unclamped or improperly clamped values from within the
   charger driver.
 - Corrected hard-coded values in the panel driver unprepare routine
   as well as correcting an improperly checked return condition.

Chris Morgan (6):
  dt-bindings: power: supply: sgm41542: document sgm41542
  power: supply: sgm41542: Add SG Micro sgm41542 charger
  dt-bindings: display: panel: document Anbernic TD4310 panel
  drm/panel: anbernic-td4310: Add RG Vita Pro panel
  dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
  arm64: dts: rockchip: Add Anbernic RG Vita-Pro

 .../devicetree/bindings/arm/rockchip.yaml     |    6 +
 .../display/panel/anbernic,td4310.yaml        |   66 +
 .../power/supply/sgmicro,sgm41542.yaml        |  104 ++
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 drivers/gpu/drm/panel/Kconfig                 |   10 +
 drivers/gpu/drm/panel/Makefile                |    1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c |  254 ++++
 drivers/power/supply/Kconfig                  |    8 +
 drivers/power/supply/Makefile                 |    1 +
 drivers/power/supply/sgm41542_charger.c       | 1065 +++++++++++++
 11 files changed, 2843 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
 create mode 100644 drivers/power/supply/sgm41542_charger.c

-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:07 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:07 -0500
Subject: [PATCH V4 1/6] dt-bindings: power: supply: sgm41542: document sgm41542
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Document the SG Micro sgm41542 battery charger/boost converter.
The parameters of input-current-limit-microamp and
input-voltage-limit-microvolt are defined as such since they are in
common use among multiple bindings currently.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../power/supply/sgmicro,sgm41542.yaml        | 104 ++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
new file mode 100644
index 000000000000..a97afea83700
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SGM41542 Battery Charger
+
+description:
+  The SGMicro SGM41542 is a single cell battery charger/boost controller.
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+  - Xu Shengfei <xsf at rock-chips.com>
+
+allOf:
+  - $ref: power-supply.yaml#
+
+properties:
+  compatible:
+    const: sgmicro,sgm41542
+
+  input-current-limit-microamp:
+    description:
+      Optional value to clamp the maximum input current limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (2400000).
+    minimum: 100000
+    maximum: 3800000
+
+  input-voltage-limit-microvolt:
+    description:
+      Optional value to clamp the maximum input voltage limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (4500000).
+    minimum: 3900000
+    maximum: 12000000
+
+  interrupts:
+    maxItems: 1
+
+  monitored-battery:
+    description: |
+        A phandle to a monitored battery node. Values for the following
+        are used by the driver and if not present will result in default
+        values being applied:
+        constant-charge-current-max-microamp
+        constant-charge-voltage-max-microvolt
+        charge-term-current-microamp
+        precharge-current-microamp
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    properties:
+      otg-vbus:
+        type: object
+        description: OTG boost regulator
+        $ref: /schemas/regulator/regulator.yaml
+        unevaluatedProperties: false
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    battery: battery {
+      compatible = "simple-battery";
+      constant-charge-current-max-microamp = <10000000>;
+      constant-charge-voltage-max-microvolt = <4350000>;
+      precharge-current-microamp = <180000>;
+      charge-term-current-microamp = <300000>;
+    };
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      charger at 3b {
+        compatible = "sgmicro,sgm41542";
+        reg = <0x3b>;
+        input-current-limit-microamp = <3000000>;
+        input-voltage-limit-microvolt = <4500000>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        monitored-battery = <&battery>;
+
+        regulators {
+          otg-vbus {
+            regulator-max-microvolt = <5000000>;
+            regulator-min-microvolt = <5000000>;
+          };
+        };
+      };
+    };
-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:08 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:08 -0500
Subject: [PATCH V4 2/6] power: supply: sgm41542: Add SG Micro sgm41542 charger
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the SG Micro SGM41542 charger/boost converter.
Driver was adapted from Rockchip BSP driver [1] and confirmed
with vendor datasheet [2].

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
[2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/power/supply/Kconfig            |    8 +
 drivers/power/supply/Makefile           |    1 +
 drivers/power/supply/sgm41542_charger.c | 1065 +++++++++++++++++++++++
 3 files changed, 1074 insertions(+)
 create mode 100644 drivers/power/supply/sgm41542_charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 83392ed6a8da..57dae0913472 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -856,6 +856,14 @@ config CHARGER_RK817
 	help
 	  Say Y to include support for Rockchip RK817 Battery Charger.
 
+config CHARGER_SGM41542
+	tristate "SGM41542 charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the SGM41542 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB3XX Battery Charger"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7ee839dca7f3..c376889db317 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
+obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
new file mode 100644
index 000000000000..334767df3d9e
--- /dev/null
+++ b/drivers/power/supply/sgm41542_charger.c
@@ -0,0 +1,1065 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Chrager driver for Sgm4154x
+ *
+ * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Xu Shengfei <xsf at rock-chips.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/types.h>
+
+#define SGM4154X_MANUFACTURER			"SGMICRO"
+#define SGM4154X_NAME				"sgm41542"
+
+#define SGM4154X_CHRG_CTRL_0			0x00
+#define SGM4154X_HIZ_EN				BIT(7)
+#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
+#define SGM4154X_IINDPM_I_MIN_UA		100000
+#define SGM4154X_IINDPM_I_MAX_UA		3800000
+#define SGM4154X_IINDPM_STEP_UA			100000
+#define SGM4154X_IINDPM_DEF_UA			2400000
+
+#define SGM4154X_CHRG_CTRL_1			0x01
+#define SGM4154X_WDT_RST			BIT(6)
+#define SGM4154X_OTG_EN				BIT(5)
+#define SGM4154X_CHRG_EN			BIT(4)
+
+#define SGM4154X_CHRG_CTRL_2			0x02
+#define SGM4154X_BOOST_LIM			BIT(7)
+#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
+#define SGM4154X_ICHRG_I_STEP_UA		60000
+#define SGM4154X_ICHRG_I_MIN_UA			0
+#define SGM4154X_ICHRG_I_MAX_UA			3780000
+#define SGM4154X_ICHRG_I_DEF_UA			2040000
+
+#define SGM4154X_CHRG_CTRL_3			0x03
+#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
+#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_PRECHRG_I_MIN_UA		60000
+#define SGM4154X_PRECHRG_I_MAX_UA		780000
+#define SGM4154X_PRECHRG_I_DEF_UA		180000
+#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
+#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_TERMCHRG_I_MIN_UA		60000
+#define SGM4154X_TERMCHRG_I_MAX_UA		960000
+#define SGM4154X_TERMCHRG_I_DEF_UA		180000
+
+#define SGM4154X_CHRG_CTRL_4			0x04
+#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
+#define SGM4154X_VREG_V_MAX_UV			4624000
+#define SGM4154X_VREG_V_MIN_UV			3856000
+#define SGM4154X_VREG_V_DEF_UV			4208000
+#define SGM4154X_VREG_V_STEP_UV			32000
+#define SGM4154X_VRECHARGE			BIT(0)
+#define SGM4154X_VRECHRG_STEP_MV		100
+#define SGM4154X_VRECHRG_OFFSET_MV		100
+
+#define SGM4154X_CHRG_CTRL_5			0x05
+#define SGM4154X_TERM_EN			BIT(7)
+#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
+#define SGM4154X_WDT_TIMER_40S			BIT(4)
+#define SGM4154X_WDT_TIMER_80S			BIT(5)
+#define SGM4154X_WDT_TIMER_160S			(BIT(4) | BIT(5))
+#define SGM4154X_WDT_TIMER_DISABLE		0
+
+#define SGM4154X_CHRG_CTRL_6			0x06
+#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
+#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
+#define SGM4154X_OVP_10_5V			BIT(7)
+#define SGM4154X_OVP_6_5V			BIT(6)
+#define SGM4154X_OVP_5_5V			0
+#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
+#define SGM4154X_BOOSTV				GENMASK(5, 4)
+#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
+#define SGM4154X_VINDPM_V_MIN_UV		3900000
+#define SGM4154X_VINDPM_V_MAX_UV		12000000
+#define SGM4154X_VINDPM_STEP_UV			100000
+#define SGM4154X_VINDPM_DEF_UV			4500000
+
+#define SGM4154X_CHRG_CTRL_7			0x07
+
+#define SGM4154X_CHRG_STAT		0x08
+#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
+#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
+#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
+#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
+#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
+#define SGM4154X_USB_CDP		BIT(6)
+#define SGM4154X_USB_SDP		BIT(5)
+#define SGM4154X_NOT_CHRGING		0
+#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
+#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
+#define SGM4154X_FAST_CHRG		BIT(4)
+#define SGM4154X_PRECHRG		BIT(3)
+#define SGM4154X_PG_STAT		BIT(2)
+#define SGM4154X_THERM_STAT		BIT(1)
+#define SGM4154X_VSYS_STAT		BIT(0)
+
+#define SGM4154X_CHRG_FAULT		0x09
+#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
+#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
+#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
+#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
+#define SGM4154X_TEMP_WARM		BIT(1)
+#define SGM4154X_TEMP_NORMAL		BIT(0)
+
+#define SGM4154X_CHRG_CTRL_A		0x0a
+#define SGM4154X_VBUS_GOOD		BIT(7)
+#define SGM4154X_VINDPM_INT_MASK	BIT(1)
+#define SGM4154X_IINDPM_INT_MASK	BIT(0)
+
+#define SGM4154X_CHRG_CTRL_B		0x0b
+#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
+#define SGM4154X_PN_MASK		GENMASK(6, 3)
+
+#define SGM4154X_CHRG_CTRL_C		0x0c
+
+#define SGM4154X_CHRG_CTRL_D		0x0d
+#define SGM4154X_JEITA_EN		BIT(0)
+
+#define SGM4154X_INPUT_DET		0x0e
+#define SGM4154X_DPDM_ONGOING		BIT(7)
+
+#define SGM4154X_CHRG_CTRL_F		0x0f
+#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
+
+#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
+
+struct sgm4154x_init_data {
+	int ilim;	/* input current limit */
+	int vlim;	/* minimum system voltage limit */
+	int iterm;	/* termination current */
+	int iprechg;	/* precharge current */
+	int max_ichg;	/* maximum charge current */
+	int max_vreg;	/* maximum charge voltage */
+};
+
+struct sgm4154x_state {
+	bool vsys_stat;
+	bool therm_stat;
+	bool online;
+	u8 chrg_stat;
+	bool chrg_en;
+	bool vbus_gd;
+	u8 chrg_type;
+	u8 health;
+	u8 chrg_fault;
+	u8 ntc_fault;
+};
+
+struct sgm4154x_device {
+	struct i2c_client *client;
+	struct device *dev;
+	struct power_supply *charger;
+	struct regmap *regmap;
+	char model_name[I2C_NAME_SIZE];
+	struct sgm4154x_init_data init_data;
+	struct sgm4154x_state state;
+	struct regulator_dev *otg_rdev;
+	bool watchdog_enable;
+	struct workqueue_struct *sgm_monitor_wq;
+	struct delayed_work sgm_delay_work;
+};
+
+enum SGM4154X_VINDPM_OS {
+	VINDPM_OS_3900MV,
+	VINDPM_OS_5900MV,
+	VINDPM_OS_7500MV,
+	VINDPM_OS_10500MV,
+};
+
+static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_TERMCHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set term current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
+
+	reg_val = reg_val << 4;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_PRECHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set precharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, SGM4154X_ICHRG_I_MAX_UA);
+	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_2,
+				 SGM4154X_ICHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set icharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge current error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
+
+	return val * SGM4154X_ICHRG_I_STEP_UA;
+}
+
+static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
+{
+	int reg_val;
+	int ret;
+
+	/*
+	 * Note that the value of 0x01111 represents a "special value"
+	 * corresponding to 4352000uV instead of the expected 4336000uV,
+	 * per the datasheet. All other values are as expected. So not
+	 * only do we need to clamp between max and min values, but
+	 * also clamp anything below 4352000uv to 4304000uv to prevent
+	 * overcharging.
+	 */
+	if (chrg_volt < 4352000)
+		chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, 4304000);
+	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
+	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
+	reg_val = reg_val << 3;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VREG_V_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set charge voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge voltage error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
+
+	/*
+	 * 0x01111 is a special value meaning 4352000uV, all other
+	 * values are as expected based on the offset and step values.
+	 */
+	if (val == 0x0f)
+		return 4352000;
+
+	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
+}
+
+static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
+				       unsigned int vindpm)
+{
+	enum SGM4154X_VINDPM_OS os_val;
+	unsigned int offset;
+	u8 reg_val;
+	int ret;
+
+
+	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
+	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
+		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
+		return -EINVAL;
+	}
+
+	/*
+	 * Supported ranges per the datasheet are as follows:
+	 * 3.9v - 5.4v with a 3.9v offset
+	 * 5.9v - 7.4v with a 5.9v offset
+	 * 7.5v - 9.0v with a 7.5v offset
+	 * 10.5v - 12.0v with a 10.5v offset
+	 * Step size is a constant 100mv
+	 */
+	if (vindpm < 5900000) {
+		vindpm = clamp(vindpm, VINDPM_OS_3900MV, 5400000);
+		os_val = VINDPM_OS_3900MV;
+		offset = 3900000;
+	} else if (vindpm >= 5900000 && vindpm < 7500000) {
+		vindpm = clamp(vindpm, VINDPM_OS_5900MV, 7400000);
+		os_val = VINDPM_OS_5900MV;
+		offset = 5900000;
+	} else if (vindpm >= 7500000 && vindpm < 10500000) {
+		vindpm = clamp(vindpm, VINDPM_OS_7500MV, 9000000);
+		os_val = VINDPM_OS_7500MV;
+		offset = 7500000;
+	} else {
+		vindpm = clamp(vindpm, VINDPM_OS_10500MV, 12000000);
+		os_val = VINDPM_OS_10500MV;
+		offset = 10500000;
+	}
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_F,
+				 SGM4154X_VINDPM_OS_MASK,
+				 os_val);
+	if (ret) {
+		dev_err(sgm->dev, "set vin dpm error!\n");
+		return ret;
+	}
+
+	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VINDPM_V_MASK, reg_val);
+	if (ret)
+		dev_err(sgm->dev, "input voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
+{
+	int reg_val;
+	int ret;
+
+	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Per the datasheet, values between 100000uA and 3100000uA work
+	 * as expected with the register defined as having a step of
+	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
+	 * The register value of 0x1f however corresponds to 3800000uA not
+	 * 3200000uA as one would expect.
+	 */
+	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
+		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
+
+	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
+		iindpm = 3100000;
+
+	if (iindpm == SGM4154X_IINDPM_I_MAX_UA)
+		reg_val = 0x1f;
+	else
+		reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_0,
+				 SGM4154X_IINDPM_I_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set input current limit error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int ilim;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
+	if (ret) {
+		dev_err(sgm->dev, "get input current limit error!\n");
+		return ret;
+	}
+
+	/* Max value is not 3200000uA as expected but is 3800000uA */
+	if (SGM4154X_IINDPM_I_MASK == (ilim & SGM4154X_IINDPM_I_MASK))
+		return SGM4154X_IINDPM_I_MAX_UA;
+
+	ilim = (ilim & SGM4154X_IINDPM_I_MASK) * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
+
+	return ilim;
+}
+
+static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_WDT_RST,
+				 SGM4154X_WDT_RST);
+
+	if (ret)
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, int time)
+{
+	u8 reg_val;
+	int ret;
+
+	if (time == 0)
+		reg_val = SGM4154X_WDT_TIMER_DISABLE;
+	else if (time == 40)
+		reg_val = SGM4154X_WDT_TIMER_40S;
+	else if (time == 80)
+		reg_val = SGM4154X_WDT_TIMER_80S;
+	else
+		reg_val = SGM4154X_WDT_TIMER_160S;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_5,
+				 SGM4154X_WDT_TIMER_MASK,
+				 reg_val);
+
+	if (ret) {
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+		return ret;
+	}
+
+	if (time) {
+		if (!sgm->watchdog_enable)
+			queue_delayed_work(sgm->sgm_monitor_wq,
+					   &sgm->sgm_delay_work,
+					   msecs_to_jiffies(1000 * 5));
+		sgm->watchdog_enable = true;
+	} else {
+		sgm->watchdog_enable = false;
+		sgm4154x_watchdog_timer_reset(sgm);
+	}
+
+	return ret;
+}
+
+static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 SGM4154X_CHRG_EN);
+	if (ret)
+		dev_err(sgm->dev, "enable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 0);
+	if (ret)
+		dev_err(sgm->dev, "disable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VAC_OVP_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set vac ovp error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_recharge_volt(struct sgm4154x_device *sgm, int recharge_volt)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VRECHARGE,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set recharger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_state(struct sgm4154x_device *sgm,
+			      struct sgm4154x_state *state)
+{
+	int reg, ret;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
+		return ret;
+	}
+	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
+	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
+	state->online = !!(reg & SGM4154X_PG_STAT);
+	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
+	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
+		return ret;
+	}
+	state->chrg_fault = reg;
+	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
+	state->health = state->ntc_fault;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
+		return ret;
+	}
+	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
+
+	return ret;
+}
+
+static int sgm4154x_property_is_writeable(struct power_supply *psy,
+					  enum power_supply_property prop)
+{
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int sgm4154x_charger_set_property(struct power_supply *psy,
+					 enum power_supply_property prop,
+					 const union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			ret = sgm4154x_enable_charger(sgm);
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
+		} else {
+			sgm4154x_set_watchdog_timer(sgm, 0);
+			ret = sgm4154x_disable_charger(sgm);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sgm4154x_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm, &state);
+	if (ret) {
+		dev_err(sgm->dev, "get state error!\n");
+		return ret;
+	}
+	sgm->state = state;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		else if (!state.chrg_stat)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		switch (state.chrg_stat) {
+		case SGM4154X_PRECHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_FAST_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		case SGM4154X_TERM_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_NOT_CHRGING:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		}
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = SGM4154X_MANUFACTURER;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SGM4154X_NAME;
+		break;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = state.online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = state.vbus_gd;
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		val->intval = sgm4154x_get_chrg_volt(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		val->intval = sgm4154x_get_ichrg_curr(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		val->intval = sgm->init_data.vlim;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		val->intval = sgm4154x_get_input_curr_lim(sgm);
+		if (val->intval < 0)
+			return  -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
+{
+	struct sgm4154x_device *sgm4154x = private;
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm4154x, &state);
+	if (ret) {
+		dev_err(sgm4154x->dev, "get state error!\n");
+		return IRQ_NONE;
+	}
+	sgm4154x->state = state;
+	if (state.vbus_gd) {
+		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
+			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
+			if (ret) {
+				dev_err(sgm4154x->dev, "set input current error!\n");
+				return IRQ_NONE;
+			}
+		}
+	}
+	power_supply_changed(sgm4154x->charger);
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property sgm4154x_power_supply_props[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_PRESENT
+};
+
+static char *sgm4154x_charger_supplied_to[] = {
+	"battery-monitor",
+};
+
+static struct power_supply_desc sgm4154x_power_supply_desc = {
+	.name = "sgm4154x-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = sgm4154x_power_supply_props,
+	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
+	.get_property = sgm4154x_charger_get_property,
+	.set_property = sgm4154x_charger_set_property,
+	.property_is_writeable = sgm4154x_property_is_writeable,
+};
+
+static const struct regmap_config sgm4154x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = SGM4154X_CHRG_CTRL_F,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
+				      struct device *dev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = sgm,
+					       .fwnode = dev->fwnode, };
+
+	psy_cfg.supplied_to = sgm4154x_charger_supplied_to;
+	psy_cfg.num_supplicants = ARRAY_SIZE(sgm4154x_charger_supplied_to);
+	psy_cfg.fwnode = dev->fwnode;
+	sgm->charger = devm_power_supply_register(sgm->dev,
+						  &sgm4154x_power_supply_desc,
+						  &psy_cfg);
+	if (IS_ERR(sgm->charger))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
+{
+	struct power_supply_battery_info *bat_info;
+	int ret;
+	u32 val;
+
+	/*
+	 * If unable to read devicetree info, use default/reset
+	 * values from hardware.
+	 */
+	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
+	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
+	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
+	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
+	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
+	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
+
+	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
+	if (ret)
+		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
+	else {
+		if (bat_info->constant_charge_current_max_ua)
+			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
+		if (bat_info->constant_charge_voltage_max_uv)
+			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
+		if (bat_info->charge_term_current_ua)
+			sgm->init_data.iterm = bat_info->charge_term_current_ua;
+		if (bat_info->precharge_current_ua)
+			sgm->init_data.iprechg = bat_info->precharge_current_ua;
+
+		power_supply_put_battery_info(sgm->charger, bat_info);
+	}
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-voltage-limit-microvolt",
+				       &val);
+	if (!ret)
+		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
+					    SGM4154X_VINDPM_V_MAX_UV);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-current-limit-microamp",
+				       &val);
+	if (!ret)
+		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
+					    SGM4154X_IINDPM_I_MAX_UA);
+
+	ret = sgm4154x_set_watchdog_timer(sgm, 0);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_vac_ovp(sgm);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_D,
+			   SGM4154X_JEITA_EN,
+			   0);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_IINDPM_INT_MASK,
+			   SGM4154X_IINDPM_INT_MASK);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_VINDPM_INT_MASK,
+			   SGM4154X_VINDPM_INT_MASK);
+
+	/*
+	 * Recharge voltage set to 200 by BSP driver instead of hardware
+	 * default value of 100.
+	 */
+	ret = sgm4154x_set_recharge_volt(sgm, 200);
+
+	return ret;
+}
+
+static const u32 sgm4154x_chg_otg_cur_ua[] = {
+	1200000, 2000000,
+};
+
+static const struct regulator_ops sgm4154x_vbus_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const struct regulator_desc sgm4154x_otg_rdesc = {
+	.of_match = "otg-vbus",
+	.name = "otg-vbus",
+	.regulators_node = of_match_ptr("regulators"),
+	.ops = &sgm4154x_vbus_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4850000,
+	.uV_step = 150000,
+	.n_voltages = 4,
+	.vsel_reg = SGM4154X_CHRG_CTRL_6,
+	.vsel_mask = SGM4154X_BOOSTV,
+	.enable_reg = SGM4154X_CHRG_CTRL_1,
+	.enable_mask = SGM4154X_OTG_EN,
+	.curr_table = sgm4154x_chg_otg_cur_ua,
+	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
+	.csel_reg = SGM4154X_CHRG_CTRL_2,
+	.csel_mask = SGM4154X_BOOST_LIM,
+};
+
+static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
+{
+	struct regulator_config config = {
+		.dev = sgm->dev,
+		.regmap = sgm->regmap,
+		.driver_data = sgm,
+	};
+
+	sgm->otg_rdev = devm_regulator_register(sgm->dev,
+						&sgm4154x_otg_rdesc,
+						&config);
+
+	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
+}
+
+static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
+	if (ret)
+		return ret;
+
+	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
+		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
+
+	return 0;
+}
+
+static void sgm_charger_work(struct work_struct *work)
+{
+	struct sgm4154x_device *sgm =
+		container_of(work,
+			     struct sgm4154x_device,
+			     sgm_delay_work.work);
+
+	sgm4154x_watchdog_timer_reset(sgm);
+	if (sgm->watchdog_enable)
+		queue_delayed_work(sgm->sgm_monitor_wq,
+				   &sgm->sgm_delay_work,
+				   msecs_to_jiffies(1000 * 5));
+}
+
+static int sgm4154x_probe(struct i2c_client *client)
+{
+	const struct i2c_device_id *id = i2c_client_get_device_id(client);
+	struct device *dev = &client->dev;
+	struct sgm4154x_device *sgm;
+	int ret;
+
+	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
+	if (!sgm)
+		return -ENOMEM;
+
+	sgm->client = client;
+	sgm->dev = dev;
+
+	strscpy(sgm->model_name, id->name, I2C_NAME_SIZE);
+
+	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
+	if (IS_ERR(sgm->regmap))
+		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
+				     "Failed to allocate register map\n");
+
+	i2c_set_clientdata(client, sgm);
+
+	ret = sgm4154x_hw_chipid_detect(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to read HW ID\n");
+
+	device_init_wakeup(dev, 1);
+
+	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "%s",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE, "sgm-monitor-wq");
+	if (!sgm->sgm_monitor_wq)
+		return -EINVAL;
+
+	ret = sgm4154x_power_supply_init(sgm, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register power supply\n");
+
+	ret = sgm4154x_hw_init(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						sgm4154x_irq_handler_thread,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						"sgm41542-irq", sgm);
+		if (ret)
+			return ret;
+
+		enable_irq_wake(client->irq);
+	}
+
+	INIT_DELAYED_WORK(&sgm->sgm_delay_work, sgm_charger_work);
+
+	ret = sgm4154x_vbus_regulator_register(sgm);
+	if (ret) {
+		disable_irq_wake(client->irq);
+		return dev_err_probe(dev, ret,
+				     "Unable to register VBUS regulator\n");
+	}
+
+	return 0;
+}
+
+static void sgm4154x_charger_shutdown(struct i2c_client *client)
+{
+	struct sgm4154x_device *sgm = i2c_get_clientdata(client);
+
+	sgm4154x_set_prechrg_curr(sgm, SGM4154X_PRECHRG_I_DEF_UA);
+	sgm4154x_disable_charger(sgm);
+}
+
+static const struct i2c_device_id sgm4154x_i2c_ids[] = {
+	{ "sgm41542" },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
+
+static const struct of_device_id sgm4154x_of_match[] = {
+	{ .compatible = "sgmicro,sgm41542", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
+
+static struct i2c_driver sgm4154x_driver = {
+	.driver = {
+		.name = "sgm4154x-charger",
+		.of_match_table = sgm4154x_of_match,
+	},
+	.probe = sgm4154x_probe,
+	.shutdown = sgm4154x_charger_shutdown,
+	.id_table = sgm4154x_i2c_ids,
+};
+
+module_i2c_driver(sgm4154x_driver);
+
+MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
+MODULE_DESCRIPTION("sgm4154x charger driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:10 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:10 -0500
Subject: [PATCH V4 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c | 254 ++++++++++++++++++
 3 files changed, 265 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d592f4f4b939..61dd00297ecc 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
 	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
 	  and RG-99 handheld gaming consoles.
 
+config DRM_PANEL_ANBERNIC_TD4310
+	tristate "Anbernic TD4310 LCD panel"
+	depends on GPIOLIB && OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here to enable support for Anbernic designed panels with the
+	  TD4310 panel controller such as the ones used on the Anbernic RG
+	  Vita Pro.
+
 config DRM_PANEL_ARM_VERSATILE
 	tristate "ARM Versatile panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a4291dc3905b..9d8f70c9de3e 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
 obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
new file mode 100644
index 000000000000..006716378a57
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Anbernic panels with TD4310 panel controller.
+ *
+ * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/mipi_display.h>
+
+struct anbernic_panel_td4310_info {
+	const struct drm_display_mode *display_mode;
+	u16 width_mm;
+	u16 height_mm;
+	u32 bus_flags;
+	unsigned long mode_flags;
+	u32 format;
+	u32 lanes;
+	u16 prepare_delay;
+	u16 reset_delay;
+	u16 init_delay;
+	u16 enable_delay;
+	u16 disable_delay;
+	u16 unprepare_delay;
+};
+
+struct anbernic_panel_td4310 {
+	struct device *dev;
+	struct mipi_dsi_device *dsi;
+	struct drm_panel panel;
+	const struct anbernic_panel_td4310_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	struct regulator *vdd;
+	enum drm_panel_orientation orientation;
+};
+
+static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
+{
+	return container_of(panel, struct anbernic_panel_td4310, panel);
+}
+
+static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+	int ret;
+
+	ret = regulator_enable(ctx->vdd);
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+	if (ret)
+		goto err_enable;
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	mipi_dsi_msleep(&dsi_ctx, 10);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	if (ret)
+		goto err_reset;
+	if (ctx->panel_info->reset_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	if (ret)
+		goto err_reset;
+
+	if (ctx->panel_info->enable_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+
+	if (dsi_ctx.accum_err)
+		goto err_reset;
+
+	return 0;
+
+err_reset:
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+err_enable:
+	regulator_disable(ctx->vdd);
+	return ret;
+}
+
+static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->unprepare_delay);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->disable_delay);
+
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	regulator_disable(ctx->vdd);
+
+	return 0;
+}
+
+static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
+				    struct drm_connector *connector)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
+
+	connector->display_info.bpc = 8;
+	connector->display_info.width_mm = panel_info->width_mm;
+	connector->display_info.height_mm = panel_info->height_mm;
+	connector->display_info.bus_flags = panel_info->bus_flags;
+
+	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
+}
+
+static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+
+	return ctx->orientation;
+}
+
+static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
+	.prepare = panel_anbernic_td4310_prepare,
+	.unprepare = panel_anbernic_td4310_unprepare,
+	.get_modes = panel_anbernic_td4310_get_mode,
+	.get_orientation = panel_anbernic_td4310_get_orientation,
+};
+
+static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct anbernic_panel_td4310 *ctx;
+	int ret;
+
+	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
+				   &panel_anbernic_td4310_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ctx->dev = dev;
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	if (!ctx->panel_info)
+		return -EINVAL;
+
+	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Cannot get reset gpio\n");
+
+	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
+	if (IS_ERR(ctx->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+				     "Cannot get enable gpio\n");
+
+	ctx->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(ctx->vdd))
+		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
+				     "Failed to request vdd regulator\n");
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	dsi->lanes = ctx->panel_info->lanes;
+	dsi->format = ctx->panel_info->format;
+	dsi->mode_flags = ctx->panel_info->mode_flags;
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	devm_drm_panel_add(dev, &ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+
+	return 0;
+}
+
+static const struct drm_display_mode anbernic_vitapro_mode = {
+	.clock = 140020,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 50,
+	.hsync_end = 1080 + 50 + 4,
+	.htotal = 1080 + 50 + 4 + 50,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 15,
+	.vsync_end = 1920 + 15 + 4,
+	.vtotal = 1920 + 15 + 4 + 32,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
+	.display_mode = &anbernic_vitapro_mode,
+	.width_mm = 69,
+	.height_mm = 121,
+	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
+		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+	.prepare_delay = 50,
+	.reset_delay = 220,
+	.enable_delay = 120,
+	.disable_delay = 50,
+	.unprepare_delay = 20,
+};
+
+static const struct of_device_id panel_anbernic_td4310_of_match[] = {
+	{
+		.compatible = "anbernic,panel-vita-pro",
+		.data = &anbernic_vitapro_info,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
+
+static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
+	.driver = {
+		.name = "panel-anbernic-td4310",
+		.of_match_table = panel_anbernic_td4310_of_match,
+	},
+	.probe	= panel_anbernic_td4310_probe,
+};
+module_mipi_dsi_driver(anbernic_panel_td4310_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:09 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:09 -0500
Subject: [PATCH V4 3/6] dt-bindings: display: panel: document Anbernic TD4310 panel
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
new file mode 100644
index 000000000000..6f7f92b9c860
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Anbernic TD4310 Based Panels
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+
+description:
+  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
+  (a 1080x1920 5.5 inch panel).
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - anbernic,panel-vita-pro
+      - const: anbernic,td4310
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: Panel power supply
+
+required:
+  - compatible
+  - port
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel at 0 {
+            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+            reg = <0>;
+            backlight = <&backlight>;
+            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+            rotation = <270>;
+            vdd-supply = <&vdd_lcd>;
+
+            port {
+                panel_in: endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:11 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:11 -0500
Subject: [PATCH V4 5/6] dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add compatible string for the Anbernic RG Vita-Pro.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b8babe9d3a26 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -66,6 +66,12 @@ properties:
               - anbernic,rg-ds
           - const: rockchip,rk3568
 
+      - description: Anbernic RK3576 Handheld Gaming Console
+        items:
+          - enum:
+              - anbernic,rg-vita-pro
+          - const: rockchip,rk3576
+
       - description: Ariaboard Photonicat
         items:
           - const: ariaboard,photonicat
-- 
2.43.0



From macroalpha82 at gmail.com  Tue Jun  2 14:25:12 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Tue,  2 Jun 2026 16:25:12 -0500
Subject: [PATCH V4 6/6] arm64: dts: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260602212512.418166-1-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
Message-ID: <20260602212512.418166-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add device tree for the Anbernic RG Vita-Pro, based on the Rockchip
RK3576. All hardware is currently working except for the accelerometer,
the touchscreen, the battery monitor, and DisplayPort over USB-C. PWM
is also missing currently, and as a result the LEDs and panel backlight
are currently controlled via GPIO but will be changed to PWM once
supported.

The Anbernic RG Vita-Pro includes the following hardware:
 - A 1080x1920 DSI display with touch.
 - 21 buttons.
 - 2 Analog joysticks controlled via userspace.
 - 3 LEDs.
 - 64GB eMMC, 2 SDMMC slots.
 - RTL8852BE WiFi/Bluetooth combo
 - 1 USB 3.0 USB-C port in OTG mode.
 - 3.5mm headphone jack with play button support.
 - 5000mAH battery

The following hardware has incomplete driver support and is not yet
working:
 - An Invensense icm42607p accelerometer.
 - A Cellwise cw221x battery monitor.
 - A Synaptics i2c touchscreen.
 - DisplayPort over USB-C alt-mode.
 - PWM controller.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 2 files changed, 1328 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..7d86676f98e8 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-100ask-dshanpi-a1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-anbernic-rg-vita-pro.dtb
 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
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
new file mode 100644
index 000000000000..344ba1870533
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2026 Chris Morgan <macromorgan at hotmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+
+#include "rk3576.dtsi"
+
+/ {
+	model = "Anbernic RG Vita Pro";
+	chassis-type = "handset";
+	compatible = "anbernic,rg-vita-pro", "rockchip,rk3576";
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	adc_keys_home: adc-keys-home {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 1>;
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <60>;
+
+		button-home {
+			label = "HOME";
+			linux,code = <KEY_HOME>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	adc_keys_play: adc-keys-play {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 3>;
+		keyup-threshold-microvolt = <1300000>;
+		poll-interval = <60>;
+
+		button-play {
+			label = "PLAY";
+			linux,code = <KEY_PLAYPAUSE>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	/*
+	 * Battery values from BSP except for the following:
+	 *
+	 * factory-internal-resistance-micro-ohms - This was set to 80 which
+	 * is likely incorrect and changed to 80000.
+	 *
+	 * charge-full-design-microamp-hours - Was set to 8000000 but the
+	 * physical battery says 5000000.
+	 *
+	 * constant-charge-current-max-microamp - Was set to 10000000 which
+	 * both seems high and exceeds what the charger hardware can do.
+	 * Setting to 3800000 which is the maximum input current the charger
+	 * can handle.
+	 */
+	battery: battery {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <5000000>;
+		charge-term-current-microamp = <300000>;
+		constant-charge-current-max-microamp = <3800000>;
+		constant-charge-voltage-max-microvolt = <4350000>;
+		factory-internal-resistance-micro-ohms = <80000>;
+		precharge-current-microamp = <180000>;
+		precharge-upper-limit-microvolt = <3600000>;
+		voltage-max-design-microvolt = <4350000>;
+		voltage-min-design-microvolt = <3000000>;
+	};
+
+	hp_amp: audio-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&hp_amp_enable_h>;
+		pinctrl-names = "default";
+		sound-name-prefix = "Headphone Amp";
+	};
+
+	/*
+	 * LEDs and Backlights can be controlled as a PWM, but PWM
+	 * driver is not yet available.
+	 */
+	gpio_backlight: backlight {
+		compatible = "gpio-backlight";
+		gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&led_backlight_h>;
+		pinctrl-names = "default";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_amber_h>, <&led_green_h>, <&led_red_h>;
+		pinctrl-names = "default";
+
+		charging-led {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_CHARGING;
+			gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
+		};
+
+		full-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
+		};
+
+		bat-low-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_ALARM;
+			gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio_keys_control: gpio-keys-control {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&gamepad_keys_l>;
+		pinctrl-names = "default";
+
+		button-a {
+			gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
+			label = "EAST";
+			linux,code = <BTN_EAST>;
+		};
+
+		button-b {
+			gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+			label = "SOUTH";
+			linux,code = <BTN_SOUTH>;
+		};
+
+		button-down {
+			gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+			label = "DPAD-DOWN";
+			linux,code = <BTN_DPAD_DOWN>;
+		};
+
+		button-l1 {
+			gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>;
+			label = "TL";
+			linux,code = <BTN_TL>;
+		};
+
+		button-l2 {
+			gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+			label = "TL2";
+			linux,code = <BTN_TL2>;
+		};
+
+		button-left {
+			gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+			label = "DPAD-LEFT";
+			linux,code = <BTN_DPAD_LEFT>;
+		};
+
+		button-menu {
+			gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+			label = "MENU";
+			linux,code = <BTN_MODE>;
+		};
+
+		button-right {
+			gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+			label = "DPAD-RIGHT";
+			linux,code = <BTN_DPAD_RIGHT>;
+		};
+
+		button-r1 {
+			gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+			label = "T2";
+			linux,code = <BTN_TR>;
+		};
+
+		button-r2 {
+			gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+			label = "TR2";
+			linux,code = <BTN_TR2>;
+		};
+
+		button-select {
+			gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>;
+			label = "SELECT";
+			linux,code = <BTN_SELECT>;
+		};
+
+		button-start {
+			gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>;
+			label = "START";
+			linux,code = <BTN_START>;
+		};
+
+		button-thumbl {
+			gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+			label = "THUMBL";
+			linux,code = <BTN_THUMBL>;
+		};
+
+		button-thumbr {
+			gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>;
+			label = "THUMBR";
+			linux,code = <BTN_THUMBR>;
+		};
+
+		button-up {
+			gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+			label = "DPAD-UP";
+			linux,code = <BTN_DPAD_UP>;
+		};
+
+		button-x {
+			gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+			label = "NORTH";
+			linux,code = <BTN_NORTH>;
+		};
+
+		button-y {
+			gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+			label = "WEST";
+			linux,code = <BTN_WEST>;
+		};
+	};
+
+	gpio_keys_volume: gpio-keys-volume {
+		compatible = "gpio-keys";
+		autorepeat;
+		pinctrl-0 = <&vol_keys_l>;
+		pinctrl-names = "default";
+
+		vol-down-key {
+			gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEDOWN";
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+
+		vol-up-key {
+			gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEUP";
+			linux,code = <KEY_VOLUMEUP>;
+		};
+	};
+
+	hdmi-con {
+		compatible = "hdmi-connector";
+		type = "c";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_h>;
+		radio-type = "wlan";
+		shutdown-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+
+	sound: sound {
+		compatible = "simple-audio-card";
+		pinctrl-0 = <&hp_det>;
+		pinctrl-names = "default";
+		simple-audio-card,aux-devs = <&aw87391_pa_l>, <&aw87391_pa_r>,
+					     <&hp_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "rockchip,es8388-codec";
+		simple-audio-card,pin-switches = "Headphones", "Internal Speakers";
+		simple-audio-card,routing =
+			"LINPUT1", "Mic Jack",
+			"LINPUT2", "Mic Jack",
+			"RINPUT1", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone",
+			"Headphones", "Headphone Amp OUTL",
+			"Headphones", "Headphone Amp OUTR",
+			"Headphone Amp INL", "LOUT1",
+			"Headphone Amp INR", "ROUT1",
+			"Internal Speakers", "Left Amp OUT",
+			"Internal Speakers", "Right Amp OUT",
+			"Left Amp IN", "LOUT2",
+			"Right Amp IN", "ROUT2";
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Internal Speakers";
+		status = "okay";
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1100000>;
+		regulator-min-microvolt = <1100000>;
+		regulator-name = "vcc_1v1_nldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <2000000>;
+		regulator-min-microvolt = <2000000>;
+		regulator-name = "vcc_2v0_pldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_3v8_sys: regulator-vcc-3v8-sys {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <3800000>;
+		regulator-min-microvolt = <3800000>;
+		regulator-name = "vcc_3v8_sys";
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_3v3_sd_s0_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc_sdio: regulator-vcc-sdio {
+		compatible = "regulator-gpio";
+		regulator-name = "vcc_sdio";
+		gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_sdio_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <1800000>;
+		states = <1800000 0>, <3300000 1>;
+	};
+
+	vcc_wifi: regulator-vcc-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_wifi";
+		enable-active-high;
+		gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_wifi_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vdd_lcd: regulator-vdd-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_lcd";
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vdd_lcd_h>;
+		pinctrl-names = "default";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&dsi {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	panel: panel at 0 {
+		compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+		reg = <0>;
+		backlight = <&gpio_backlight>;
+		enable-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable>, <&lcd_rst>;
+		reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
+		rotation = <270>;
+		vdd-supply = <&vdd_lcd>;
+
+		port {
+			mipi_in_panel: endpoint {
+				remote-endpoint = <&mipi_out_panel>;
+			};
+		};
+	};
+};
+
+&dsi_in {
+	dsi_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dsi>;
+	};
+};
+
+&dsi_out {
+	mipi_out_panel: endpoint {
+		remote-endpoint = <&mipi_in_panel>;
+	};
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&hdmi_sound {
+	status = "okay";
+};
+
+&hdptxphy {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m1_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	/* synaptics,dsx-i2c touchscreen at 0x70 */
+};
+
+&i2c1 {
+	status = "okay";
+
+	pmic at 23 {
+		compatible = "rockchip,rk806";
+		reg = <0x23>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins
+			     &rk806_dvs1_null
+			     &rk806_dvs2_null
+			     &rk806_dvs3_null>;
+		system-power-controller;
+		vcc1-supply = <&vcc_3v8_sys>;
+		vcc2-supply = <&vcc_3v8_sys>;
+		vcc3-supply = <&vcc_3v8_sys>;
+		vcc4-supply = <&vcc_3v8_sys>;
+		vcc5-supply = <&vcc_3v8_sys>;
+		vcc6-supply = <&vcc_3v8_sys>;
+		vcc7-supply = <&vcc_3v8_sys>;
+		vcc8-supply = <&vcc_3v8_sys>;
+		vcc9-supply = <&vcc_3v8_sys>;
+		vcc10-supply = <&vcc_3v8_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc_3v8_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc_3v8_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_pwrdn: dvs1-pwrdn-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: dvs1-rst-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs1_slp: dvs1-slp-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_dvs: dvs2-dvs-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: dvs2-gpio-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_pwrdn: dvs2-pwrdn-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: dvs2-rst-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_slp: dvs2-slp-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_dvs: dvs3-dvs-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: dvs3-gpio-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_pwrdn: dvs3-pwrdn-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: dvs3-rst-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_slp: dvs3-slp-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		regulators {
+			vdd_cpu_big_s0: dcdc-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_big_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_npu_s0: dcdc-reg2 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_npu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vdd_gpu_s0: dcdc-reg5 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_logic_s0: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <800000>;
+				regulator-name = "vdd_logic_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdd_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo2_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdda_1v2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcca_3v3_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo6_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdda_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_ddr_pll_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v75_hdmi_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda0v75_hdmi_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_0v85_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda_0v75_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	/* inv,icm42607 IMU at 0x68 */
+};
+
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		assigned-clock-rates = <12288000>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		DVDD-supply = <&vcc_3v3_s3>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		pinctrl-0 = <&sai1m0_mclk>;
+		pinctrl-names = "default";
+		PVDD-supply = <&vcc_3v3_s3>;
+		#sound-dai-cells = <0>;
+	};
+
+	aw87391_pa_l: audio-codec at 58 {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x58>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Left Amp";
+	};
+
+	aw87391_pa_r: audio-codec at 5b {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x5b>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Right Amp";
+	};
+};
+
+&i2c6 {
+	pinctrl-0 = <&i2c6m3_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	sgm41542: charger at 3b {
+		compatible = "sgmicro,sgm41542";
+		reg = <0x3b>;
+		input-current-limit-microamp = <3000000>;
+		input-voltage-limit-microvolt = <4500000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-0 = <&charger_irq>;
+		pinctrl-names = "default";
+		monitored-battery = <&battery>;
+		status = "okay";
+
+		regulators {
+			vbus5v0_typec: otg-vbus {
+				regulator-name = "vbus5v0_typec";
+				regulator-max-microvolt = <5000000>;
+				regulator-min-microvolt = <5000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+
+	/* Unused iSmartWare SW2001 encryption device at 0x3c */
+
+	husb311: typec-portc at 4e {
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD1 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&usbc_int>;
+		pinctrl-names = "default";
+		status = "okay";
+		vbus-supply = <&vbus5v0_typec>;
+
+		connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			op-sink-microwatt = <10000000>;
+			power-role = "dual";
+			try-power-role  = "sink";
+
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_FIXED(9000, 2000, PDO_FIXED_USB_COMM)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs_ep: endpoint {
+						remote-endpoint = <&usb_drd0_hs_ep>;
+					};
+				};
+				port at 1 {
+					reg = <1>;
+					usbc0_ss_ep: endpoint {
+						remote-endpoint = <&usb_drd0_ss_ep>;
+					};
+				};
+				port at 2 {
+					reg = <2>;
+					usbc0_dp_ep: endpoint {
+						remote-endpoint = <&usbdp_phy_ep>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hym8563_int>;
+		wakeup-source;
+	};
+
+	/* cellwise,cw221X battery manager at 0x64 */
+};
+
+&mipidcphy {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_perstn>;
+	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_wifi>;
+	status = "okay";
+};
+
+&pinctrl {
+	audio {
+		hp_amp_enable_h: hp-amp-enable {
+			rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_det: hp-det {
+			rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	bluetooth {
+		bt_reset_gpio: bt-reset-pin {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_gpio: bt-wake-pin {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_host_irq: bt-wake-host-irq {
+			rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	charger {
+		charger_irq: charger-irq {
+			rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	display {
+		lcd_enable: lcd-enable {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		lcd_rst: lcd-rst {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	gpio-keys {
+		vol_keys_l: vol-keys_l {
+			rockchip,pins =
+				<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		gamepad_keys_l: gamepad-keys-l {
+			rockchip,pins =
+				<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	gpio-leds {
+		led_amber_h: led-amber-h {
+			rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_backlight_h: led-backlight-h {
+			rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_green_h: led-green-h {
+			rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_red_h: led-red-h {
+			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie0_perstn: pcie0-perstn {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	regulator {
+		vcc_3v3_sd_s0_h: vcc-3v3-sd-s0-h {
+			rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_sdio_h: vcc-sdio-h {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_wifi_h: vcc-wifi-h {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vdd_lcd_h: vdd-lcd-h {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtc {
+		hym8563_int: hym8563-int {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	touch {
+		touch_int: touch-int {
+			rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		usbc_int: usbc-int {
+			rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		usbc0_sbu1: usbc0-sbu1 {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		usbc0_sbu2: usbc0-sbu2 {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	wifi {
+		wifi_en_h: wifi-en-h {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sai1 {
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai6 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
+&sdio {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&sdmmc1m0_bus4>, <&sdmmc1m0_clk>,
+		    <&sdmmc1m0_cmd>, <&sdmmc1m0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vcc_sdio>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	no-sd;
+	no-sdio;
+	non-removable;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>,
+		    <&sdmmc0_cmd>, <&sdmmc0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi1 {
+	num-cs = <1>;
+	pinctrl-0 = <&spi1m2_pins>, <&spi1m2_csn0>;
+	status = "okay";
+
+	/* SPI controlled MCU for joystick and joystick LEDs. */
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_dsi: endpoint at ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi_in_vp1>;
+	};
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m1_xfer>, <&uart6m1_ctsn>, <&uart6m1_rtsn>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "realtek,rtl8822cs-bt";
+		device-wake-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		host-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&bt_reset_gpio>, <&bt_wake_gpio>, <&bt_wake_host_irq>;
+		pinctrl-names = "default";
+	};
+};
+
+&usbdp_phy {
+	mode-switch;
+	orientation-switch;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbc0_sbu1 &usbc0_sbu2>;
+	sbu1-dc-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		usbdp_phy_ep: endpoint {
+			remote-endpoint = <&usbc0_dp_ep>;
+		};
+	};
+};
+
+&usb_drd0_dwc3 {
+	usb-role-switch;
+	dr_mode = "otg";
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_drd0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_drd0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss_ep>;
+			};
+		};
+	};
+};
-- 
2.43.0



From chaoyi.chen at rock-chips.com  Tue Jun  2 18:28:44 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Wed, 3 Jun 2026 09:28:44 +0800
Subject: [PATCH 1/2] drm/rockchip: dsi: Add maximum per lane bit rate
 calculation
In-Reply-To: <4888940.6M6d0yLqnL@phil>
References: <20260324085838.90-1-kernel@airkyi.com> <4888940.6M6d0yLqnL@phil>
Message-ID: <91378132-8a8e-4bcc-9aa7-4de9fb135a6a@rock-chips.com>

Hi Heiko,

On 6/3/2026 4:59 AM, Heiko Stuebner wrote:
> Am Dienstag, 24. M?rz 2026, 09:58:37 Mitteleurop?ische Sommerzeit schrieb Chaoyi Chen:
>> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>>
>> Different chips have varying support for the maximum bit rate per lane.
>>
>> Add calculation for the maximum per lane bit rate for various chip
>> platforms, and relax the bandwidth margin requirements.
>>
>> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>> ---
>>  .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 21 +++++++++++++++----
>>  1 file changed, 17 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> index 3547d91b25d3..d3bacfae174e 100644
>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> @@ -268,6 +268,7 @@ struct rockchip_dw_dsi_chip_data {
>>  
>>  	unsigned int flags;
>>  	unsigned int max_data_lanes;
>> +	unsigned long max_bit_rate_per_lane;
>>  };
>>  
>>  struct dw_mipi_dsi_rockchip {
>> @@ -565,7 +566,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>>  	int bpp;
>>  	unsigned long mpclk, tmp;
>>  	unsigned int target_mbps = 1000;
>> -	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
>> +	unsigned int max_mbps;
>>  	unsigned long best_freq = 0;
>>  	unsigned long fvco_min, fvco_max, fin, fout;
>>  	unsigned int min_prediv, max_prediv;
>> @@ -573,6 +574,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>>  	unsigned long _fbdiv, best_fbdiv;
>>  	unsigned long min_delta = ULONG_MAX;
>>  
>> +	max_mbps = dsi->cdata->max_bit_rate_per_lane;
> 
> I may be blind, but how do the values come together?
> In the dppa_map table we have mbps values of 89 to 1500
> (MHz)
> 
> While below the values set are
> 	.max_bit_rate_per_lane = 1500000000UL,
> in Hz I guess
> 
> And I don't see the needed conversion somehow.
> 
>

Oh! It should be:

max_mbps = dsi->cdata->max_bit_rate_per_lane / USEC_PER_SEC;

Will fix in v2.

>>  	dsi->format = format;
>>  	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
>>  	if (bpp < 0) {
>> @@ -584,8 +586,8 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
>>  
>>  	mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
>>  	if (mpclk) {
>> -		/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
>> -		tmp = mpclk * (bpp / lanes) * 10 / 8;
>> +		/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
>> +		tmp = mpclk * (bpp / lanes) * 10 / 9;
> 
> Please do this in a separate patch, especially as I would expect some
> sort of explanation on why this is ok to do.
>

Sure! I'll split this out in the new series.

-- 
Best, 
Chaoyi


From chaoyi.chen at rock-chips.com  Tue Jun  2 18:34:27 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Wed, 3 Jun 2026 09:34:27 +0800
Subject: [PATCH 2/2] drm/rockchip: dsi: Add dphy_get_timing support for
 multiple PHY types
In-Reply-To: <7091445.e8TTKsaY2g@phil>
References: <20260324085838.90-1-kernel@airkyi.com>
 <20260324085838.90-2-kernel@airkyi.com> <7091445.e8TTKsaY2g@phil>
Message-ID: <a473c5a2-b1f9-4cf8-85bb-d3ec1572cbe8@rock-chips.com>

Hi Heiko,

On 6/3/2026 5:02 AM, Heiko Stuebner wrote:
> Am Dienstag, 24. M?rz 2026, 09:58:38 Mitteleurop?ische Sommerzeit schrieb Chaoyi Chen:
>> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>>
>> Currently, there are generally two types of DPHY for Rockchip. One is
>> the DPHY used by RK3288/RK3399, whose timing is described by Table A-3
>> High-Speed Transition Times in the databook. The other is the DPHY used
>> by PX30 and its successors. If its timing is still described using
>> RK3288/RK3399, it may not perform correctly on some DSI panel.
>>
>> Add dphy_get_timing for different D-PHY types to adapt to timing
>> differences.
>>
>> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>> ---
>>  .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 45 ++++++++++++++++++-
>>  1 file changed, 43 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> index d3bacfae174e..2d1c9e54ff85 100644
>> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
>> @@ -247,6 +247,7 @@ enum {
>>  	BIASEXTR_127_7,
>>  };
>>  
>> +struct dw_mipi_dsi_rockchip;
>>  struct rockchip_dw_dsi_chip_data {
>>  	u32 reg;
>>  
>> @@ -262,6 +263,9 @@ struct rockchip_dw_dsi_chip_data {
>>  	u32 lanecfg2_grf_reg;
>>  	u32 lanecfg2;
>>  
>> +	int (*dphy_get_timing)(struct dw_mipi_dsi_rockchip *dsi, unsigned int lane_mbps,
>> +			       struct dw_mipi_dsi_dphy_timing *timing);
>> +
>>  	int (*dphy_rx_init)(struct phy *phy);
>>  	int (*dphy_rx_power_on)(struct phy *phy);
>>  	int (*dphy_rx_power_off)(struct phy *phy);
>> @@ -721,8 +725,9 @@ static struct hstt hstt_table[] = {
>>  };
>>  
>>  static int
>> -dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
>> -			   struct dw_mipi_dsi_dphy_timing *timing)
>> +dw_mipi_dsi_phy_rk3288_get_timing(struct dw_mipi_dsi_rockchip *dsi,
>> +				  unsigned int lane_mbps,
>> +				  struct dw_mipi_dsi_dphy_timing *timing)
>>  {
>>  	int i;
>>  
>> @@ -738,6 +743,32 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
>>  	return 0;
>>  }
>>  
>> +static const struct dw_mipi_dsi_dphy_timing dphy_timing_px30 = {
>> +	.clk_lp2hs = 0x40,
>> +	.clk_hs2lp = 0x40,
>> +	.data_lp2hs = 0x10,
>> +	.data_hs2lp = 0x14,
>> +};
> 
> so just to make sure, the timing on the px30 (and later) variant is the
> same for all lane speeds?
>

More precisely, it applies to this fixed value for INNO PHY used after PX30.

> Please include that bit in the commit description
> 

I will add more details in v2. Thank you!

-- 
Best, 
Chaoyi


From kernel at airkyi.com  Tue Jun  2 20:35:29 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Wed,  3 Jun 2026 11:35:29 +0800
Subject: [PATCH v2 0/3] DSI Controller improvements for Rockchip platforms
Message-ID: <20260603033532.164-1-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This series is dedicated to enhancing the DSI controller and PHY timing
interaction, refining the lane rate calculation, and addressing the
associated hardware limitations.

Changes in v2:
- Link to v1: https://lore.kernel.org/all/20260324085838.90-1-kernel at airkyi.com/
- Fix the unit conversion for max_mbps.
- Split the lane rate calculation into a separate patch.
- Add more comment about timing config.

Chaoyi Chen (3):
  drm/rockchip: dsi: Add maximum per lane bit rate calculation
  drm/rockchip: dsi: Add dphy_get_timing support for multiple PHY types
  drm/rockchip: dsi: Relax the lane rate margin requirements

 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 66 +++++++++++++++++--
 1 file changed, 60 insertions(+), 6 deletions(-)

-- 
2.53.0



From kernel at airkyi.com  Tue Jun  2 20:35:30 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Wed,  3 Jun 2026 11:35:30 +0800
Subject: [PATCH v2 1/3] drm/rockchip: dsi: Add maximum per lane bit rate calculation
In-Reply-To: <20260603033532.164-1-kernel@airkyi.com>
References: <20260603033532.164-1-kernel@airkyi.com>
Message-ID: <20260603033532.164-2-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Different chips have varying support for the maximum bit rate per lane.

Add calculation for the maximum per lane bit rate for various chip
platforms.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---
Changes in v2:
- Fix the unit conversion for max_mbps.
- Split the lane rate calculation into a separate patch.

---
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 3547d91b25d3..1060abec9f29 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -268,6 +268,7 @@ struct rockchip_dw_dsi_chip_data {
 
 	unsigned int flags;
 	unsigned int max_data_lanes;
+	unsigned long max_bit_rate_per_lane;
 };
 
 struct dw_mipi_dsi_rockchip {
@@ -565,7 +566,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
 	int bpp;
 	unsigned long mpclk, tmp;
 	unsigned int target_mbps = 1000;
-	unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
+	unsigned int max_mbps;
 	unsigned long best_freq = 0;
 	unsigned long fvco_min, fvco_max, fin, fout;
 	unsigned int min_prediv, max_prediv;
@@ -573,6 +574,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
 	unsigned long _fbdiv, best_fbdiv;
 	unsigned long min_delta = ULONG_MAX;
 
+	max_mbps = dsi->cdata->max_bit_rate_per_lane / USEC_PER_SEC;
 	dsi->format = format;
 	bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
 	if (bpp < 0) {
@@ -1503,6 +1505,7 @@ static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = {
 						PX30_DSI_FORCETXSTOPMODE), 0),
 
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1000000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1515,6 +1518,7 @@ static const struct rockchip_dw_dsi_chip_data rk3128_chip_data[] = {
 						RK3128_DSI_FORCERXMODE |
 						RK3128_DSI_FORCETXSTOPMODE), 0),
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1000000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1527,6 +1531,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
 		.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI0_LCDC_SEL, 1),
 
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1500000000UL,
 	},
 	{
 		.reg = 0xff964000,
@@ -1535,6 +1540,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
 		.lcdsel_lit = FIELD_PREP_WM16_CONST(RK3288_DSI1_LCDC_SEL, 1),
 
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1500000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1547,6 +1553,7 @@ static const struct rockchip_dw_dsi_chip_data rk3368_chip_data[] = {
 						RK3368_DSI_FORCETXSTOPMODE |
 						RK3368_DSI_FORCERXMODE), 0),
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1500000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1634,6 +1641,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
 
 		.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1500000000UL,
 	},
 	{
 		.reg = 0xff968000,
@@ -1658,6 +1666,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
 
 		.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1500000000UL,
 
 		.dphy_rx_init = rk3399_dphy_tx1rx1_init,
 		.dphy_rx_power_on = rk3399_dphy_tx1rx1_power_on,
@@ -1674,6 +1683,7 @@ static const struct rockchip_dw_dsi_chip_data rk3506_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RK3506_DSI_FORCERXMODE, 0) |
 			     FIELD_PREP_WM16_CONST(RK3506_DSI_FORCETXSTOPMODE, 0)),
 		.max_data_lanes = 2,
+		.max_bit_rate_per_lane = 1500000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1687,6 +1697,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RK3568_DSI0_TURNDISABLE, 0) |
 			     FIELD_PREP_WM16_CONST(RK3568_DSI0_FORCERXMODE, 0)),
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1200000000UL,
 	},
 	{
 		.reg = 0xfe070000,
@@ -1696,6 +1707,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RK3568_DSI1_TURNDISABLE, 0) |
 			     FIELD_PREP_WM16_CONST(RK3568_DSI1_FORCERXMODE, 0)),
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1200000000UL,
 	},
 	{ /* sentinel */ }
 };
@@ -1708,6 +1720,7 @@ static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RV1126_DSI_FORCERXMODE, 0) |
 			     FIELD_PREP_WM16_CONST(RV1126_DSI_FORCETXSTOPMODE, 0)),
 		.max_data_lanes = 4,
+		.max_bit_rate_per_lane = 1000000000UL,
 	},
 	{ /* sentinel */ }
 };
-- 
2.53.0



From kernel at airkyi.com  Tue Jun  2 20:35:32 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Wed,  3 Jun 2026 11:35:32 +0800
Subject: [PATCH v2 3/3] drm/rockchip: dsi: Relax the lane rate margin requirements
In-Reply-To: <20260603033532.164-1-kernel@airkyi.com>
References: <20260603033532.164-1-kernel@airkyi.com>
Message-ID: <20260603033532.164-4-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

The lane rate is calculated as follows:

	Lane_Rate = Pixel_Clk * BPP / lanes * Overhead

The overhead factor is set to 1/0.8, equivalent to a 25% overhead.

Now let's consider the case of RGB888 (BPP24) with a pclk of 148.5MHz.
The lane rate equals 148.5M * 24 / 4 * 1.25 = 1113.75 Mbps.

However, this is beyond the capability of certain platforms limited to a
1Gbps lane rate. On the other hand, we have observed that some DSI panel
actually perform worse with higher overhead.

So we are considering relaxing the bandwidth margin requirements.
According to the downstream test results, adopting 1/0.9 seems to
be a sound approach, corresponding to an overhead of about 11%.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index e64dfc327891..8af9d6934d27 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -590,8 +590,8 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
 
 	mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC);
 	if (mpclk) {
-		/* take 1 / 0.8, since mbps must big than bandwidth of RGB */
-		tmp = mpclk * (bpp / lanes) * 10 / 8;
+		/* take 1 / 0.9, since mbps must big than bandwidth of RGB */
+		tmp = mpclk * (bpp / lanes) * 10 / 9;
 		if (tmp < max_mbps)
 			target_mbps = tmp;
 		else
@@ -601,7 +601,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
 
 	/* for external phy only a the mipi_dphy_config is necessary */
 	if (dsi->phy) {
-		phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 8,
+		phy_mipi_dphy_get_default_config(mode->clock * 1000 * 10 / 9,
 						 bpp, lanes,
 						 &dsi->phy_opts.mipi_dphy);
 		dsi->lane_mbps = target_mbps;
-- 
2.53.0



From kernel at airkyi.com  Tue Jun  2 20:35:31 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Wed,  3 Jun 2026 11:35:31 +0800
Subject: [PATCH v2 2/3] drm/rockchip: dsi: Add dphy_get_timing support for multiple PHY types
In-Reply-To: <20260603033532.164-1-kernel@airkyi.com>
References: <20260603033532.164-1-kernel@airkyi.com>
Message-ID: <20260603033532.164-3-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

Currently, there are generally two types of DPHY for Rockchip. One is
the DPHY used by RK3288/RK3399, whose timing is described by Table A-3
High-Speed Transition Times in the databook. The other is the DPHY used
by PX30 and its successors. If its timing is still described using
RK3288/RK3399, it may not perform correctly on some DSI panel.

Add dphy_get_timing for different D-PHY types to adapt to timing
differences. The configuration details are as follows:

- RK3288/RK3399: Select the corresponding entry from the timing table based
                 on the data rate.
- PX30 and later platforms: Use a fixed timing configuration.

Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
---
Changes in v2:
- Add more comment about timing config.

---
 .../gpu/drm/rockchip/dw-mipi-dsi-rockchip.c   | 45 ++++++++++++++++++-
 1 file changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 1060abec9f29..e64dfc327891 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -247,6 +247,7 @@ enum {
 	BIASEXTR_127_7,
 };
 
+struct dw_mipi_dsi_rockchip;
 struct rockchip_dw_dsi_chip_data {
 	u32 reg;
 
@@ -262,6 +263,9 @@ struct rockchip_dw_dsi_chip_data {
 	u32 lanecfg2_grf_reg;
 	u32 lanecfg2;
 
+	int (*dphy_get_timing)(struct dw_mipi_dsi_rockchip *dsi, unsigned int lane_mbps,
+			       struct dw_mipi_dsi_dphy_timing *timing);
+
 	int (*dphy_rx_init)(struct phy *phy);
 	int (*dphy_rx_power_on)(struct phy *phy);
 	int (*dphy_rx_power_off)(struct phy *phy);
@@ -721,8 +725,9 @@ static struct hstt hstt_table[] = {
 };
 
 static int
-dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
-			   struct dw_mipi_dsi_dphy_timing *timing)
+dw_mipi_dsi_phy_rk3288_get_timing(struct dw_mipi_dsi_rockchip *dsi,
+				  unsigned int lane_mbps,
+				  struct dw_mipi_dsi_dphy_timing *timing)
 {
 	int i;
 
@@ -738,6 +743,32 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
 	return 0;
 }
 
+static const struct dw_mipi_dsi_dphy_timing dphy_timing_px30 = {
+	.clk_lp2hs = 0x40,
+	.clk_hs2lp = 0x40,
+	.data_lp2hs = 0x10,
+	.data_hs2lp = 0x14,
+};
+
+static int
+dw_mipi_dsi_phy_px30_get_timing(struct dw_mipi_dsi_rockchip *dsi,
+				unsigned int lane_mbps,
+				struct dw_mipi_dsi_dphy_timing *timing)
+{
+	*timing = dphy_timing_px30;
+
+	return 0;
+}
+
+static int
+dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
+			   struct dw_mipi_dsi_dphy_timing *timing)
+{
+	struct dw_mipi_dsi_rockchip *dsi = priv_data;
+
+	return dsi->cdata->dphy_get_timing(dsi, lane_mbps, timing);
+}
+
 static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_rockchip_phy_ops = {
 	.init = dw_mipi_dsi_phy_init,
 	.power_on = dw_mipi_dsi_phy_power_on,
@@ -1506,6 +1537,7 @@ static const struct rockchip_dw_dsi_chip_data px30_chip_data[] = {
 
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1000000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1519,6 +1551,7 @@ static const struct rockchip_dw_dsi_chip_data rk3128_chip_data[] = {
 						RK3128_DSI_FORCETXSTOPMODE), 0),
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1000000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1532,6 +1565,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
 
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1500000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_rk3288_get_timing,
 	},
 	{
 		.reg = 0xff964000,
@@ -1541,6 +1575,7 @@ static const struct rockchip_dw_dsi_chip_data rk3288_chip_data[] = {
 
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1500000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_rk3288_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1554,6 +1589,7 @@ static const struct rockchip_dw_dsi_chip_data rk3368_chip_data[] = {
 						RK3368_DSI_FORCERXMODE), 0),
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1500000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1642,6 +1678,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
 		.flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1500000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_rk3288_get_timing,
 	},
 	{
 		.reg = 0xff968000,
@@ -1671,6 +1708,7 @@ static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
 		.dphy_rx_init = rk3399_dphy_tx1rx1_init,
 		.dphy_rx_power_on = rk3399_dphy_tx1rx1_power_on,
 		.dphy_rx_power_off = rk3399_dphy_tx1rx1_power_off,
+		.dphy_get_timing = dw_mipi_dsi_phy_rk3288_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1698,6 +1736,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RK3568_DSI0_FORCERXMODE, 0)),
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1200000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{
 		.reg = 0xfe070000,
@@ -1708,6 +1747,7 @@ static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RK3568_DSI1_FORCERXMODE, 0)),
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1200000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{ /* sentinel */ }
 };
@@ -1721,6 +1761,7 @@ static const struct rockchip_dw_dsi_chip_data rv1126_chip_data[] = {
 			     FIELD_PREP_WM16_CONST(RV1126_DSI_FORCETXSTOPMODE, 0)),
 		.max_data_lanes = 4,
 		.max_bit_rate_per_lane = 1000000000UL,
+		.dphy_get_timing = dw_mipi_dsi_phy_px30_get_timing,
 	},
 	{ /* sentinel */ }
 };
-- 
2.53.0



From phucduc.bui at gmail.com  Tue Jun  2 20:57:38 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Wed,  3 Jun 2026 10:57:38 +0700
Subject: [PATCH 0/3] ASoC: rockchip: Use guard() for spin locks
Message-ID: <20260603035741.68893-1-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Hi all,

This series converts spinlock handling in the Rockchip sound drivers
to use guard() helpers.
The changes are code cleanup only and should have no functional impact.
Compile tested only.

Best regards,
Phuc

bui duc phuc (3):
  ASoC: rockchip: rockchip_i2s: Use guard() for spin locks
  ASoC: rockchip: i2s-tdm: Use guard() for spin locks
  ASoC: rockchip: rockchip_sai: Use guard() for spin locks

 sound/soc/rockchip/rockchip_i2s.c     | 160 ++++++++--------
 sound/soc/rockchip/rockchip_i2s_tdm.c |   8 +-
 sound/soc/rockchip/rockchip_sai.c     | 258 +++++++++++++-------------
 3 files changed, 209 insertions(+), 217 deletions(-)

-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 20:57:39 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Wed,  3 Jun 2026 10:57:39 +0700
Subject: [PATCH 1/3] ASoC: rockchip: rockchip_i2s: Use guard() for spin locks
In-Reply-To: <20260603035741.68893-1-phucduc.bui@gmail.com>
References: <20260603035741.68893-1-phucduc.bui@gmail.com>
Message-ID: <20260603035741.68893-2-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.

 sound/soc/rockchip/rockchip_i2s.c | 160 +++++++++++++++---------------
 1 file changed, 80 insertions(+), 80 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 0a0a95b4f520..5a5087f4ae03 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -127,52 +127,52 @@ static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 	unsigned int val = 0;
 	int ret = 0;
 
-	spin_lock(&i2s->lock);
-	if (on) {
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_TDE_ENABLE,
-					 I2S_DMACR_TDE_ENABLE);
-		if (ret < 0)
-			goto end;
-		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-		if (ret < 0)
-			goto end;
-		i2s->tx_start = true;
-	} else {
-		i2s->tx_start = false;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_TDE_ENABLE,
-					 I2S_DMACR_TDE_DISABLE);
-		if (ret < 0)
-			goto end;
-
-		if (!i2s->rx_start) {
+	scoped_guard(spinlock, &i2s->lock) {
+		if (on) {
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_TDE_ENABLE,
+						 I2S_DMACR_TDE_ENABLE);
+			if (ret < 0)
+				break;
 			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
 						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+						 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 			if (ret < 0)
-				goto end;
-			udelay(150);
-			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
-						 I2S_CLR_TXC | I2S_CLR_RXC,
-						 I2S_CLR_TXC | I2S_CLR_RXC);
-			if (ret < 0)
-				goto end;
-			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
-							      I2S_CLR,
-							      val,
-							      val == 0,
-							      20,
-							      200);
+				break;
+			i2s->tx_start = true;
+		} else {
+			i2s->tx_start = false;
+
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_TDE_ENABLE,
+						 I2S_DMACR_TDE_DISABLE);
 			if (ret < 0)
-				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+				break;
+
+			if (!i2s->rx_start) {
+				ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+							 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+							 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+				if (ret < 0)
+					break;
+				udelay(150);
+				ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+							 I2S_CLR_TXC | I2S_CLR_RXC,
+						 I2S_CLR_TXC | I2S_CLR_RXC);
+				if (ret < 0)
+					break;
+				ret = regmap_read_poll_timeout_atomic(i2s->regmap,
+								      I2S_CLR,
+								      val,
+								      val == 0,
+								      20,
+								      200);
+				if (ret < 0)
+					dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+			}
 		}
 	}
-end:
-	spin_unlock(&i2s->lock);
+
 	if (ret < 0)
 		dev_err(i2s->dev, "lrclk update failed\n");
 
@@ -184,53 +184,53 @@ static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 	unsigned int val = 0;
 	int ret = 0;
 
-	spin_lock(&i2s->lock);
-	if (on) {
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_RDE_ENABLE,
-					 I2S_DMACR_RDE_ENABLE);
-		if (ret < 0)
-			goto end;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-		if (ret < 0)
-			goto end;
-		i2s->rx_start = true;
-	} else {
-		i2s->rx_start = false;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_RDE_ENABLE,
-					 I2S_DMACR_RDE_DISABLE);
-		if (ret < 0)
-			goto end;
+	scoped_guard(spinlock, &i2s->lock) {
+		if (on) {
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_RDE_ENABLE,
+						 I2S_DMACR_RDE_ENABLE);
+			if (ret < 0)
+				break;
 
-		if (!i2s->tx_start) {
 			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
 						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+						 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 			if (ret < 0)
-				goto end;
-			udelay(150);
-			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
-						 I2S_CLR_TXC | I2S_CLR_RXC,
-						 I2S_CLR_TXC | I2S_CLR_RXC);
-			if (ret < 0)
-				goto end;
-			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
-							      I2S_CLR,
-							      val,
-							      val == 0,
-							      20,
-							      200);
+				break;
+			i2s->rx_start = true;
+		} else {
+			i2s->rx_start = false;
+
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_RDE_ENABLE,
+						 I2S_DMACR_RDE_DISABLE);
 			if (ret < 0)
-				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+				break;
+
+			if (!i2s->tx_start) {
+				ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+							 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+							 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+				if (ret < 0)
+					break;
+				udelay(150);
+				ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+							 I2S_CLR_TXC | I2S_CLR_RXC,
+							 I2S_CLR_TXC | I2S_CLR_RXC);
+				if (ret < 0)
+					break;
+				ret = regmap_read_poll_timeout_atomic(i2s->regmap,
+								      I2S_CLR,
+								      val,
+								      val == 0,
+								      20,
+								      200);
+				if (ret < 0)
+					dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+			}
 		}
 	}
-end:
-	spin_unlock(&i2s->lock);
+
 	if (ret < 0)
 		dev_err(i2s->dev, "lrclk update failed\n");
 
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 20:57:40 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Wed,  3 Jun 2026 10:57:40 +0700
Subject: [PATCH 2/3] ASoC: rockchip: i2s-tdm: Use guard() for spin locks
In-Reply-To: <20260603035741.68893-1-phucduc.bui@gmail.com>
References: <20260603035741.68893-1-phucduc.bui@gmail.com>
Message-ID: <20260603035741.68893-3-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.

 sound/soc/rockchip/rockchip_i2s_tdm.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index fc52149ed6ae..3f3db28b8940 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -285,9 +285,8 @@ static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai, int on)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
-	unsigned long flags;
 
-	spin_lock_irqsave(&i2s_tdm->lock, flags);
+	guard(spinlock_irqsave)(&i2s_tdm->lock);
 	if (on) {
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			rockchip_enable_tde(i2s_tdm->regmap);
@@ -313,7 +312,6 @@ static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,
 						I2S_CLR_TXC | I2S_CLR_RXC);
 		}
 	}
-	spin_unlock_irqrestore(&i2s_tdm->lock, flags);
 }
 
 static void rockchip_snd_txctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on)
@@ -587,12 +585,11 @@ static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,
 				  unsigned int fmt)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
-	unsigned long flags;
 
 	if (!i2s_tdm->clk_trcm)
 		return 0;
 
-	spin_lock_irqsave(&i2s_tdm->lock, flags);
+	guard(spinlock_irqsave)(&i2s_tdm->lock);
 	if (i2s_tdm->refcount)
 		rockchip_i2s_tdm_xfer_pause(substream, i2s_tdm);
 
@@ -614,7 +611,6 @@ static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,
 
 	if (i2s_tdm->refcount)
 		rockchip_i2s_tdm_xfer_resume(substream, i2s_tdm);
-	spin_unlock_irqrestore(&i2s_tdm->lock, flags);
 
 	return 0;
 }
-- 
2.43.0



From phucduc.bui at gmail.com  Tue Jun  2 20:57:41 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Wed,  3 Jun 2026 10:57:41 +0700
Subject: [PATCH 3/3] ASoC: rockchip: rockchip_sai: Use guard() for spin locks
In-Reply-To: <20260603035741.68893-1-phucduc.bui@gmail.com>
References: <20260603035741.68893-1-phucduc.bui@gmail.com>
Message-ID: <20260603035741.68893-4-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.

 sound/soc/rockchip/rockchip_sai.c | 258 +++++++++++++++---------------
 1 file changed, 127 insertions(+), 131 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index ed393e5034a4..9104f4dedb15 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -18,7 +18,6 @@
 #include <sound/pcm_params.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/tlv.h>
-
 #include "rockchip_sai.h"
 
 #define DRV_NAME		"rockchip-sai"
@@ -216,14 +215,12 @@ static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned
 static int rockchip_sai_runtime_suspend(struct device *dev)
 {
 	struct rk_sai_dev *sai = dev_get_drvdata(dev);
-	unsigned long flags;
 
 	rockchip_sai_fsync_lost_detect(sai, 0);
 	rockchip_sai_fsync_err_detect(sai, 0);
 
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock)
+		rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
 
 	regcache_cache_only(sai->regmap, true);
 	/*
@@ -483,7 +480,6 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
 	unsigned int mask = 0, val = 0;
 	unsigned int clk_gates;
-	unsigned long flags;
 	int ret = 0;
 
 	pm_runtime_get_sync(dai->dev);
@@ -499,56 +495,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		sai->is_master_mode = false;
 		break;
 	default:
-		ret = -EINVAL;
-		goto err_pm_put;
-	}
-
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
-	if (sai->initialized) {
-		if (sai->has_capture && sai->has_playback)
-			rockchip_sai_xfer_stop(sai, -1);
-		else if (sai->has_capture)
-			rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
-		else
-			rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
-	} else {
-		rockchip_sai_clear(sai, 0);
-		sai->initialized = true;
+		pm_runtime_put(dai->dev);
+		return -EINVAL;
 	}
 
-	regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
+		rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+		if (sai->initialized) {
+			if (sai->has_capture && sai->has_playback)
+				rockchip_sai_xfer_stop(sai, -1);
+			else if (sai->has_capture)
+				rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
+			else
+				rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
+		} else {
+			rockchip_sai_clear(sai, 0);
+			sai->initialized = true;
+		}
 
-	mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
-		break;
-	case SND_SOC_DAIFMT_IB_IF:
-		val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
-		break;
-	default:
-		ret = -EINVAL;
-		goto err_xfer_unlock;
-	}
+		regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+
+		mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
 
-	regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+		if (ret == 0) {
+			regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+			rockchip_sai_fmt_create(sai, fmt);
+		}
 
-	rockchip_sai_fmt_create(sai, fmt);
+		if (clk_gates)
+			regmap_update_bits(sai->regmap, SAI_XFER,
+					SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+					clk_gates);
+	}
 
-err_xfer_unlock:
-	if (clk_gates)
-		regmap_update_bits(sai->regmap, SAI_XFER,
-				SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
-				clk_gates);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
-err_pm_put:
 	pm_runtime_put(dai->dev);
 
 	return ret;
@@ -564,7 +560,6 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
 	unsigned int ch_per_lane, slot_width;
 	unsigned int val, fscr, reg;
 	unsigned int lanes, req_lanes;
-	unsigned long flags;
 	int ret = 0;
 
 	if (!rockchip_sai_stream_valid(substream, dai))
@@ -618,84 +613,88 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
 		val = SAI_XCR_VDW(32);
 		break;
 	default:
-		ret = -EINVAL;
-		goto err_pm_put;
+		pm_runtime_put(sai->dev);
+		return -EINVAL;
 	}
 
 	val |= SAI_XCR_CSR(lanes);
 
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-
-	regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
-
-	if (!sai->is_tdm)
-		regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
-				   SAI_XCR_SBW(params_physical_width(params)));
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
 
-	regmap_read(sai->regmap, reg, &val);
+		regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
 
-	slot_width = SAI_XCR_SBW_V(val);
-	ch_per_lane = params_channels(params) / lanes;
+		if (!sai->is_tdm)
+			regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
+					   SAI_XCR_SBW(params_physical_width(params)));
 
-	regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
-			   SAI_XCR_SNB(ch_per_lane));
+		regmap_read(sai->regmap, reg, &val);
 
-	fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
-
-	switch (sai->fpw) {
-	case FPW_ONE_BCLK_WIDTH:
-		fscr |= SAI_FSCR_FPW(1);
-		break;
-	case FPW_ONE_SLOT_WIDTH:
-		fscr |= SAI_FSCR_FPW(slot_width);
-		break;
-	case FPW_HALF_FRAME_WIDTH:
-		fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
-		break;
-	default:
-		dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
-		ret = -EINVAL;
-		goto err_xfer_unlock;
-	}
+		slot_width = SAI_XCR_SBW_V(val);
+		ch_per_lane = params_channels(params) / lanes;
 
-	regmap_update_bits(sai->regmap, SAI_FSCR,
-			   SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
+		regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
+				   SAI_XCR_SNB(ch_per_lane));
 
-	if (sai->is_master_mode) {
-		bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
-		ret = clk_set_rate(sai->mclk, sai->mclk_rate);
-		if (ret) {
-			dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
-				sai->mclk_rate, ERR_PTR(ret));
-			goto err_xfer_unlock;
-		}
+		fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
 
-		mclk_rate = clk_get_rate(sai->mclk);
-		if (mclk_rate < bclk_rate) {
-			dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
-				mclk_rate, bclk_rate);
+		switch (sai->fpw) {
+		case FPW_ONE_BCLK_WIDTH:
+			fscr |= SAI_FSCR_FPW(1);
+			break;
+		case FPW_ONE_SLOT_WIDTH:
+			fscr |= SAI_FSCR_FPW(slot_width);
+			break;
+		case FPW_HALF_FRAME_WIDTH:
+			fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
+			break;
+		default:
+			dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
 			ret = -EINVAL;
-			goto err_xfer_unlock;
+			break;
 		}
 
-		div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
-		mclk_req_rate = bclk_rate * div_bclk;
-
-		if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
-		    mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
-			dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
-				mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
-			ret = -EINVAL;
-			goto err_xfer_unlock;
+		if (ret == 0) {
+			regmap_update_bits(sai->regmap, SAI_FSCR,
+					   SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
+
+			if (sai->is_master_mode) {
+				bclk_rate = sai->fw_ratio * slot_width *
+						ch_per_lane * params_rate(params);
+				ret = clk_set_rate(sai->mclk, sai->mclk_rate);
+				if (ret)
+					dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
+						sai->mclk_rate, ERR_PTR(ret));
+				else {
+					mclk_rate = clk_get_rate(sai->mclk);
+					if (mclk_rate < bclk_rate) {
+						dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
+							mclk_rate, bclk_rate);
+						ret = -EINVAL;
+					} else {
+
+						div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
+						mclk_req_rate = bclk_rate * div_bclk;
+
+						if (mclk_rate <
+							mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
+						    mclk_rate >
+							mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
+							dev_err(sai->dev,
+								"Mismatch mclk: %u, expected %u (+/- %dHz)\n",
+								mclk_rate, mclk_req_rate,
+								CLK_SHIFT_RATE_HZ_MAX);
+							ret = -EINVAL;
+						} else
+							regmap_update_bits(sai->regmap,
+									SAI_CKR,
+									SAI_CKR_MDIV_MASK,
+									SAI_CKR_MDIV(div_bclk));
+					}
+				}
+			}
 		}
-
-		regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
-				   SAI_CKR_MDIV(div_bclk));
 	}
 
-err_xfer_unlock:
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
-err_pm_put:
 	pm_runtime_put(sai->dev);
 
 	return ret;
@@ -705,7 +704,6 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
-	unsigned long flags;
 
 	if (!rockchip_sai_stream_valid(substream, dai))
 		return 0;
@@ -726,13 +724,12 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
 		 * udelay falls short.
 		 */
 		udelay(20);
-		spin_lock_irqsave(&sai->xfer_lock, flags);
-		regmap_update_bits(sai->regmap, SAI_XFER,
-				   SAI_XFER_CLK_MASK |
-				   SAI_XFER_FSS_MASK,
-				   SAI_XFER_CLK_EN |
-				   SAI_XFER_FSS_EN);
-		spin_unlock_irqrestore(&sai->xfer_lock, flags);
+		scoped_guard(spinlock_irqsave, &sai->xfer_lock)
+			regmap_update_bits(sai->regmap, SAI_XFER,
+					   SAI_XFER_CLK_MASK |
+					   SAI_XFER_FSS_MASK,
+					   SAI_XFER_CLK_EN |
+					   SAI_XFER_FSS_EN);
 	}
 
 	rockchip_sai_fsync_lost_detect(sai, 1);
@@ -915,7 +912,6 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
 				     int slots, int slot_width)
 {
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
-	unsigned long flags;
 	unsigned int clk_gates;
 	int sw = slot_width;
 
@@ -931,16 +927,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 
 	pm_runtime_get_sync(dai->dev);
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
-	regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
-			   SAI_XCR_SBW(sw));
-	regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
-			   SAI_XCR_SBW(sw));
-	regmap_update_bits(sai->regmap, SAI_XFER,
-			   SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
-			   clk_gates);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
+		rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+		regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
+				   SAI_XCR_SBW(sw));
+		regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
+				   SAI_XCR_SBW(sw));
+		regmap_update_bits(sai->regmap, SAI_XFER,
+				   SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+				   clk_gates);
+	}
 	pm_runtime_put(dai->dev);
 
 	return 0;
-- 
2.43.0



From jai.luthra at ideasonboard.com  Tue Jun  2 23:51:18 2026
From: jai.luthra at ideasonboard.com (Jai Luthra)
Date: Wed, 03 Jun 2026 12:21:18 +0530
Subject: [PATCH] media: rockchip: rkcif: Fix error handling for media_entity_remote_source_pad_unique()
In-Reply-To: <20260522065548.2438545-1-nichen@iscas.ac.cn>
References: <20260522065548.2438545-1-nichen@iscas.ac.cn>
Message-ID: <178046947892.1525445.1023288239828130272@freya>

Quoting Chen Ni (2026-05-22 12:25:48)
> The media_entity_remote_source_pad_unique() function returns an error
> pointer on failure, not NULL. Fix the check to use IS_ERR() and return
> PTR_ERR() to correctly handle allocation failures.
> 
> Fixes: 501802e2ad51 ("media: rockchip: rkcif: add abstraction for dma blocks")
> Signed-off-by: Chen Ni <nichen at iscas.ac.cn>

Reviewed-by: Jai Luthra <jai.luthra at ideasonboard.com>

Thanks,
    Jai

> ---
>  drivers/media/platform/rockchip/rkcif/rkcif-stream.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-stream.c b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> index 3130d420ad55..542aa877919d 100644
> --- a/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> +++ b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> @@ -466,7 +466,7 @@ static int rkcif_stream_link_validate(struct media_link *link)
>         struct rkcif_stream *stream = to_rkcif_stream(vdev);
>         int ret = -EINVAL;
>  
> -       if (!media_entity_remote_source_pad_unique(link->sink->entity))
> +       if (IS_ERR(media_entity_remote_source_pad_unique(link->sink->entity)))
>                 return -ENOTCONN;
>  
>         sd = media_entity_to_v4l2_subdev(link->source->entity);
> -- 
> 2.25.1
> 
>


From broonie at kernel.org  Tue Jun  2 08:04:14 2026
From: broonie at kernel.org (Mark Brown)
Date: Tue, 02 Jun 2026 16:04:14 +0100
Subject: [PATCH] ASoC: rockchip: i2s: Use managed hclk and runtime PM
 cleanup
In-Reply-To: <20260521-asoc-rockchip-i2s-devm-cleanup-v1-1-9319bd781393@gmail.com>
References: <20260521-asoc-rockchip-i2s-devm-cleanup-v1-1-9319bd781393@gmail.com>
Message-ID: <178041265480.93058.3443088566208285913.b4-ty@b4>

On Thu, 21 May 2026 23:30:07 -0300, C?ssio Gabriel wrote:
> ASoC: rockchip: i2s: Use managed hclk and runtime PM cleanup

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/1] ASoC: rockchip: i2s: Use managed hclk and runtime PM cleanup
      https://git.kernel.org/broonie/sound/c/2d90ecdfa326

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 mripard at kernel.org  Wed Jun  3 00:55:51 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Wed, 3 Jun 2026 09:55:51 +0200
Subject: [PATCH 2/2] drm/rockchip: dw_hdmi_qp: expose "overscan" property
In-Reply-To: <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
 <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>
Message-ID: <20260603-glittering-vigilant-beluga-0c6bf6@houat>

On Tue, Jun 02, 2026 at 09:00:40PM +0400, Alexey Charkov wrote:
> Expose the "overscan" connector property as recognized by KWin and the
> likes to compensate for TV overscan cropping.
> 
> The CRTC will use the margin values derived from this overscan percentage
> in its post-composition scaler to add appropriate blank margins on all
> sides of the output image so that the TV doesn't eat up visible content.
> 
> Signed-off-by: Alexey Charkov <alchark at flipper.net>
> ---
>  drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> index f35484715c2d..fae44d11dbef 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> @@ -137,10 +137,18 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
>  					 struct drm_connector_state *conn_state)
>  {
>  	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
> +	const struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
>  	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
>  	union phy_configure_opts phy_cfg = {};
> +	unsigned int overscan;
>  	int ret;
>  
> +	overscan = min(conn_state->tv.overscan, 100u);
> +	s->tv_margins.left   = adj_mode->hdisplay * overscan / 200;
> +	s->tv_margins.right  = s->tv_margins.left;
> +	s->tv_margins.top    = adj_mode->vdisplay * overscan / 200;
> +	s->tv_margins.bottom = s->tv_margins.top;
> +
>  	if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
>  	    s->output_bpc == conn_state->hdmi.output_bpc)
>  		return 0;
> @@ -603,6 +611,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
>  		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
>  				     "Failed to init bridge connector\n");
>  
> +	ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to create TV connector properties\n");
> +
> +	drm_object_attach_property(&connector->base,
> +				   drm->mode_config.tv_overscan_property, 0);
> +

As the name suggests, it's a legacy property only ever used for TV. You
should be using drm_mode_create_tv_margin_properties()

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-rockchip/attachments/20260603/43444525/attachment.sig>

From alchark at flipper.net  Wed Jun  3 01:15:04 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Wed, 3 Jun 2026 12:15:04 +0400
Subject: [PATCH 2/2] drm/rockchip: dw_hdmi_qp: expose "overscan" property
In-Reply-To: <20260603-glittering-vigilant-beluga-0c6bf6@houat>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
 <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net> <20260603-glittering-vigilant-beluga-0c6bf6@houat>
Message-ID: <CAKTNdwE5uAOc9V+L1J7_QJfW45D-K-vTnpHuktxD2=x9e_4jOQ@mail.gmail.com>

On Wed, Jun 3, 2026 at 11:55?AM Maxime Ripard <mripard at kernel.org> wrote:
>
> On Tue, Jun 02, 2026 at 09:00:40PM +0400, Alexey Charkov wrote:
> > Expose the "overscan" connector property as recognized by KWin and the
> > likes to compensate for TV overscan cropping.
> >
> > The CRTC will use the margin values derived from this overscan percentage
> > in its post-composition scaler to add appropriate blank margins on all
> > sides of the output image so that the TV doesn't eat up visible content.
> >
> > Signed-off-by: Alexey Charkov <alchark at flipper.net>
> > ---
> >  drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
> >  1 file changed, 16 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > index f35484715c2d..fae44d11dbef 100644
> > --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > @@ -137,10 +137,18 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
> >                                        struct drm_connector_state *conn_state)
> >  {
> >       struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
> > +     const struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
> >       struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> >       union phy_configure_opts phy_cfg = {};
> > +     unsigned int overscan;
> >       int ret;
> >
> > +     overscan = min(conn_state->tv.overscan, 100u);
> > +     s->tv_margins.left   = adj_mode->hdisplay * overscan / 200;
> > +     s->tv_margins.right  = s->tv_margins.left;
> > +     s->tv_margins.top    = adj_mode->vdisplay * overscan / 200;
> > +     s->tv_margins.bottom = s->tv_margins.top;
> > +
> >       if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
> >           s->output_bpc == conn_state->hdmi.output_bpc)
> >               return 0;
> > @@ -603,6 +611,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> >               return dev_err_probe(hdmi->dev, PTR_ERR(connector),
> >                                    "Failed to init bridge connector\n");
> >
> > +     ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret,
> > +                                  "Failed to create TV connector properties\n");
> > +
> > +     drm_object_attach_property(&connector->base,
> > +                                drm->mode_config.tv_overscan_property, 0);
> > +
>
> As the name suggests, it's a legacy property only ever used for TV. You
> should be using drm_mode_create_tv_margin_properties()

Hi Maxime, I tried that one before going for the current solution but
realized that the userspace tooling I care about (KWin in particular)
doesn't recognize those properties, but it does recognize "overscan".
Maybe there's a compat helper somewhere that I missed, which would
translate between the two?

It is for TVs. Turns out that having a proper right-sized digital
input interface doesn't prevent them from doing weird stuff with the
image data, i.e. overscanning and cropping it right where one would
expect to see the system tray and panel.

Best regards,
Alexey


From michael.riesch at collabora.com  Wed Jun  3 02:50:31 2026
From: michael.riesch at collabora.com (Michael Riesch)
Date: Wed, 3 Jun 2026 11:50:31 +0200
Subject: [PATCH] media: rockchip: rkcif: Fix error handling for
 media_entity_remote_source_pad_unique()
In-Reply-To: <20260522065548.2438545-1-nichen@iscas.ac.cn>
References: <20260522065548.2438545-1-nichen@iscas.ac.cn>
Message-ID: <a80c978f-65e8-436e-a3d6-74cf50b5ea6a@collabora.com>

Hi Chen,

Thanks for the fix!

On 5/22/26 08:55, Chen Ni wrote:
> The media_entity_remote_source_pad_unique() function returns an error
> pointer on failure, not NULL. Fix the check to use IS_ERR() and return
> PTR_ERR() to correctly handle allocation failures.
> 
> Fixes: 501802e2ad51 ("media: rockchip: rkcif: add abstraction for dma blocks")
> Signed-off-by: Chen Ni <nichen at iscas.ac.cn>

Reviewed-by: Michael Riesch <michael.riesch at collabora.com>

Best regards,
Michael

> ---
>  drivers/media/platform/rockchip/rkcif/rkcif-stream.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-stream.c b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> index 3130d420ad55..542aa877919d 100644
> --- a/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> +++ b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c
> @@ -466,7 +466,7 @@ static int rkcif_stream_link_validate(struct media_link *link)
>  	struct rkcif_stream *stream = to_rkcif_stream(vdev);
>  	int ret = -EINVAL;
>  
> -	if (!media_entity_remote_source_pad_unique(link->sink->entity))
> +	if (IS_ERR(media_entity_remote_source_pad_unique(link->sink->entity)))
>  		return -ENOTCONN;
>  
>  	sd = media_entity_to_v4l2_subdev(link->source->entity);



From cristian.ciocaltea at collabora.com  Wed Jun  3 03:27:20 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Wed, 3 Jun 2026 13:27:20 +0300
Subject: [PATCH v2 0/6] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
In-Reply-To: <e0eeb794-11b9-4ba6-bee2-f6cc607d3a16@collabora.com>
References: <20260511-hdptx-clk-fixes-v2-0-664e41379cab@collabora.com>
 <e0eeb794-11b9-4ba6-bee2-f6cc607d3a16@collabora.com>
Message-ID: <ebcad67e-e14a-4d0e-b3e0-79ae1d146eaf@collabora.com>

On 5/20/26 10:05 PM, Cristian Ciocaltea wrote:
> Hi Vinod,
> 
> On 5/11/26 9:21 PM, Cristian Ciocaltea wrote:
>> This series provides a set of bug fixes and cleanups for the Rockchip
>> Samsung HDPTX PHY driver.
>>
>> The first part of the series (i.e. PATCH 1 & 2) addresses clock rate
>> calculation and synchronization issues.  Specifically, it fixes edge
>> cases where the PHY PLL is pre-programmed by an external component (like
>> a bootloader) or when changing the color depth (bpc) while keeping the
>> modeline constant.  Because the Common Clock Framework .set_rate()
>> callback might not be invoked if the pixel clock remains unchanged, this
>> previously led to out-of-sync states between CCF and the actual HDMI PHY
>> configuration.
>>
>> The second part focuses on code cleanups and modernizing the register
>> access.  Now that dw_hdmi_qp driver has fully switched to using
>> phy_configure(), we can drop the deprecated TMDS rate setup workarounds
>> and the restrict_rate_change flag logic.  Finally, it refactors the
>> driver to consistently use standard bitfield macros.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>> ---
>> Changes in v2:
>> - Collected Tested-by tags from Thomas and Simon
>> - Fixed a typo in commit description of patch 1
>> - Added a comment in patch 2 explaining why PLL config errors are
>>   ignored for rk_hdptx_phy_consumer_get()
>> - Added a missed FIELD_GET conversion for lcpll_hw.pms_sdiv in patch 6
>> - Rebased onto latest phy/fixes
>> - Link to v1: https://lore.kernel.org/r/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f at collabora.com
> 
> In case you missed my comments from last week on the Sashiko AI review findings
> - in short, I don't think there is anything to worry about and the series should
> be fine to apply as-is.  Please let me know if you would still prefer a new
> revision.
Kind reminder..

Regards,
Cristian


From andyshrk at 163.com  Wed Jun  3 06:01:52 2026
From: andyshrk at 163.com (Andy Yan)
Date: Wed, 3 Jun 2026 21:01:52 +0800 (CST)
Subject: [PATCH v4 2/3] drm/rockchip: dw_dp: Add missing newline in
 dev_err_probe() message
In-Reply-To: <20260601-drm-rk-fixes-v4-2-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
 <20260601-drm-rk-fixes-v4-2-c3f3f123e1da@collabora.com>
Message-ID: <3db55ac2.a5b3.19e8d9377c6.Coremail.andyshrk@163.com>


Hello Cristian?

At 2026-06-02 00:13:45, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>Add the missing trailing newline to dev_err_probe() call in
>dw_dp_rockchip_bind().
>
>Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
>Fixes: 26cb3e26efa7 ("drm/rockchip: dw_dp: Simplify error handling")


Just one Fixes tag?


>Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>---
> drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
>diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>index 32bc73a1d5e4..f137f699737c 100644
>--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>@@ -109,7 +109,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
> 	connector = drm_bridge_connector_init(drm_dev, encoder);
> 	if (IS_ERR(connector))
> 		return dev_err_probe(dev, PTR_ERR(connector),
>-				     "Failed to init bridge connector");
>+				     "Failed to init bridge connector\n");
> 
> 	return 0;
> }
>
>-- 
>2.54.0

From andyshrk at 163.com  Wed Jun  3 06:03:44 2026
From: andyshrk at 163.com (Andy Yan)
Date: Wed, 3 Jun 2026 21:03:44 +0800 (CST)
Subject: [PATCH v4 3/3] drm/rockchip: dw_dp: Release core resources
In-Reply-To: <20260601-drm-rk-fixes-v4-3-c3f3f123e1da@collabora.com>
References: <20260601-drm-rk-fixes-v4-0-c3f3f123e1da@collabora.com>
 <20260601-drm-rk-fixes-v4-3-c3f3f123e1da@collabora.com>
Message-ID: <1f9bf6c3.a5dd.19e8d952dc9.Coremail.andyshrk@163.com>


Hello Cristian?

At 2026-06-02 00:13:46, "Cristian Ciocaltea" <cristian.ciocaltea at collabora.com> wrote:
>Core resources such as the DisplayPort AUX channel get initialized and
>registered during dw_dp_bind(), but are never unregistered, which may
>lead to memory leaks and/or use-after-free:
>
>[  224.661371] BUG: KASAN: slab-use-after-free in device_is_dependent+0xe0/0x2b0
>[  224.662015] Read of size 8 at addr ffff00011aee8550 by task modprobe/658
>[  224.662612]
>[  224.662752] CPU: 7 UID: 0 PID: 658 Comm: modprobe Not tainted 7.0.0-rc2-next-20260305 #14 PREEMPT
>[  224.662759] Hardware name: Radxa ROCK 5B (DT)
>[  224.662762] Call trace:
>[  224.662764]  show_stack+0x20/0x38 (C)
>[  224.662772]  dump_stack_lvl+0x6c/0x98
>[  224.662777]  print_report+0x160/0x4b8
>[  224.662783]  kasan_report+0xb4/0xe0
>[  224.662790]  __asan_report_load8_noabort+0x20/0x30
>[  224.662796]  device_is_dependent+0xe0/0x2b0
>[  224.662802]  device_is_dependent+0x108/0x2b0
>[  224.662808]  device_link_add+0x1f8/0x10b0
>[  224.662813]  devm_of_phy_get_by_index+0x120/0x200
>[  224.662819]  dw_dp_bind+0x34c/0xb10 [dw_dp]
>[  224.662830]  dw_dp_rockchip_bind+0x194/0x250 [rockchipdrm]
>[  224.662864]  component_bind_all+0x3a8/0x720
>[  224.662869]  rockchip_drm_bind+0x120/0x390 [rockchipdrm]
>[  224.662899]  try_to_bring_up_aggregate_device+0x76c/0x838
>[  224.662904]  component_master_add_with_match+0x1f4/0x230
>[  224.662909]  rockchip_drm_platform_probe+0x420/0x538 [rockchipdrm]
>[  224.662939]  platform_probe+0xe8/0x168
>[  224.662945]  really_probe+0x340/0x828
>[  224.662950]  __driver_probe_device+0x2e0/0x350
>[  224.662954]  driver_probe_device+0x80/0x140
>[  224.662959]  __driver_attach+0x398/0x460
>[  224.662964]  bus_for_each_dev+0xe0/0x198
>[  224.662968]  driver_attach+0x50/0x68
>[  224.662972]  bus_add_driver+0x2a0/0x4c0
>[  224.662977]  driver_register+0x294/0x360
>[  224.662982]  __platform_driver_register+0x7c/0x98
>[  224.662987]  rockchip_drm_init+0xc4/0xff8 [rockchipdrm]
>
>Since a previous commit exported dw_dp_unbind() function in DW DP core
>library to take care of the necessary cleanup, use this in the
>component's unbind() callback, as well as in its bind() error path.
>
>Fixes: d68ba7bac955 ("drm/rockchip: Add RK3588 DPTX output support")
>Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

   Reviewed-by: Andy Yan <andy.yan at rock-chips.com>

Thanks

>---
> drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 13 ++++++++++++-
> 1 file changed, 12 insertions(+), 1 deletion(-)
>
>diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>index f137f699737c..0de822360c8d 100644
>--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
>@@ -107,15 +107,26 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
> 		return PTR_ERR(dp->base);
> 
> 	connector = drm_bridge_connector_init(drm_dev, encoder);
>-	if (IS_ERR(connector))
>+	if (IS_ERR(connector)) {
>+		dw_dp_unbind(dp->base);
> 		return dev_err_probe(dev, PTR_ERR(connector),
> 				     "Failed to init bridge connector\n");
>+	}
> 
> 	return 0;
> }
> 
>+static void dw_dp_rockchip_unbind(struct device *dev, struct device *master,
>+				  void *data)
>+{
>+	struct rockchip_dw_dp *dp = dev_get_drvdata(dev);
>+
>+	dw_dp_unbind(dp->base);
>+}
>+
> static const struct component_ops dw_dp_rockchip_component_ops = {
> 	.bind = dw_dp_rockchip_bind,
>+	.unbind = dw_dp_rockchip_unbind,
> };
> 
> static int dw_dp_probe(struct platform_device *pdev)
>
>-- 
>2.54.0

From andyshrk at 163.com  Wed Jun  3 06:11:05 2026
From: andyshrk at 163.com (Andy Yan)
Date: Wed, 3 Jun 2026 21:11:05 +0800 (CST)
Subject: [PATCH 2/2] drm/rockchip: dw_hdmi_qp: expose "overscan" property
In-Reply-To: <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
 <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>
Message-ID: <6f7ae6e2.a68c.19e8d9be74d.Coremail.andyshrk@163.com>


Hello Alexy?

At 2026-06-03 01:00:40, "Alexey Charkov" <alchark at flipper.net> wrote:
>Expose the "overscan" connector property as recognized by KWin and the
>likes to compensate for TV overscan cropping.
>
>The CRTC will use the margin values derived from this overscan percentage
>in its post-composition scaler to add appropriate blank margins on all
>sides of the output image so that the TV doesn't eat up visible content.
>
>Signed-off-by: Alexey Charkov <alchark at flipper.net>
>---
> drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
>diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
>index f35484715c2d..fae44d11dbef 100644
>--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
>+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
>@@ -137,10 +137,18 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
> 					 struct drm_connector_state *conn_state)
> {
> 	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
>+	const struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
> 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> 	union phy_configure_opts phy_cfg = {};
>+	unsigned int overscan;
> 	int ret;
> 
>+	overscan = min(conn_state->tv.overscan, 100u);
>+	s->tv_margins.left   = adj_mode->hdisplay * overscan / 200;
>+	s->tv_margins.right  = s->tv_margins.left;
>+	s->tv_margins.top    = adj_mode->vdisplay * overscan / 200;
>+	s->tv_margins.bottom = s->tv_margins.top;
>+
> 	if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
> 	    s->output_bpc == conn_state->hdmi.output_bpc)
> 		return 0;
>@@ -603,6 +611,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> 		return dev_err_probe(hdmi->dev, PTR_ERR(connector),
> 				     "Failed to init bridge connector\n");
> 
>+	ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
>+	if (ret)
>+		return dev_err_probe(dev, ret,
>+				     "Failed to create TV connector properties\n");

      I suggest calling a similar API within rockchip_drm_bind, and then attaching this property in
the connector drivers that need to expose it. This approach avoids invoking the API multiple times in multiple drivers?

>+
>+	drm_object_attach_property(&connector->base,
>+				   drm->mode_config.tv_overscan_property, 0);
>+
> 	return 0;
> }
> 
>
>-- 
>2.52.0
>
>
>_______________________________________________
>Linux-rockchip mailing list
>Linux-rockchip at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-rockchip

From heiko at sntech.de  Wed Jun  3 14:37:26 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed,  3 Jun 2026 23:37:26 +0200
Subject: [PATCH] clk: rockchip: don't COMPILE_TEST builds on M68K
Message-ID: <20260603213726.1025094-1-heiko@sntech.de>

Rockchip clock drivers use hash-tables with enums as inputs.

M68K does interesting things in its __hash_32() implementation, casting
that u32 input to an u16 and therefore triggering warnings like:

   drivers/clk/rockchip/clk-rk3528.c: note: in included file (through include/linux/hash.h, include/linux/slab.h):
     arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (18720 becomes 8720)
     arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (1e8e8 becomes e8e8)

As M68K should never ever need Rockchip clock drivers, simply disable
compile-tests for M68K.

Fixes: 7edfb7fb58ee ("clk: rockchip: allow COMPILE_TEST builds")
Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605191434.PQkj2Rki-lkp at intel.com/
Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/clk/rockchip/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig
index 85133498f013..8b49fe6f46fb 100644
--- a/drivers/clk/rockchip/Kconfig
+++ b/drivers/clk/rockchip/Kconfig
@@ -4,6 +4,7 @@
 config COMMON_CLK_ROCKCHIP
 	bool "Rockchip clock controller common support"
 	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	depends on !M68K
 	default ARCH_ROCKCHIP
 	help
 	  Say y here to enable common clock controller for Rockchip platforms.
-- 
2.47.3



From dmitry.baryshkov at oss.qualcomm.com  Wed Jun  3 15:59:07 2026
From: dmitry.baryshkov at oss.qualcomm.com (Dmitry Baryshkov)
Date: Thu, 4 Jun 2026 01:59:07 +0300
Subject: [PATCH 7/7] arm64: dts: qcom: Add #{address,size}-cells to
 Chromium-based /firmware
In-Reply-To: <20260428200712.2660635-8-briannorris@chromium.org>
References: <20260428200712.2660635-1-briannorris@chromium.org>
 <20260428200712.2660635-8-briannorris@chromium.org>
Message-ID: <pfo7vpd3ooiyfuo3wjom7qzknnnkiyel2kdu5fjqqrq5nccysq@e63rs7lgdfl4>

On Tue, Apr 28, 2026 at 01:06:59PM -0700, Brian Norris wrote:
> Chromium/Depthcharge bootloaders may dynamically add a few device nodes
> to a system's DTB under a /firmware node. A typical DT looks something
> like the following:
> 
> / {
>         firmware {
>                 ranges;
> 
>                 coreboot {
>                         compatible = "coreboot";
>                         reg = <...>;
>                         ...;
>                 };
>         };
> };
> 
> Notably, the /firmware node has an empty 'ranges', but does not have
> address/size-cells.
> 
> Commit 6e5773d52f4a ("of/address: Fix WARN when attempting translating
> non-translatable addresses") started requiring #address-cells for a
> device's parent if we want to use the reg resource in a device node.
> This leads to errors like the following:
> 
> [    7.763870] coreboot_table firmware:coreboot: probe with driver coreboot_table failed with error -22
> 
> Add appropriate #{address,size}-cells to work around the problem.
> 
> Note that Google has also patched the Depthcharge bootloader source to
> add {address,size}-cells [1], but bootloader updates are typically
> delivered only via Google OS updates. Not all users install Google
> software updates, and even if they do, Google may not produce updated
> binaries for all/older devices.
> 
> [1] https://lore.kernel.org/all/20241209092809.GA3246424 at google.com/
>     https://crrev.com/c/6051580 ("coreboot: Insert #address-cells and
>     #size-cells for firmware node")
> 
> Closes: https://lore.kernel.org/all/aeKlYzTiL0OB1y3g at google.com/
> Fixes: 6e5773d52f4a ("of/address: Fix WARN when attempting translating non-translatable addresses")
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>

> 

-- 
With best wishes
Dmitry


From dennis at ausil.us  Wed Jun  3 19:49:41 2026
From: dennis at ausil.us (Dennis Gilmore)
Date: Wed, 3 Jun 2026 21:49:41 -0500
Subject: [PATCH v10 0/4] Add support for Orange Pi 5 Pro
In-Reply-To: <20260511025352.106126-1-dennis@ausil.us>
References: <20260511025352.106126-1-dennis@ausil.us>
Message-ID: <CAABkxwvWNvZbGNRYGQVnrORr0ycXFY=SdUTD9Oe9tkPcdPSUEA@mail.gmail.com>

Hi,

Just checking if anything else is needed.

Dennis

On Sun, May 10, 2026 at 9:53?PM Dennis Gilmore <dennis at ausil.us> wrote:
>
> This series adds initial support for the Xunlong Orange Pi 5 Pro, based on
> the Rockchip RK3588S SoC. The board features eMMC, SD card, NVMe (PCIe),
> a Motorcomm YT6801 NIC (PCIe), WiFi/BT (BCM43456), HDMI connected to SoC
> (Second port is disabled in this patch), and a 40-pin expansion header.
>
> The series was tested against Linux 7.0
>
> Please take a look.
>
> Thank you,
>
> Dennis Gilmore
>
> Changes in v10:
> - rename rk806_single to rk806
> - link to v9: https://lore.kernel.org/linux-devicetree/20260429024737.544813-5-dennis at ausil.us/
>
> Changes in v9:
> - removed support for the dp-to-HDMI bridge, will send in a second patch
>   set to enable discusion to finish on how to handle its two operating
>   modes
> - link to v8: https://lore.kernel.org/linux-devicetree/20260425031011.2529364-1-dennis at ausil.us/
>
> Changes in v8:
> - Bridge node: renamed label from lt8711uxd to hdmi-bridge
> - Bridge node: added vdd-supply = <&vcc3v3_dp>. The vcc3v3_dp regulator
>   gates power to the LT8711UXD. regulator-always-on is kept because
>   drm_simple_bridge only enables vdd-supply with HPD which does not
>   happen without power on
> - GPIO output pinctrl groups (bt_wake_gpio, dp_bridge_en, ethernet_en,
>   vcc5v0_otg_en, wifi_enable_h) changed from pcfg_pull_none to
>   pcfg_pull_down to match the RK3588S power-on-reset default state
> - pcie2x1l1 (NVMe): switched from GPIO-mode reset to hardware sideband pins
>   using pinctrl-0 = <&pcie30x1m1_1_perstn>, <&pcie30x1m1_1_clkreqn>,
>   <&pcie30x1m1_1_waken>. Note: despite the "pcie30" prefix in the DTSI
>   group names, the SoC pin-mux table confirms these alt-function 4 pads
>   physically route to pcie2x1l1's native PERST#/CLKREQ#/WAKE# inputs.
>   reset-gpios is retained alongside the pinctrl entry for U-Boot
>   compatibility (pcie_dw_rockchip in U-Boot requires reset-gpios).
> - pcie2x1l2 (NIC): added &pcie20x1m0_clkreqn and &pcie20x1m0_waken to
>   pinctrl-0
> - Renamed pinctrl group vcc3v3_phy1_en to ethernet_en to match the
>   schematic signal name (Ethernet_EN)
> - link to v7: https://lore.kernel.org/linux-devicetree/20260414214104.1363987-1-dennis at ausil.us/
>
> Changes in v7:
> - Fix up whitespace issues identified by checkpatch.pl --strict in
>   rk3588s-orangepi-5-5b.dtsi
> - checkpatch gave a warning for WARNING: phy-mode "rgmii-rxid" without
>   comment, as this was moved over I left it untouched
> - Added lontium,lt8711uxd to the compatible enum in the simple-bridge
>   binding
> - Added lontium,lt8711uxd match entry with DRM_MODE_CONNECTOR_HDMIA to
>   the simple-bridge driver
> - New patch to rename the regulator labels for the es8388 supplies to
>   match the schematics and they all use vcca_*
> - Fixed ES8388 PVDD-supply ? vcca_3v3_s0 ? vcca_1v8_s0, 5 Pro is
>   different to 5 and 5b.
> - analog-sound: use CPU-as-clock-master on the Pro. The ES8388 is wired to
>   i2s2_2ch (the only I2S block physically routed to the codec pins on this
>   board), which uses the legacy rockchip_i2s driver. That driver's
>   slave-mode trigger path hangs for 200 ?s polling I2S_CLR and bails with
>   -ETIMEDOUT ("lrclk update failed"). The TDM-capable i2s0/i2s1/i2s5
>   blocks served by rockchip_i2s_tdm don't have this issue, which is why
>   other mainline ES8388 boards get away with bitclock-master = masterdai.
>   Drop bitclock-master/frame-master and the masterdai label to let the I2S
>   block generate BCLK/LRCK itself
> - Removed regulator-always-on/regulator-boot-on from vcc3v3_dp
> - Added pinctrl entries for all GPIO pins (dp_bridge_en, vcc3v3_phy1_en,
>   wifi_enable_h, pcie2x1l1_rst, pcie2x1l2_rst)
> - DP bridge rework ? replaced dp-connector node with proper chain:
>     - lt8711uxd bridge node (compatible lontium,lt8711uxd, with port at 0/port at 1
>       endpoints). Bridge power is gated by the vcc3v3_dp regulator, whose
>       enable GPIO (GPIO3_PC2) is driven via the dp_bridge_en pinctrl group;
>       no enable-gpios/vdd-supply on the bridge node itself.
>     - hdmi1-con connector node (compatible hdmi-connector, type a)
>     - dp0_out endpoint now points to bridge input instead of old connector
> - remove accidentally included unnecessary changes
> - link to v6: https://lore.kernel.org/linux-devicetree/20260411024743.195385-1-dennis at ausil.us/
>
> Changes in v6:
> - Move the shared configs for the Orange Pi 5 and Orange Pi 5b from each
>   devices dts to a shared rk3588s-orangepi-5-5b.dtsi to avoid duplication
> - Remove empty ports subnodeis from typea_con
> - Move i2s2m1_mclk pinctrl from &i2s2 to the es8388 codec node
> - Add dp-con, dp0_out, dp0_in, and vp1 nodes, plus the vcc3v3_dp regulator
>   in order to get the second HDMI port working via its transparent
>   LT8711UXD DP to HDMI bridge
> - link to v5: https://lore.kernel.org/linux-devicetree/20260401010707.2584962-1-dennis at ausil.us/
>
> Changes in v5:
> - define a connector node for Type-A port, and list the regulator as its VBUS supply explicitly.
> - Requires https://lore.kernel.org/all/20260217-typea-vbus-v1-1-657b4e55a4c2 at flipper.net/
> - link to v4: https://lore.kernel.org/linux-devicetree/20260310031002.3921234-1-dennis at ausil.us/
>
> Changes in v4:
> - rename vcc3v3_pcie20 copied from rk3588s-orangepi-5.dts to vcc3v3_phy1 to match the schematic
> - use vcc_3v3_s3 as the supply not vcc5v0_sys for PCIe
> - remove the definition for vcc3v3_pcie_m2 as it does not really exist
>   as a regulator
> - link to v3: https://lore.kernel.org/linux-devicetree/20260306024634.239614-1-dennis at ausil.us/
>
> Changes in v3:
> - moved leds from gpio-leds to pwm-leds
> - remove disable-wp from sdio
> - rename vcc3v3_pcie_eth regulator to vcc3v3_pcie_m2 to reflect the
>   purpose
> - actually clean up the delete lines and comments missed in v2
> - link to v2: https://lore.kernel.org/linux-devicetree/20260304025521.210377-1-dennis at ausil.us/
>
> Changes in v2:
> - moved items not shared by orangepi 5/5b/5 Pro from dtsi to 5 and 5b
>   dts files
> - removed all the comments and deleted properties from 5 Pro dts
> - link to v1: https://lore.kernel.org/linux-devicetree/20260228205418.2944620-1-dennis at ausil.us/
>
> Dennis Gilmore (4):
>   dt-bindings: arm: rockchip: Add Orange Pi 5 Pro
>   arm64: dts: rockchip: rk3588s-orangepi-5: rename PLDO regulator labels
>     to match schematic
>   arm64: dts: rockchip: refactor items from Orange Pi 5/b to prep for
>     Pro
>   arm64: dts: rockchip: Add Orange Pi 5 Pro board support
>
>  .../devicetree/bindings/arm/rockchip.yaml     |   1 +
>  arch/arm64/boot/dts/rockchip/Makefile         |   1 +
>  .../dts/rockchip/rk3588s-orangepi-5-5b.dtsi   | 256 +++++++++++++
>  .../dts/rockchip/rk3588s-orangepi-5-pro.dts   | 358 ++++++++++++++++++
>  .../boot/dts/rockchip/rk3588s-orangepi-5.dts  |   6 +-
>  .../boot/dts/rockchip/rk3588s-orangepi-5.dtsi | 263 +------------
>  .../boot/dts/rockchip/rk3588s-orangepi-5b.dts |   2 +-
>  7 files changed, 637 insertions(+), 250 deletions(-)
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-5b.dtsi
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5-pro.dts
>
> --
> 2.54.0
>


From phucduc.bui at gmail.com  Wed Jun  3 20:35:50 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Thu,  4 Jun 2026 10:35:50 +0700
Subject: [PATCH v2 0/3] ASoC: rockchip: Use guard() for spin locks
Message-ID: <20260604033554.96996-1-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Hi all,

This series converts spinlock handling in the Rockchip sound drivers
to use guard() helpers.
The changes are code cleanup only and should have no functional impact.

Changes in v2:
 - Remove the unnecessary err_pm_put label in rockchip_sai_hw_params().

Compile tested only.

Best regards,
Phuc

bui duc phuc (3):
  ASoC: rockchip: rockchip_i2s: Use guard() for spin locks
  ASoC: rockchip: i2s-tdm: Use guard() for spin locks
  ASoC: rockchip: rockchip_sai: Use guard() for spin locks

 sound/soc/rockchip/rockchip_i2s.c     | 160 ++++++++--------
 sound/soc/rockchip/rockchip_i2s_tdm.c |   8 +-
 sound/soc/rockchip/rockchip_sai.c     | 262 +++++++++++++-------------
 3 files changed, 211 insertions(+), 219 deletions(-)

-- 
2.43.0



From phucduc.bui at gmail.com  Wed Jun  3 20:35:51 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Thu,  4 Jun 2026 10:35:51 +0700
Subject: [PATCH v2 1/3] ASoC: rockchip: rockchip_i2s: Use guard() for spin locks
In-Reply-To: <20260604033554.96996-1-phucduc.bui@gmail.com>
References: <20260604033554.96996-1-phucduc.bui@gmail.com>
Message-ID: <20260604033554.96996-2-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.

 sound/soc/rockchip/rockchip_i2s.c | 160 +++++++++++++++---------------
 1 file changed, 80 insertions(+), 80 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 0a0a95b4f520..5a5087f4ae03 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -127,52 +127,52 @@ static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 	unsigned int val = 0;
 	int ret = 0;
 
-	spin_lock(&i2s->lock);
-	if (on) {
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_TDE_ENABLE,
-					 I2S_DMACR_TDE_ENABLE);
-		if (ret < 0)
-			goto end;
-		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-		if (ret < 0)
-			goto end;
-		i2s->tx_start = true;
-	} else {
-		i2s->tx_start = false;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_TDE_ENABLE,
-					 I2S_DMACR_TDE_DISABLE);
-		if (ret < 0)
-			goto end;
-
-		if (!i2s->rx_start) {
+	scoped_guard(spinlock, &i2s->lock) {
+		if (on) {
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_TDE_ENABLE,
+						 I2S_DMACR_TDE_ENABLE);
+			if (ret < 0)
+				break;
 			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
 						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+						 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 			if (ret < 0)
-				goto end;
-			udelay(150);
-			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
-						 I2S_CLR_TXC | I2S_CLR_RXC,
-						 I2S_CLR_TXC | I2S_CLR_RXC);
-			if (ret < 0)
-				goto end;
-			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
-							      I2S_CLR,
-							      val,
-							      val == 0,
-							      20,
-							      200);
+				break;
+			i2s->tx_start = true;
+		} else {
+			i2s->tx_start = false;
+
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_TDE_ENABLE,
+						 I2S_DMACR_TDE_DISABLE);
 			if (ret < 0)
-				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+				break;
+
+			if (!i2s->rx_start) {
+				ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+							 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+							 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+				if (ret < 0)
+					break;
+				udelay(150);
+				ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+							 I2S_CLR_TXC | I2S_CLR_RXC,
+						 I2S_CLR_TXC | I2S_CLR_RXC);
+				if (ret < 0)
+					break;
+				ret = regmap_read_poll_timeout_atomic(i2s->regmap,
+								      I2S_CLR,
+								      val,
+								      val == 0,
+								      20,
+								      200);
+				if (ret < 0)
+					dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+			}
 		}
 	}
-end:
-	spin_unlock(&i2s->lock);
+
 	if (ret < 0)
 		dev_err(i2s->dev, "lrclk update failed\n");
 
@@ -184,53 +184,53 @@ static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 	unsigned int val = 0;
 	int ret = 0;
 
-	spin_lock(&i2s->lock);
-	if (on) {
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_RDE_ENABLE,
-					 I2S_DMACR_RDE_ENABLE);
-		if (ret < 0)
-			goto end;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
-		if (ret < 0)
-			goto end;
-		i2s->rx_start = true;
-	} else {
-		i2s->rx_start = false;
-
-		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
-					 I2S_DMACR_RDE_ENABLE,
-					 I2S_DMACR_RDE_DISABLE);
-		if (ret < 0)
-			goto end;
+	scoped_guard(spinlock, &i2s->lock) {
+		if (on) {
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_RDE_ENABLE,
+						 I2S_DMACR_RDE_ENABLE);
+			if (ret < 0)
+				break;
 
-		if (!i2s->tx_start) {
 			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
 						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+						 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 			if (ret < 0)
-				goto end;
-			udelay(150);
-			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
-						 I2S_CLR_TXC | I2S_CLR_RXC,
-						 I2S_CLR_TXC | I2S_CLR_RXC);
-			if (ret < 0)
-				goto end;
-			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
-							      I2S_CLR,
-							      val,
-							      val == 0,
-							      20,
-							      200);
+				break;
+			i2s->rx_start = true;
+		} else {
+			i2s->rx_start = false;
+
+			ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+						 I2S_DMACR_RDE_ENABLE,
+						 I2S_DMACR_RDE_DISABLE);
 			if (ret < 0)
-				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+				break;
+
+			if (!i2s->tx_start) {
+				ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+							 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+							 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
+				if (ret < 0)
+					break;
+				udelay(150);
+				ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+							 I2S_CLR_TXC | I2S_CLR_RXC,
+							 I2S_CLR_TXC | I2S_CLR_RXC);
+				if (ret < 0)
+					break;
+				ret = regmap_read_poll_timeout_atomic(i2s->regmap,
+								      I2S_CLR,
+								      val,
+								      val == 0,
+								      20,
+								      200);
+				if (ret < 0)
+					dev_warn(i2s->dev, "fail to clear: %d\n", ret);
+			}
 		}
 	}
-end:
-	spin_unlock(&i2s->lock);
+
 	if (ret < 0)
 		dev_err(i2s->dev, "lrclk update failed\n");
 
-- 
2.43.0



From phucduc.bui at gmail.com  Wed Jun  3 20:35:52 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Thu,  4 Jun 2026 10:35:52 +0700
Subject: [PATCH v2 2/3] ASoC: rockchip: i2s-tdm: Use guard() for spin locks
In-Reply-To: <20260604033554.96996-1-phucduc.bui@gmail.com>
References: <20260604033554.96996-1-phucduc.bui@gmail.com>
Message-ID: <20260604033554.96996-3-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.

 sound/soc/rockchip/rockchip_i2s_tdm.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index fc52149ed6ae..3f3db28b8940 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -285,9 +285,8 @@ static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai, int on)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
-	unsigned long flags;
 
-	spin_lock_irqsave(&i2s_tdm->lock, flags);
+	guard(spinlock_irqsave)(&i2s_tdm->lock);
 	if (on) {
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			rockchip_enable_tde(i2s_tdm->regmap);
@@ -313,7 +312,6 @@ static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,
 						I2S_CLR_TXC | I2S_CLR_RXC);
 		}
 	}
-	spin_unlock_irqrestore(&i2s_tdm->lock, flags);
 }
 
 static void rockchip_snd_txctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on)
@@ -587,12 +585,11 @@ static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,
 				  unsigned int fmt)
 {
 	struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);
-	unsigned long flags;
 
 	if (!i2s_tdm->clk_trcm)
 		return 0;
 
-	spin_lock_irqsave(&i2s_tdm->lock, flags);
+	guard(spinlock_irqsave)(&i2s_tdm->lock);
 	if (i2s_tdm->refcount)
 		rockchip_i2s_tdm_xfer_pause(substream, i2s_tdm);
 
@@ -614,7 +611,6 @@ static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,
 
 	if (i2s_tdm->refcount)
 		rockchip_i2s_tdm_xfer_resume(substream, i2s_tdm);
-	spin_unlock_irqrestore(&i2s_tdm->lock, flags);
 
 	return 0;
 }
-- 
2.43.0



From phucduc.bui at gmail.com  Wed Jun  3 20:35:53 2026
From: phucduc.bui at gmail.com (phucduc.bui at gmail.com)
Date: Thu,  4 Jun 2026 10:35:53 +0700
Subject: [PATCH v2 3/3] ASoC: rockchip: rockchip_sai: Use guard() for spin locks
In-Reply-To: <20260604033554.96996-1-phucduc.bui@gmail.com>
References: <20260604033554.96996-1-phucduc.bui@gmail.com>
Message-ID: <20260604033554.96996-4-phucduc.bui@gmail.com>

From: bui duc phuc <phucduc.bui at gmail.com>

Clean up the code using guard() for spin locks.
Merely code refactoring, and no behavior change.

Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
---

NOTE: This patch is compile-tested only.
Changes in v2:
 - Remove the unnecessary err_pm_put label in rockchip_sai_hw_params().

 sound/soc/rockchip/rockchip_sai.c | 262 +++++++++++++++---------------
 1 file changed, 129 insertions(+), 133 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index ed393e5034a4..a195e96fed0a 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -18,7 +18,6 @@
 #include <sound/pcm_params.h>
 #include <sound/dmaengine_pcm.h>
 #include <sound/tlv.h>
-
 #include "rockchip_sai.h"
 
 #define DRV_NAME		"rockchip-sai"
@@ -216,14 +215,12 @@ static void rockchip_sai_xfer_clk_stop_and_wait(struct rk_sai_dev *sai, unsigned
 static int rockchip_sai_runtime_suspend(struct device *dev)
 {
 	struct rk_sai_dev *sai = dev_get_drvdata(dev);
-	unsigned long flags;
 
 	rockchip_sai_fsync_lost_detect(sai, 0);
 	rockchip_sai_fsync_err_detect(sai, 0);
 
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock)
+		rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
 
 	regcache_cache_only(sai->regmap, true);
 	/*
@@ -483,7 +480,6 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
 	unsigned int mask = 0, val = 0;
 	unsigned int clk_gates;
-	unsigned long flags;
 	int ret = 0;
 
 	pm_runtime_get_sync(dai->dev);
@@ -499,56 +495,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		sai->is_master_mode = false;
 		break;
 	default:
-		ret = -EINVAL;
-		goto err_pm_put;
-	}
-
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
-	if (sai->initialized) {
-		if (sai->has_capture && sai->has_playback)
-			rockchip_sai_xfer_stop(sai, -1);
-		else if (sai->has_capture)
-			rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
-		else
-			rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
-	} else {
-		rockchip_sai_clear(sai, 0);
-		sai->initialized = true;
+		pm_runtime_put(dai->dev);
+		return -EINVAL;
 	}
 
-	regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
+		rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+		if (sai->initialized) {
+			if (sai->has_capture && sai->has_playback)
+				rockchip_sai_xfer_stop(sai, -1);
+			else if (sai->has_capture)
+				rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
+			else
+				rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
+		} else {
+			rockchip_sai_clear(sai, 0);
+			sai->initialized = true;
+		}
 
-	mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
-	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
-	case SND_SOC_DAIFMT_NB_NF:
-		val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
-		break;
-	case SND_SOC_DAIFMT_NB_IF:
-		val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
-		break;
-	case SND_SOC_DAIFMT_IB_NF:
-		val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
-		break;
-	case SND_SOC_DAIFMT_IB_IF:
-		val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
-		break;
-	default:
-		ret = -EINVAL;
-		goto err_xfer_unlock;
-	}
+		regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+
+		mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
+			break;
+		default:
+			ret = -EINVAL;
+			break;
+		}
 
-	regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+		if (ret == 0) {
+			regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+			rockchip_sai_fmt_create(sai, fmt);
+		}
 
-	rockchip_sai_fmt_create(sai, fmt);
+		if (clk_gates)
+			regmap_update_bits(sai->regmap, SAI_XFER,
+					SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+					clk_gates);
+	}
 
-err_xfer_unlock:
-	if (clk_gates)
-		regmap_update_bits(sai->regmap, SAI_XFER,
-				SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
-				clk_gates);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
-err_pm_put:
 	pm_runtime_put(dai->dev);
 
 	return ret;
@@ -564,7 +560,6 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
 	unsigned int ch_per_lane, slot_width;
 	unsigned int val, fscr, reg;
 	unsigned int lanes, req_lanes;
-	unsigned long flags;
 	int ret = 0;
 
 	if (!rockchip_sai_stream_valid(substream, dai))
@@ -591,8 +586,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
 			dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
 				lanes, reg == SAI_TXCR ? "playback" : "capture",
 				params_channels(params));
-			ret = -EINVAL;
-			goto err_pm_put;
+			pm_runtime_put(sai->dev);
+			return -EINVAL;
 		} else {
 			lanes = req_lanes;
 		}
@@ -618,84 +613,88 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
 		val = SAI_XCR_VDW(32);
 		break;
 	default:
-		ret = -EINVAL;
-		goto err_pm_put;
+		pm_runtime_put(sai->dev);
+		return -EINVAL;
 	}
 
 	val |= SAI_XCR_CSR(lanes);
 
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-
-	regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
 
-	if (!sai->is_tdm)
-		regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
-				   SAI_XCR_SBW(params_physical_width(params)));
+		regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
 
-	regmap_read(sai->regmap, reg, &val);
+		if (!sai->is_tdm)
+			regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
+					   SAI_XCR_SBW(params_physical_width(params)));
 
-	slot_width = SAI_XCR_SBW_V(val);
-	ch_per_lane = params_channels(params) / lanes;
+		regmap_read(sai->regmap, reg, &val);
 
-	regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
-			   SAI_XCR_SNB(ch_per_lane));
+		slot_width = SAI_XCR_SBW_V(val);
+		ch_per_lane = params_channels(params) / lanes;
 
-	fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
+		regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
+				   SAI_XCR_SNB(ch_per_lane));
 
-	switch (sai->fpw) {
-	case FPW_ONE_BCLK_WIDTH:
-		fscr |= SAI_FSCR_FPW(1);
-		break;
-	case FPW_ONE_SLOT_WIDTH:
-		fscr |= SAI_FSCR_FPW(slot_width);
-		break;
-	case FPW_HALF_FRAME_WIDTH:
-		fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
-		break;
-	default:
-		dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
-		ret = -EINVAL;
-		goto err_xfer_unlock;
-	}
+		fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
 
-	regmap_update_bits(sai->regmap, SAI_FSCR,
-			   SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
-
-	if (sai->is_master_mode) {
-		bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
-		ret = clk_set_rate(sai->mclk, sai->mclk_rate);
-		if (ret) {
-			dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
-				sai->mclk_rate, ERR_PTR(ret));
-			goto err_xfer_unlock;
-		}
-
-		mclk_rate = clk_get_rate(sai->mclk);
-		if (mclk_rate < bclk_rate) {
-			dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
-				mclk_rate, bclk_rate);
+		switch (sai->fpw) {
+		case FPW_ONE_BCLK_WIDTH:
+			fscr |= SAI_FSCR_FPW(1);
+			break;
+		case FPW_ONE_SLOT_WIDTH:
+			fscr |= SAI_FSCR_FPW(slot_width);
+			break;
+		case FPW_HALF_FRAME_WIDTH:
+			fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
+			break;
+		default:
+			dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
 			ret = -EINVAL;
-			goto err_xfer_unlock;
+			break;
 		}
 
-		div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
-		mclk_req_rate = bclk_rate * div_bclk;
-
-		if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
-		    mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
-			dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
-				mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
-			ret = -EINVAL;
-			goto err_xfer_unlock;
+		if (ret == 0) {
+			regmap_update_bits(sai->regmap, SAI_FSCR,
+					   SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
+
+			if (sai->is_master_mode) {
+				bclk_rate = sai->fw_ratio * slot_width *
+						ch_per_lane * params_rate(params);
+				ret = clk_set_rate(sai->mclk, sai->mclk_rate);
+				if (ret)
+					dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
+						sai->mclk_rate, ERR_PTR(ret));
+				else {
+					mclk_rate = clk_get_rate(sai->mclk);
+					if (mclk_rate < bclk_rate) {
+						dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
+							mclk_rate, bclk_rate);
+						ret = -EINVAL;
+					} else {
+
+						div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
+						mclk_req_rate = bclk_rate * div_bclk;
+
+						if (mclk_rate <
+							mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
+						    mclk_rate >
+							mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
+							dev_err(sai->dev,
+								"Mismatch mclk: %u, expected %u (+/- %dHz)\n",
+								mclk_rate, mclk_req_rate,
+								CLK_SHIFT_RATE_HZ_MAX);
+							ret = -EINVAL;
+						} else
+							regmap_update_bits(sai->regmap,
+									SAI_CKR,
+									SAI_CKR_MDIV_MASK,
+									SAI_CKR_MDIV(div_bclk));
+					}
+				}
+			}
 		}
-
-		regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
-				   SAI_CKR_MDIV(div_bclk));
 	}
 
-err_xfer_unlock:
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
-err_pm_put:
 	pm_runtime_put(sai->dev);
 
 	return ret;
@@ -705,7 +704,6 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
 				struct snd_soc_dai *dai)
 {
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
-	unsigned long flags;
 
 	if (!rockchip_sai_stream_valid(substream, dai))
 		return 0;
@@ -726,13 +724,12 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
 		 * udelay falls short.
 		 */
 		udelay(20);
-		spin_lock_irqsave(&sai->xfer_lock, flags);
-		regmap_update_bits(sai->regmap, SAI_XFER,
-				   SAI_XFER_CLK_MASK |
-				   SAI_XFER_FSS_MASK,
-				   SAI_XFER_CLK_EN |
-				   SAI_XFER_FSS_EN);
-		spin_unlock_irqrestore(&sai->xfer_lock, flags);
+		scoped_guard(spinlock_irqsave, &sai->xfer_lock)
+			regmap_update_bits(sai->regmap, SAI_XFER,
+					   SAI_XFER_CLK_MASK |
+					   SAI_XFER_FSS_MASK,
+					   SAI_XFER_CLK_EN |
+					   SAI_XFER_FSS_EN);
 	}
 
 	rockchip_sai_fsync_lost_detect(sai, 1);
@@ -915,7 +912,6 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
 				     int slots, int slot_width)
 {
 	struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
-	unsigned long flags;
 	unsigned int clk_gates;
 	int sw = slot_width;
 
@@ -931,16 +927,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
 		return -EINVAL;
 
 	pm_runtime_get_sync(dai->dev);
-	spin_lock_irqsave(&sai->xfer_lock, flags);
-	rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
-	regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
-			   SAI_XCR_SBW(sw));
-	regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
-			   SAI_XCR_SBW(sw));
-	regmap_update_bits(sai->regmap, SAI_XFER,
-			   SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
-			   clk_gates);
-	spin_unlock_irqrestore(&sai->xfer_lock, flags);
+	scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
+		rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+		regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
+				   SAI_XCR_SBW(sw));
+		regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
+				   SAI_XCR_SBW(sw));
+		regmap_update_bits(sai->regmap, SAI_XFER,
+				   SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+				   clk_gates);
+	}
 	pm_runtime_put(dai->dev);
 
 	return 0;
-- 
2.43.0



From geert at linux-m68k.org  Thu Jun  4 00:56:04 2026
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Thu, 4 Jun 2026 09:56:04 +0200
Subject: [PATCH] clk: rockchip: don't COMPILE_TEST builds on M68K
In-Reply-To: <20260603213726.1025094-1-heiko@sntech.de>
References: <20260603213726.1025094-1-heiko@sntech.de>
Message-ID: <CAMuHMdUAoUmCNMBVRGgZzSt9SbZqV6SVW2brkvsBKuHrfWHKvw@mail.gmail.com>

Hi Heiko,

On Wed, 3 Jun 2026 at 23:37, Heiko Stuebner <heiko at sntech.de> wrote:
> Rockchip clock drivers use hash-tables with enums as inputs.
>
> M68K does interesting things in its __hash_32() implementation, casting
> that u32 input to an u16 and therefore triggering warnings like:
>
>    drivers/clk/rockchip/clk-rk3528.c: note: in included file (through include/linux/hash.h, include/linux/slab.h):
>      arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (18720 becomes 8720)
>      arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (1e8e8 becomes e8e8)
>
> As M68K should never ever need Rockchip clock drivers, simply disable
> compile-tests for M68K.
>
> Fixes: 7edfb7fb58ee ("clk: rockchip: allow COMPILE_TEST builds")
> Reported-by: kernel test robot <lkp at intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202605191434.PQkj2Rki-lkp at intel.com/
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

Thanks for your patch!

> --- a/drivers/clk/rockchip/Kconfig
> +++ b/drivers/clk/rockchip/Kconfig
> @@ -4,6 +4,7 @@
>  config COMMON_CLK_ROCKCHIP
>         bool "Rockchip clock controller common support"
>         depends on ARCH_ROCKCHIP || COMPILE_TEST
> +       depends on !M68K
>         default ARCH_ROCKCHIP
>         help
>           Say y here to enable common clock controller for Rockchip platforms.

Obviously this is the wrong fix ;-)

I have sent a better one, fixing the issue for every user:
"[PATCH] m68k: hash: Use lower_16_bits() helper"
https://lore.kernel.org/b55e9bd0532c0cad519809c86e0a8400060d75a1.1780559561.git.geert at linux-m68k.org

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 damon.ding at rock-chips.com  Thu Jun  4 01:52:19 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Thu,  4 Jun 2026 16:52:19 +0800
Subject: [PATCH v5 3/4] drm/bridge: analogix_dp: Add validation for samsung,lane-count property
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
References: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Message-ID: <20260604085220.2862986-4-damon.ding@rock-chips.com>

Add validity check for samsung,lane-count to ensure DT-provided
lane count values are specification-compliant.

Suggested-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>

---

Changes in v5:
- Apply DRM DP helper API to check the validity of DP lane count.
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5dc07ff84cd3..9300b0db8785 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1238,6 +1238,7 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 {
 	struct device_node *dp_node = dp->dev->of_node;
 	struct video_info *video_info = &dp->video_info;
+	int ret;
 
 	switch (dp->plat_data->dev_type) {
 	case RK3288_DP:
@@ -1261,8 +1262,11 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 		 */
 		of_property_read_u32(dp_node, "samsung,link-rate",
 				     &video_info->max_link_rate);
-		of_property_read_u32(dp_node, "samsung,lane-count",
-				     &video_info->max_lane_count);
+		ret = of_property_read_u32(dp_node, "samsung,lane-count",
+					   &video_info->max_lane_count);
+		if (ret || !drm_dp_lane_count_is_valid(video_info->max_lane_count))
+			return dev_err_probe(dp->dev, ret ? ret : -EINVAL,
+					     "failed to parse samsung,lane-count\n");
 		break;
 	}
 
-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 01:52:17 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Thu,  4 Jun 2026 16:52:17 +0800
Subject: [PATCH v5 1/4] dt-bindings: display: bridge: analogix-dp: Add data-lanes support for endpoint
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
References: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Message-ID: <20260604085220.2862986-2-damon.ding@rock-chips.com>

Add data-lanes property support to the port at 1 endpoint for physical
lane mapping configuration.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

Additionally, add data-lanes setting in Rockchip eDP DT node example
to show actual lane mapping usage.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>

---

Changes in v2:
- Add lane mapping application scenarios in commit message.
- Remove redundant deprecated property 'data-lanes' for eDP node.
- Update port at 1 $ref to /schemas/graph.yaml#/$defs/port-base.

Changes in v3:
- Squash data-lanes adjustment of Rockchip eDP DT example into this
  commit.
- Add unevaluatedProperties: false to both the port at 1 and endpoint
  nodes.

Changes in v5
- Add Acked-by and Reviewed-by tags.
---
 .../bindings/display/bridge/analogix,dp.yaml  | 19 ++++++++++++++-----
 .../rockchip/rockchip,analogix-dp.yaml        |  1 +
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
index 62f0521b0924..ecf206871cdd 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
+++ b/Documentation/devicetree/bindings/display/bridge/analogix,dp.yaml
@@ -42,13 +42,22 @@ properties:
     properties:
       port at 0:
         $ref: /schemas/graph.yaml#/properties/port
-        description:
-          Input node to receive pixel data.
+        description: Input node to receive pixel data.
 
       port at 1:
-        $ref: /schemas/graph.yaml#/properties/port
-        description:
-          Port node with one endpoint connected to a dp-connector node.
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: Port node with one endpoint connected to sink device node.
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+            properties:
+              data-lanes:
+                minItems: 1
+                maxItems: 4
+                items:
+                  enum: [ 0, 1, 2, 3 ]
 
     required:
       - port at 0
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
index 6548f157fd96..39dafe75a680 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml
@@ -160,6 +160,7 @@ examples:
           reg = <1>;
 
           edp_out_panel: endpoint {
+            data-lanes = <0 1>;
             remote-endpoint = <&panel_in_edp>;
           };
         };
-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 01:52:20 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Thu,  4 Jun 2026 16:52:20 +0800
Subject: [PATCH v5 4/4] drm/bridge: analogix_dp: Add support for optional data-lanes mapping
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
References: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Message-ID: <20260604085220.2862986-5-damon.ding@rock-chips.com>

Parse the optional 'data-lanes' device tree property to support
custom physical lane mapping configuration.

If no valid configuration is found, fall back to the default
lane map (0, 1, 2, 3) automatically and keep the driver running.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>

---

Changes in v2:
- Add lane mapping application scenarios in commit message.

Changes in v5:
- Add Reviewed-by tag.
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 56 +++++++++++++++++++
 .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
 .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
 .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
 4 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 9300b0db8785..ea525aa3effd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1234,6 +1234,59 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
 	.detect = analogix_dp_bridge_detect,
 };
 
+static int analogix_dp_dt_parse_lanes_map(struct analogix_dp_device *dp)
+{
+	struct video_info *video_info = &dp->video_info;
+	struct device_node *endpoint;
+	u32 tmp[LANE_COUNT4];
+	u32 map[LANE_COUNT4] = {0, 1, 2, 3};
+	bool used[LANE_COUNT4] = {false};
+	int num_lanes;
+	int ret, i;
+
+	memcpy(video_info->lane_map, map, sizeof(map));
+
+	num_lanes = drm_of_get_data_lanes_count_ep(dp->dev->of_node, 1, 0, 1,
+						   video_info->max_lane_count);
+	if (num_lanes < 0)
+		return -EINVAL;
+
+	endpoint = of_graph_get_endpoint_by_regs(dp->dev->of_node, 1, -1);
+	if (!endpoint)
+		return -EINVAL;
+
+	ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, num_lanes);
+	of_node_put(endpoint);
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < num_lanes; i++) {
+		if (tmp[i] >= LANE_COUNT4) {
+			dev_dbg(dp->dev, "data-lanes[%d] = %u is out of range\n", i, tmp[i]);
+			return -EINVAL;
+		}
+
+		if (used[tmp[i]]) {
+			dev_dbg(dp->dev, "data-lanes[%d] = %u is duplicate\n", i, tmp[i]);
+			return -EINVAL;
+		}
+
+		used[tmp[i]] = true;
+		map[i] = tmp[i];
+	}
+
+	for (i = 0; i < LANE_COUNT4 && num_lanes < LANE_COUNT4; i++) {
+		if (!used[i])
+			map[num_lanes++] = i;
+	}
+
+	dev_dbg(dp->dev, "Using parsed lane map: <%u %u %u %u>\n", map[0], map[1], map[2], map[3]);
+
+	memcpy(video_info->lane_map, map, sizeof(map));
+
+	return 0;
+}
+
 static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 {
 	struct device_node *dp_node = dp->dev->of_node;
@@ -1270,6 +1323,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 		break;
 	}
 
+	if (analogix_dp_dt_parse_lanes_map(dp))
+		dev_dbg(dp->dev, "No valid data-lanes found, using default lane map\n");
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 94348c4e3623..a75d0fb8f980 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -137,6 +137,8 @@ struct video_info {
 
 	int max_link_rate;
 	enum link_lane_count_type max_lane_count;
+
+	u32 lane_map[LANE_COUNT4];
 };
 
 struct link_train {
@@ -175,7 +177,7 @@ struct analogix_dp_device {
 /* analogix_dp_reg.c */
 void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable);
 void analogix_dp_stop_video(struct analogix_dp_device *dp);
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable);
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp);
 void analogix_dp_init_analog_param(struct analogix_dp_device *dp);
 void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
 void analogix_dp_reset(struct analogix_dp_device *dp);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index ea8401293a23..c1344a3f013a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -48,16 +48,15 @@ void analogix_dp_stop_video(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
 }
 
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp)
 {
+	u32 *lane_map = dp->video_info.lane_map;
 	u32 reg;
 
-	if (enable)
-		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
-		      LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
-	else
-		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
-		      LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+	reg = lane_map[0] << LANE0_MAP_SHIFT;
+	reg |= lane_map[1] << LANE1_MAP_SHIFT;
+	reg |= lane_map[2] << LANE2_MAP_SHIFT;
+	reg |= lane_map[3] << LANE3_MAP_SHIFT;
 
 	writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
 }
@@ -140,7 +139,7 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
 
 	usleep_range(20, 30);
 
-	analogix_dp_lane_swap(dp, 0);
+	analogix_dp_lane_mapping(dp);
 
 	writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
 	writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 12735139046c..ac914e37089b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -209,6 +209,10 @@
 #define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
 #define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
 #define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
+#define LANE3_MAP_SHIFT				(6)
+#define LANE2_MAP_SHIFT				(4)
+#define LANE1_MAP_SHIFT				(2)
+#define LANE0_MAP_SHIFT				(0)
 
 /* ANALOGIX_DP_ANALOG_CTL_1 */
 #define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 01:52:16 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Thu,  4 Jun 2026 16:52:16 +0800
Subject: [PATCH v5 0/4] Add eDP lane mapping support
Message-ID: <20260604085220.2862986-1-damon.ding@rock-chips.com>

This series adds configurable eDP physical lane mapping support via
device tree data-lanes property.

Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
   without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
   by configuring data-lanes in device tree only.

The series includes driver implementation and device tree binding
updates to support custom lane mapping configuration from endpoint
node, and keeps default linear lane order if no configuration is given.

Patch 1: Add endpoint data-lanes property to analogix-dp binding
Patch 2: Add DRM DP helper API to validate DP lane counts
Patch 3: Add validation for samsung,lane-count property as preparation
Patch 4: Implement lane mapping in analogix_dp driver

Damon Ding (4):
  dt-bindings: display: bridge: analogix-dp: Add data-lanes support for
    endpoint
  drm/dp: Add helper to validate DP lane counts
  drm/bridge: analogix_dp: Add validation for samsung,lane-count
    property
  drm/bridge: analogix_dp: Add support for optional data-lanes mapping

 .../bindings/display/bridge/analogix,dp.yaml  | 19 ++++--
 .../rockchip/rockchip,analogix-dp.yaml        |  1 +
 .../drm/bridge/analogix/analogix_dp_core.c    | 64 ++++++++++++++++++-
 .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
 .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 ++---
 .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
 include/drm/display/drm_dp_helper.h           |  6 ++
 7 files changed, 97 insertions(+), 16 deletions(-)

---

Changes in v2:
- Add lane mapping application scenarios in commit message.
- Remove redundant deprecated property 'data-lanes' for eDP node.
- Update port at 1 $ref to /schemas/graph.yaml#/$defs/port-base.

Changes in v3:
- Squash [PATCH v2 2/3] into [PATCH v2 1/3].
- Add unevaluatedProperties: false to both the port at 1 and endpoint
  nodes.

Changes in v4:
- Add validation for samsung,lane-count property as preparation.

Changes in v5:
- Add DRM DP helper API to validate DP lane counts.
- Apply DRM DP helper API to check the validity of samsung,lane-count
  property.
- Add Acked-by and Reviewed-by tags.

-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 01:52:18 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Thu,  4 Jun 2026 16:52:18 +0800
Subject: [PATCH v5 2/4] drm/dp: Add helper to validate DP lane counts
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
References: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Message-ID: <20260604085220.2862986-3-damon.ding@rock-chips.com>

Add a generic helper function drm_dp_lane_count_is_valid() to check
if a DisplayPort lane count is valid. According to the DP specification,
only 1, 2, or 4 lanes are supported.

This helper avoids duplicating DP lane count validation logic across
individual DisplayPort drivers.

Suggested-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
---
 include/drm/display/drm_dp_helper.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h
index 8c2d77a032f0..c904cb480d84 100644
--- a/include/drm/display/drm_dp_helper.h
+++ b/include/drm/display/drm_dp_helper.h
@@ -138,6 +138,12 @@ bool drm_dp_as_sdp_supported(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_C
 
 int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]);
 
+static inline bool
+drm_dp_lane_count_is_valid(int lane_count)
+{
+	return lane_count == 1 || lane_count == 2 || lane_count == 4;
+}
+
 static inline int
 drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 {
-- 
2.34.1



From heiko at sntech.de  Thu Jun  4 01:59:19 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 04 Jun 2026 10:59:19 +0200
Subject: [PATCH] clk: rockchip: don't COMPILE_TEST builds on M68K
In-Reply-To: <CAMuHMdUAoUmCNMBVRGgZzSt9SbZqV6SVW2brkvsBKuHrfWHKvw@mail.gmail.com>
References: <20260603213726.1025094-1-heiko@sntech.de>
 <CAMuHMdUAoUmCNMBVRGgZzSt9SbZqV6SVW2brkvsBKuHrfWHKvw@mail.gmail.com>
Message-ID: <36034140.aRNtrjHk3s@phil>

Hi Geert,

Am Donnerstag, 4. Juni 2026, 09:56:04 Mitteleurop?ische Sommerzeit schrieb Geert Uytterhoeven:
> On Wed, 3 Jun 2026 at 23:37, Heiko Stuebner <heiko at sntech.de> wrote:
> > Rockchip clock drivers use hash-tables with enums as inputs.
> >
> > M68K does interesting things in its __hash_32() implementation, casting
> > that u32 input to an u16 and therefore triggering warnings like:
> >
> >    drivers/clk/rockchip/clk-rk3528.c: note: in included file (through include/linux/hash.h, include/linux/slab.h):
> >      arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (18720 becomes 8720)
> >      arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (1e8e8 becomes e8e8)
> >
> > As M68K should never ever need Rockchip clock drivers, simply disable
> > compile-tests for M68K.
> >
> > Fixes: 7edfb7fb58ee ("clk: rockchip: allow COMPILE_TEST builds")
> > Reported-by: kernel test robot <lkp at intel.com>
> > Closes: https://lore.kernel.org/oe-kbuild-all/202605191434.PQkj2Rki-lkp at intel.com/
> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> 
> Thanks for your patch!
> 
> > --- a/drivers/clk/rockchip/Kconfig
> > +++ b/drivers/clk/rockchip/Kconfig
> > @@ -4,6 +4,7 @@
> >  config COMMON_CLK_ROCKCHIP
> >         bool "Rockchip clock controller common support"
> >         depends on ARCH_ROCKCHIP || COMPILE_TEST
> > +       depends on !M68K
> >         default ARCH_ROCKCHIP
> >         help
> >           Say y here to enable common clock controller for Rockchip platforms.
> 
> Obviously this is the wrong fix ;-)
> 
> I have sent a better one, fixing the issue for every user:
> "[PATCH] m68k: hash: Use lower_16_bits() helper"
> https://lore.kernel.org/b55e9bd0532c0cad519809c86e0a8400060d75a1.1780559561.git.geert at linux-m68k.org

oh nice - fixing the actual problem instead of working around the
issue. I had no clue about m68k and thus no idea of how to test
anything, so went for the easx "fix" :-)


So thanks for looking into that
Heiko




From heiko at sntech.de  Thu Jun  4 02:27:34 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 04 Jun 2026 11:27:34 +0200
Subject: [GIT PULL] Rockchip arm32 fix for the current 7.1-rc
Message-ID: <4474108.o2A3GueYyp@phil>

Hi SoC maintainers,

please find a below a fix for an issue in the ARCH code for 32bit
Rockchip SoCs, that appeared with 7.1-rc .


Please pull

Thanks
Heiko


The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v7.1-rockchip-arm32fixe

for you to fetch changes up to 6fc5666aa576c6c3bec256fa31d72653210319d5:

  ARM: rockchip: keep reset control around (2026-05-26 23:20:39 +0200)

----------------------------------------------------------------
A change in 7.1-rc improved the general handling for reset controllers
using SRCU, but at the same time broke really early users before work-
queues are available.

So adapt the SMP bringup to keep the core-resets around, instead
of aquiring/releasing them on ever SMP action.

----------------------------------------------------------------
Heiko Stuebner (1):
      ARM: rockchip: keep reset control around

 arch/arm/mach-rockchip/platsmp.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)





From andy.yan at rock-chips.com  Thu Jun  4 04:32:20 2026
From: andy.yan at rock-chips.com (Andy Yan)
Date: Thu, 4 Jun 2026 19:32:20 +0800
Subject: [PATCH v2 03/12] drm/bridge: synopsys: dw-dp: Simplify driver
 data setting
In-Reply-To: <20260501-synopsys-dw-dp-improvements-v2-3-d7e7f6bac77f@collabora.com>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-3-d7e7f6bac77f@collabora.com>
Message-ID: <c3b829f2-8f8f-4b76-bbd6-977ee49e32d1@rock-chips.com>

Hello,

On 5/1/26 06:20, Sebastian Reichel wrote:
> There is no need to get the platform device just for setting up
> the driver data. Simplify the logic.
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>

    Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
> ---
>   drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
> index 150c2da8fee5..52e956bffb12 100644
> --- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
> @@ -74,7 +74,6 @@ static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = {
>   
>   static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *data)
>   {
> -	struct platform_device *pdev = to_platform_device(dev);
>   	const struct dw_dp_plat_data *plat_data;
>   	struct drm_device *drm_dev = data;
>   	struct rockchip_dw_dp *dp;
> @@ -87,7 +86,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
>   		return -ENOMEM;
>   
>   	dp->dev = dev;
> -	platform_set_drvdata(pdev, dp);
> +	dev_set_drvdata(dev, dp);
>   
>   	plat_data = of_device_get_match_data(dev);
>   	if (!plat_data)
> 



From diogompaissilva at gmail.com  Thu Jun  4 05:32:25 2026
From: diogompaissilva at gmail.com (Diogo Silva)
Date: Thu,  4 Jun 2026 14:32:25 +0200
Subject: [PATCH] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
Message-ID: <20260604123224.192543-2-diogompaissilva@gmail.com>

Remove the dependency on drm_simple_kms_helper by open-coding the
drm_simple_encoder_init call.

Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
---
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 3547d91b25d3..a09b382d208e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -25,7 +25,6 @@
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 	clk_disable_unprepare(dsi->grf_clk);
 }
 
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi_encoder_helper_funcs = {
 	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
@@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dsi->dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+	ret = drm_encoder_init(drm_dev, encoder,
+				&dw_mipi_dsi_encoder_funcs,
+				DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		DRM_ERROR("Failed to initialize encoder with drm\n");
 		return ret;
-- 
2.51.2



From midgy971 at gmail.com  Thu Jun  4 06:52:46 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:46 +0000
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
Message-ID: <20260604135255.62682-1-midgy971@gmail.com>

RFC, not for merge. End-to-end inference does not produce correct output
yet (see Status), so per the v2 discussion this is a request for design
feedback. It now probes, attaches, and submits cleanly on a stock
v7.1-rc6 tree; what remains is one hardware-internal issue.

The RK3568 has a single NVDLA-derived NPU core, the same IP family as the
RK3588 NPU the driver already supports; the register layout matches. The
RK3568 differences are a 32-bit NPU AXI/IOMMU (vs 40-bit) and explicit
PVTPLL/PMU bring-up to power and de-idle the NPU before it is reachable.

Patches:
  1-2  rocket: per-SoC data struct, then derive DMA width and core count
       from match data (refactors, no functional change).
  3    rocket: RK3568 SoC data + PVTPLL/PMU/NOC bring-up.
  4    rocket: reset the NPU before detaching the IOMMU on a job timeout
       (the detach otherwise stalls a wedged AXI master and WARNs).
  5    rocket: keep the IOMMU domain attached across jobs instead of
       re-attaching per job (the per-job rk_iommu handshake on the idle
       NPU MMU is slow and noisy).
  6    iommu/rockchip: clear AUTO_GATING bit 1 on the RK356x v1 IOMMU so
       the page-walker keeps its clock (else a TLB-miss walk never
       completes).
  7    dt-bindings: add the RK3568 NPU compatible.
  8-9  arm64 dts: add the NPU and its IOMMU, and enable them on ROCK 3B.

Dependency. The NPU MMU is rockchip-iommu v1 (32-bit) while the rest of
the RK3568 uses v2 (40-bit). They cannot coexist until the driver carries
per-device ops; this series is developed on top of Simon Xue's
"iommu/rockchip: Drop global rk_ops in favor of per-device ops" [1].
Without it the NPU IOMMU fails to probe on a full RK3568 boot.

Power bring-up. The NPU is brought up through the power-domain layer (no
driver hack): the NPU power-domain keeps its clocks but drops the pm_qos
phandle (qos_npu sits behind the gated NPU NoC, so genpd's power-off QoS
save faults reading it), and vdd_npu is marked always-on so the rail is
up before genpd de-idles the NoC at power-on. The PMU de-idle then ACKs
without PVTPLL running; PVTPLL is only needed for compute.

Status. On v7.1-rc6 the driver probes, creates /dev/accel/accel0,
attaches an IOMMU domain, and submits jobs; the program controller
fetches and broadcasts the command list. Inference output is still wrong,
and the cause is split across three layers:
  - kernel (this series): the RK3568 differences appear handled;
  - mesa/Teflon userspace: still emits RK3588-tuned config, wrong for
    RK3568 (to be filed separately on mesa-dev);
  - hardware: with corrected config the NPU's DMA reads the full input
    and weight tensors (confirmed via its DMA bandwidth counters), but
    the MAC/output stage never completes, the job times out, and the
    output stays at the buffer's zero-point. I have not found the missing
    step; it is not in the command list (replaying the vendor's
    byte-exact command list behaves the same). Pointers welcome,
    especially from anyone with RK3568 NPU experience.

Known residual. On the first IOMMU attach the NPU MMU is idle with paging
already enabled; the rk_iommu stall/reset handshake does not complete in
that state and logs one burst of timeouts before the (kept) domain
settles. It is harmless here because the job times out regardless, but it
points at an idle-MMU reconfiguration corner the rk_iommu code does not
handle on this block.

[1] https://lore.kernel.org/linux-rockchip/20260310105303.128859-1-xxm at rock-chips.com/

Changes since v2:
  - Tagged RFC; now tested on a stock v7.1-rc6 tree.
  - Bring-up moved into the power-domain/DT layer (no initcall hack).
  - Added the IOMMU detach-on-timeout and attach-once driver fixes.
  - Split the driver patch (Heiko): soc_data / match-data / RK3568.
  - Derive DMA width and core count from match data; drop the DT rescans.
  - Binding describes the hardware; added the missing $ref on rockchip,pmu.
  - Disclosed the per-device-ops IOMMU dependency.

Midgy BALON (9):
  accel: rocket: Introduce per-SoC rocket_soc_data
  accel: rocket: Derive DMA width and core count from match data
  accel: rocket: Add RK3568 SoC support
  accel: rocket: Reset the NPU before detaching the IOMMU on timeout
  accel: rocket: Keep the IOMMU domain attached across jobs
  iommu/rockchip: Clear AUTO_GATING bit 1 on the RK356x v1 IOMMU
  dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
  arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
  arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU

 .../npu/rockchip,rk3588-rknn-core.yaml        | 18 ++++-
 .../boot/dts/rockchip/rk3568-rock-3b.dts      | 14 +++-
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++
 drivers/accel/rocket/rocket_core.c            | 22 ++++++-
 drivers/accel/rocket/rocket_core.h            | 19 ++++++
 drivers/accel/rocket/rocket_device.c          | 15 ++---
 drivers/accel/rocket/rocket_device.h          |  3 +-
 drivers/accel/rocket/rocket_drv.c             | 66 ++++++++++++++++++-
 drivers/accel/rocket/rocket_job.c             | 35 ++++++++--
 drivers/iommu/rockchip-iommu.c                | 12 ++++
 10 files changed, 219 insertions(+), 23 deletions(-)


base-commit: 52c800fdcf11888ebeb50c3d707f782cc15b66eb
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:47 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:47 +0000
Subject: [RFC PATCH v3 1/9] accel: rocket: Introduce per-SoC rocket_soc_data
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-2-midgy971@gmail.com>

Add a per-SoC data structure carried in the OF match table, currently
holding only the NPU AXI address width, and use it for the per-core DMA
mask instead of a hardcoded 40-bit value.  No functional change: the
RK3588 AXI master is 40-bit.  This prepares for SoCs with a narrower
address width.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c |  7 ++++++-
 drivers/accel/rocket/rocket_core.h | 11 +++++++++++
 drivers/accel/rocket/rocket_drv.c  |  6 +++++-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index b3b2fa9ba645a..09c445af7de73 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -7,6 +7,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/iommu.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
@@ -21,6 +22,10 @@ int rocket_core_init(struct rocket_core *core)
 	u32 version;
 	int err = 0;
 
+	core->soc_data = of_device_get_match_data(dev);
+	if (!core->soc_data)
+		return dev_err_probe(dev, -EINVAL, "missing SoC match data\n");
+
 	core->resets[0].id = "srst_a";
 	core->resets[1].id = "srst_h";
 	err = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(core->resets),
@@ -52,7 +57,7 @@ int rocket_core_init(struct rocket_core *core)
 
 	dma_set_max_seg_size(dev, UINT_MAX);
 
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(core->soc_data->dma_bits));
 	if (err)
 		return err;
 
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index f6d7382854ca9..8ee105a0be40e 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -12,6 +12,16 @@
 
 #include "rocket_registers.h"
 
+struct rocket_core;
+
+/**
+ * struct rocket_soc_data - per-SoC configuration data
+ * @dma_bits: Physical address width reachable by the NPU's AXI master.
+ */
+struct rocket_soc_data {
+	unsigned int dma_bits;
+};
+
 #define rocket_pc_readl(core, reg) \
 	readl((core)->pc_iomem + (REG_PC_##reg))
 #define rocket_pc_writel(core, reg, value) \
@@ -31,6 +41,7 @@ struct rocket_core {
 	struct device *dev;
 	struct rocket_device *rdev;
 	unsigned int index;
+	const struct rocket_soc_data *soc_data;
 
 	int irq;
 	void __iomem *pc_iomem;
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index 8bbbce594883e..384c38e13acce 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -213,8 +213,12 @@ static void rocket_remove(struct platform_device *pdev)
 	}
 }
 
+static const struct rocket_soc_data rk3588_soc_data = {
+	.dma_bits = 40,
+};
+
 static const struct of_device_id dt_match[] = {
-	{ .compatible = "rockchip,rk3588-rknn-core" },
+	{ .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:48 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:48 +0000
Subject: [RFC PATCH v3 2/9] accel: rocket: Derive DMA width and core count from match data
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-3-midgy971@gmail.com>

The probe already has the per-SoC match data, which now records the core
count and DMA width.  Use it for the cores array allocation and the
device DMA mask instead of re-scanning the device tree for available core
nodes.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.h   |  2 ++
 drivers/accel/rocket/rocket_device.c | 15 +++++----------
 drivers/accel/rocket/rocket_device.h |  3 ++-
 drivers/accel/rocket/rocket_drv.c    |  7 ++++++-
 4 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index 8ee105a0be40e..d6421251670dc 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -16,9 +16,11 @@ struct rocket_core;
 
 /**
  * struct rocket_soc_data - per-SoC configuration data
+ * @num_cores: Number of NPU cores in this SoC.
  * @dma_bits: Physical address width reachable by the NPU's AXI master.
  */
 struct rocket_soc_data {
+	unsigned int num_cores;
 	unsigned int dma_bits;
 };
 
diff --git a/drivers/accel/rocket/rocket_device.c b/drivers/accel/rocket/rocket_device.c
index 46e6ee1e72c5f..6186f4faa3a2a 100644
--- a/drivers/accel/rocket/rocket_device.c
+++ b/drivers/accel/rocket/rocket_device.c
@@ -6,18 +6,16 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
-#include <linux/of.h>
 
 #include "rocket_device.h"
 
 struct rocket_device *rocket_device_init(struct platform_device *pdev,
-					 const struct drm_driver *rocket_drm_driver)
+					 const struct drm_driver *rocket_drm_driver,
+					 const struct rocket_soc_data *soc_data)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *core_node;
 	struct rocket_device *rdev;
 	struct drm_device *ddev;
-	unsigned int num_cores = 0;
 	int err;
 
 	rdev = devm_drm_dev_alloc(dev, rocket_drm_driver, struct rocket_device, ddev);
@@ -27,17 +25,14 @@ struct rocket_device *rocket_device_init(struct platform_device *pdev,
 	ddev = &rdev->ddev;
 	dev_set_drvdata(dev, rdev);
 
-	for_each_compatible_node(core_node, NULL, "rockchip,rk3588-rknn-core")
-		if (of_device_is_available(core_node))
-			num_cores++;
-
-	rdev->cores = devm_kcalloc(dev, num_cores, sizeof(*rdev->cores), GFP_KERNEL);
+	rdev->cores = devm_kcalloc(dev, soc_data->num_cores, sizeof(*rdev->cores),
+				   GFP_KERNEL);
 	if (!rdev->cores)
 		return ERR_PTR(-ENOMEM);
 
 	dma_set_max_seg_size(dev, UINT_MAX);
 
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(soc_data->dma_bits));
 	if (err)
 		return ERR_PTR(err);
 
diff --git a/drivers/accel/rocket/rocket_device.h b/drivers/accel/rocket/rocket_device.h
index ce662abc01d3d..2f74e078974e3 100644
--- a/drivers/accel/rocket/rocket_device.h
+++ b/drivers/accel/rocket/rocket_device.h
@@ -22,7 +22,8 @@ struct rocket_device {
 };
 
 struct rocket_device *rocket_device_init(struct platform_device *pdev,
-					 const struct drm_driver *rocket_drm_driver);
+					 const struct drm_driver *rocket_drm_driver,
+					 const struct rocket_soc_data *soc_data);
 void rocket_device_fini(struct rocket_device *rdev);
 #define to_rocket_device(drm_dev) \
 	((struct rocket_device *)(container_of((drm_dev), struct rocket_device, ddev)))
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index 384c38e13acce..c18840e5aff76 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -159,11 +159,15 @@ static const struct drm_driver rocket_drm_driver = {
 
 static int rocket_probe(struct platform_device *pdev)
 {
+	const struct rocket_soc_data *soc_data = of_device_get_match_data(&pdev->dev);
 	int ret;
 
+	if (!soc_data)
+		return -EINVAL;
+
 	if (rdev == NULL) {
 		/* First core probing, initialize DRM device. */
-		rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
+		rdev = rocket_device_init(drm_dev, &rocket_drm_driver, soc_data);
 		if (IS_ERR(rdev)) {
 			dev_err(&pdev->dev, "failed to initialize rocket device\n");
 			return PTR_ERR(rdev);
@@ -214,6 +218,7 @@ static void rocket_remove(struct platform_device *pdev)
 }
 
 static const struct rocket_soc_data rk3588_soc_data = {
+	.num_cores = 3,
 	.dma_bits = 40,
 };
 
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:50 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:50 +0000
Subject: [RFC PATCH v3 4/9] accel: rocket: Reset the NPU before detaching the IOMMU on timeout
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-5-midgy971@gmail.com>

On a job timeout the NPU AXI master can be left wedged with
outstanding transactions. rocket_reset() detached the IOMMU group
before resetting the hardware, so iommu_detach_group() ->
__iommu_group_set_core_domain() asked the rk_iommu to stall and wait
for the in-flight transactions to drain. They never did, the stall
request timed out (-ETIMEDOUT) and the IOMMU core WARNed:

  WARNING: drivers/iommu/iommu.c:157 __iommu_group_set_core_domain
    iommu_detach_group
    rocket_reset
    rocket_job_timedout

Assert the core reset first: it quiesces the AXI master so the
following IOMMU detach completes cleanly. Move the detach after
rocket_core_reset() and out of the job_lock (it does not touch
in_flight_job).

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_job.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index ac51bff39833f..e25234261536b 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -364,14 +364,20 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
 		if (core->in_flight_job)
 			pm_runtime_put_noidle(core->dev);
 
-		iommu_detach_group(NULL, core->iommu_group);
-
 		core->in_flight_job = NULL;
 	}
 
-	/* Proceed with reset now. */
+	/*
+	 * Reset the NPU hardware before detaching the IOMMU. A timed-out job
+	 * leaves the NPU AXI master wedged; detaching the IOMMU then issues a
+	 * stall request that never drains and times out (warning in the IOMMU
+	 * core). Asserting the core reset first quiesces the master so the
+	 * detach completes cleanly.
+	 */
 	rocket_core_reset(core);
 
+	iommu_detach_group(NULL, core->iommu_group);
+
 	/* NPU has been reset, we can clear the reset pending bit. */
 	atomic_set(&core->reset.pending, 0);
 
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:49 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:49 +0000
Subject: [RFC PATCH v3 3/9] accel: rocket: Add RK3568 SoC support
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-4-midgy971@gmail.com>

The RK3568 has a single core of the same NVDLA-derived NPU IP as the
RK3588, with a 32-bit AXI master.  Unlike the RK3588 it must be powered
on and de-idled through the PMU, and its PVTPLL clock started via SCMI,
before the NPU is reachable.  Add rk3568_soc_data with an noc_init
callback performing this bring-up.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c |  9 +++++
 drivers/accel/rocket/rocket_core.h |  3 ++
 drivers/accel/rocket/rocket_drv.c  | 53 ++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index 09c445af7de73..a8de876365873 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -88,6 +88,15 @@ int rocket_core_init(struct rocket_core *core)
 		return err;
 	}
 
+	if (core->soc_data->noc_init) {
+		err = core->soc_data->noc_init(core);
+		if (err) {
+			pm_runtime_put_sync(dev);
+			rocket_job_fini(core);
+			return err;
+		}
+	}
+
 	version = rocket_pc_readl(core, VERSION);
 	version += rocket_pc_readl(core, VERSION_NUM) & 0xffff;
 
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index d6421251670dc..66d138a8ed773 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -18,10 +18,13 @@ struct rocket_core;
  * struct rocket_soc_data - per-SoC configuration data
  * @num_cores: Number of NPU cores in this SoC.
  * @dma_bits: Physical address width reachable by the NPU's AXI master.
+ * @noc_init: Optional callback to power on and de-idle the NPU NOC bus.
+ *            Required on RK3568, where this is done through the PMU.
  */
 struct rocket_soc_data {
 	unsigned int num_cores;
 	unsigned int dma_bits;
+	int (*noc_init)(struct rocket_core *core);
 };
 
 #define rocket_pc_readl(core, reg) \
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index c18840e5aff76..5a72d0b5f4dff 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -9,9 +9,11 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/iommu.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 
 #include "rocket_device.h"
 #include "rocket_drv.h"
@@ -217,12 +219,63 @@ static void rocket_remove(struct platform_device *pdev)
 	}
 }
 
+/*
+ * On RK3568 the NPU NOC bus is gated and idle out of reset and must be
+ * powered on and de-idled through the PMU before the NPU is reachable.  PMU
+ * registers use a write-mask protocol: the upper 16 bits enable writes to the
+ * matching lower 16 bits.
+ *
+ * The NPU's high-speed clock is a PVTPLL managed by TF-A via SCMI and must be
+ * running before the NOC acknowledges the de-idle request.  Force a real SCMI
+ * rate change (an intermediate rate defeats the clock framework's
+ * unchanged-rate shortcut) now that the power domain is on and clocks enabled.
+ */
+#define ROCKET_RK3568_SCMI_CLK	2
+
+static int rk3568_noc_init(struct rocket_core *core)
+{
+	struct regmap *pmu;
+	unsigned int val;
+	int ret;
+
+	clk_set_rate(core->clks[ROCKET_RK3568_SCMI_CLK].clk, 600000000UL);
+	clk_set_rate(core->clks[ROCKET_RK3568_SCMI_CLK].clk, 1000000000UL);
+
+	pmu = syscon_regmap_lookup_by_phandle(core->dev->of_node, "rockchip,pmu");
+	if (IS_ERR(pmu))
+		return dev_err_probe(core->dev, PTR_ERR(pmu),
+				     "failed to get PMU regmap\n");
+
+	/* Power on the NPU power domain (PWR_GATE_SFTCON bit 1 = 0). */
+	regmap_write(pmu, 0xa0, BIT(1 + 16));
+
+	/* Disable NPU NOC auto-idle (NOC_AUTO_CON0 bit 2). */
+	regmap_write(pmu, 0x70, BIT(2 + 16));
+
+	/* Request NPU bus de-idle (BUS_IDLE_SFTCON0 bit 2 = 0). */
+	regmap_write(pmu, 0x50, BIT(2 + 16));
+
+	/* Wait for the bus to report active (BUS_IDLE_ST bit 2 = 0). */
+	ret = regmap_read_poll_timeout(pmu, 0x68, val, !(val & BIT(2)), 10, 1000);
+	if (ret)
+		dev_err(core->dev, "timed out waiting for NPU bus de-idle\n");
+
+	return ret;
+}
+
+static const struct rocket_soc_data rk3568_soc_data = {
+	.num_cores = 1,
+	.dma_bits = 32,
+	.noc_init = rk3568_noc_init,
+};
+
 static const struct rocket_soc_data rk3588_soc_data = {
 	.num_cores = 3,
 	.dma_bits = 40,
 };
 
 static const struct of_device_id dt_match[] = {
+	{ .compatible = "rockchip,rk3568-rknn-core", .data = &rk3568_soc_data },
 	{ .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data },
 	{}
 };
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:51 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:51 +0000
Subject: [RFC PATCH v3 5/9] accel: rocket: Keep the IOMMU domain attached across jobs
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-6-midgy971@gmail.com>

rocket attached the job's IOMMU domain in rocket_job_run() and
detached it again on every completion and reset. Each attach/detach
toggles the rk_iommu stall/force-reset/paging handshake, and on
RK3568 the NPU MMU is idle between jobs, so that handshake times out
and logs a burst of "stall/paging request timed out" errors for
every job.

Attach the per-context domain once and keep it: track the attached
domain in the core, swap it only when a job from a different context
runs, and detach it at core teardown. A reference on the attached
domain is held so it outlives the job that first attached it and is
released on swap/teardown.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c |  6 ++++++
 drivers/accel/rocket/rocket_core.h |  3 +++
 drivers/accel/rocket/rocket_job.c  | 27 +++++++++++++++++++++------
 3 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index a8de876365873..634f78dfe2887 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -13,6 +13,7 @@
 #include <linux/reset.h>
 
 #include "rocket_core.h"
+#include "rocket_drv.h"
 #include "rocket_job.h"
 
 int rocket_core_init(struct rocket_core *core)
@@ -112,6 +113,11 @@ void rocket_core_fini(struct rocket_core *core)
 {
 	pm_runtime_dont_use_autosuspend(core->dev);
 	pm_runtime_disable(core->dev);
+	if (core->attached_domain) {
+		iommu_detach_group(NULL, core->iommu_group);
+		rocket_iommu_domain_put(core->attached_domain);
+		core->attached_domain = NULL;
+	}
 	iommu_group_put(core->iommu_group);
 	core->iommu_group = NULL;
 	rocket_job_fini(core);
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index 66d138a8ed773..05a197a9c0113 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -42,6 +42,8 @@ struct rocket_soc_data {
 #define rocket_core_writel(core, reg, value) \
 	writel(value, (core)->core_iomem + (REG_CORE_##reg) - REG_CORE_S_STATUS)
 
+struct rocket_iommu_domain;
+
 struct rocket_core {
 	struct device *dev;
 	struct rocket_device *rdev;
@@ -56,6 +58,7 @@ struct rocket_core {
 	struct reset_control_bulk_data resets[2];
 
 	struct iommu_group *iommu_group;
+	struct rocket_iommu_domain *attached_domain;
 
 	struct mutex job_lock;
 	struct rocket_job *in_flight_job;
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index e25234261536b..b248371be8a1e 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -9,6 +9,7 @@
 #include <drm/rocket_accel.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
+#include <linux/kref.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
@@ -314,9 +315,26 @@ static struct dma_fence *rocket_job_run(struct drm_sched_job *sched_job)
 	if (ret < 0)
 		return fence;
 
-	ret = iommu_attach_group(job->domain->domain, core->iommu_group);
-	if (ret < 0)
-		return fence;
+	/*
+	 * Attach the job's IOMMU domain only when it differs from the one
+	 * already attached. Re-attaching per job toggles the rk_iommu
+	 * stall/reset handshake on an idle NPU MMU, which is slow and
+	 * noisy; keep the domain attached across jobs instead.
+	 */
+	if (core->attached_domain != job->domain) {
+		if (core->attached_domain) {
+			iommu_detach_group(NULL, core->iommu_group);
+			rocket_iommu_domain_put(core->attached_domain);
+			core->attached_domain = NULL;
+		}
+
+		ret = iommu_attach_group(job->domain->domain, core->iommu_group);
+		if (ret < 0)
+			return fence;
+
+		kref_get(&job->domain->kref);
+		core->attached_domain = job->domain;
+	}
 
 	scoped_guard(mutex, &core->job_lock) {
 		core->in_flight_job = job;
@@ -340,7 +358,6 @@ static void rocket_job_handle_irq(struct rocket_core *core)
 				return;
 			}
 
-			iommu_detach_group(NULL, iommu_group_get(core->dev));
 			dma_fence_signal(core->in_flight_job->done_fence);
 			pm_runtime_put_autosuspend(core->dev);
 			core->in_flight_job = NULL;
@@ -376,8 +393,6 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
 	 */
 	rocket_core_reset(core);
 
-	iommu_detach_group(NULL, core->iommu_group);
-
 	/* NPU has been reset, we can clear the reset pending bit. */
 	atomic_set(&core->reset.pending, 0);
 
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:54 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:54 +0000
Subject: [RFC PATCH v3 8/9] arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-9-midgy971@gmail.com>

The RK3568 has an NVDLA-derived NPU at fde40000 with its own IOMMU at
fde4b000. Add both nodes (disabled by default) and the NPU power-domain
child under the PMU power-controller, and point rockchip,pmu at the PMU
syscon that controls the NPU NoC bus-idle.

The power-domain deliberately carries no pm_qos: qos_npu sits behind the
NPU NoC, which is gated until the NPU is brought up, so a genpd power-off
QoS save would fault reading it.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index 64bdd8b7754b5..50ce5a5e4fc24 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -512,6 +512,13 @@ power-domain at RK3568_PD_GPU {
 				#power-domain-cells = <0>;
 			};
 
+			pd_npu: power-domain at RK3568_PD_NPU {
+				reg = <RK3568_PD_NPU>;
+				clocks = <&cru ACLK_NPU_PRE>,
+					 <&cru HCLK_NPU_PRE>;
+				#power-domain-cells = <0>;
+			};
+
 			/* These power domains are grouped by VD_LOGIC */
 			power-domain at RK3568_PD_VI {
 				reg = <RK3568_PD_VI>;
@@ -948,6 +955,37 @@ qos_rga_wr: qos at fe158300 {
 		reg = <0x0 0xfe158300 0x0 0x20>;
 	};
 
+	rknn_core_0: npu at fde40000 {
+		compatible = "rockchip,rk3568-rknn-core";
+		reg = <0x0 0xfde40000 0x0 0x1000>,
+		      <0x0 0xfde41000 0x0 0x1000>,
+		      <0x0 0xfde43000 0x0 0x1000>;
+		reg-names = "pc", "cna", "core";
+		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>,
+			 <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_PRE>;
+		clock-names = "aclk", "hclk", "npu", "pclk";
+		assigned-clocks = <&scmi_clk SCMI_CLK_NPU>;
+		assigned-clock-rates = <200000000>;
+		resets = <&cru SRST_A_NPU>, <&cru SRST_H_NPU>;
+		reset-names = "srst_a", "srst_h";
+		power-domains = <&power RK3568_PD_NPU>;
+		rockchip,pmu = <&pmu>;
+		iommus = <&rknn_mmu_0>;
+		status = "disabled";
+	};
+
+	rknn_mmu_0: iommu at fde4b000 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xfde4b000 0x0 0x40>;
+		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+		clock-names = "aclk", "iface";
+		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>;
+		power-domains = <&power RK3568_PD_NPU>;
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	qos_npu: qos at fe180000 {
 		compatible = "rockchip,rk3568-qos", "syscon";
 		reg = <0x0 0xfe180000 0x0 0x20>;
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:52 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:52 +0000
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the RK356x v1 IOMMU
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-7-midgy971@gmail.com>

On the RK356x v1 IOMMU, RK_MMU_AUTO_GATING resets to 0x3. Bit 1 enables
auto clock-gating of the page-table walker, so the walker's AXI master
loses its clock between transactions; a TLB-miss page walk then never
completes and the IOMMU is left stuck (PAGING_ENABLED, never IDLE).

Clear bit 1 (keeping bit 0, the slave-port gate) once paging is enabled
so the walker keeps its clock. This is required for the RK3568 NPU MMU.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/iommu/rockchip-iommu.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 4da80136933c4..e3d8b6e9ca12b 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -953,6 +953,18 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
 
 	ret = rk_iommu_enable_paging(iommu);
 
+	if (!ret) {
+		/*
+		 * RK356x v1 IOMMU: RK_MMU_AUTO_GATING bit 1 enables page-walker
+		 * auto clock-gating; the walker's AXI master then loses its clock
+		 * between transactions and a TLB-miss page walk never completes,
+		 * leaving the IOMMU stuck (PAGING_ENABLED, never IDLE).  Clear
+		 * bit 1 (keep bit 0, the slave-port gate) once paging is enabled.
+		 */
+		for (i = 0; i < iommu->num_mmu; i++)
+			rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, 0x2);
+	}
+
 out_disable_stall:
 	rk_iommu_disable_stall(iommu);
 out_disable_clocks:
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:53 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:53 +0000
Subject: [RFC PATCH v3 7/9] dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-8-midgy971@gmail.com>

The RK3568 carries a single core of the same NVDLA-derived NPU IP as the
RK3588.  Add its compatible.

On RK3568 the NPU NOC bus-idle and power gating are controlled through the
system PMU rather than a dedicated register block, so add a rockchip,pmu
phandle to that syscon.  The RK3568 NPU has no dedicated SRAM rail, so
sram-supply is required only on RK3588.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 .../npu/rockchip,rk3588-rknn-core.yaml         | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
index caca2a4903cd1..af9936b32e9fe 100644
--- a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
+++ b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
@@ -21,6 +21,7 @@ properties:
 
   compatible:
     enum:
+      - rockchip,rk3568-rknn-core
       - rockchip,rk3588-rknn-core
 
   reg:
@@ -50,6 +51,13 @@ properties:
 
   npu-supply: true
 
+  rockchip,pmu:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the PMU syscon.  On RK3568 the NPU's NOC bus-idle and
+      power gating are controlled through the PMU; this points to that
+      syscon so those registers can be reached.
+
   power-domains:
     maxItems: 1
 
@@ -75,7 +83,15 @@ required:
   - resets
   - reset-names
   - npu-supply
-  - sram-supply
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: rockchip,rk3588-rknn-core
+then:
+  required:
+    - sram-supply
 
 additionalProperties: false
 
-- 
2.39.5



From midgy971 at gmail.com  Thu Jun  4 06:52:55 2026
From: midgy971 at gmail.com (Midgy BALON)
Date: Thu,  4 Jun 2026 13:52:55 +0000
Subject: [RFC PATCH v3 9/9] arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <20260604135255.62682-10-midgy971@gmail.com>

Enable the NPU and its IOMMU on ROCK 3B.

vdd_npu is marked always-on so the rail is up before genpd de-idles the
NPU NoC at power-on: the PMU de-idle handshake needs the rail powered.
The PVTPLL compute clock is brought up later by the driver.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
index 69001e453732e..7ac780ed313d5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
@@ -330,8 +330,10 @@ regulator-state-mem {
 
 			vdd_npu: DCDC_REG4 {
 				regulator-name = "vdd_npu";
+				regulator-always-on;
+				regulator-boot-on;
 				regulator-initial-mode = <0x2>;
-				regulator-min-microvolt = <500000>;
+				regulator-min-microvolt = <825000>;
 				regulator-max-microvolt = <1350000>;
 				regulator-ramp-delay = <6001>;
 
@@ -787,3 +789,13 @@ vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
 		remote-endpoint = <&hdmi_in_vp0>;
 	};
 };
+
+&rknn_core_0 {
+	npu-supply = <&vdd_npu>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
+
-- 
2.39.5



From tomeu at tomeuvizoso.net  Thu Jun  4 07:20:10 2026
From: tomeu at tomeuvizoso.net (Tomeu Vizoso)
Date: Thu, 4 Jun 2026 16:20:10 +0200
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the
 RK356x v1 IOMMU
In-Reply-To: <20260604135255.62682-7-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <20260604135255.62682-7-midgy971@gmail.com>
Message-ID: <CAPsqS2RYjf4dMj=Maz1c2vViW83ZsrEW9eOez526eh=TsKvQww@mail.gmail.com>

On Thu, Jun 4, 2026 at 3:53?PM Midgy BALON <midgy971 at gmail.com> wrote:
>
> On the RK356x v1 IOMMU, RK_MMU_AUTO_GATING resets to 0x3. Bit 1 enables
> auto clock-gating of the page-table walker, so the walker's AXI master
> loses its clock between transactions; a TLB-miss page walk then never
> completes and the IOMMU is left stuck (PAGING_ENABLED, never IDLE).
>
> Clear bit 1 (keeping bit 0, the slave-port gate) once paging is enabled
> so the walker keeps its clock. This is required for the RK3568 NPU MMU.

Hi,

I'm not able to review this patch myself, but maybe it can be
submitted separately while we work on the NPU bits?

Regards,

Tomeu

> Signed-off-by: Midgy BALON <midgy971 at gmail.com>
> ---
>  drivers/iommu/rockchip-iommu.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 4da80136933c4..e3d8b6e9ca12b 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -953,6 +953,18 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
>
>         ret = rk_iommu_enable_paging(iommu);
>
> +       if (!ret) {
> +               /*
> +                * RK356x v1 IOMMU: RK_MMU_AUTO_GATING bit 1 enables page-walker
> +                * auto clock-gating; the walker's AXI master then loses its clock
> +                * between transactions and a TLB-miss page walk never completes,
> +                * leaving the IOMMU stuck (PAGING_ENABLED, never IDLE).  Clear
> +                * bit 1 (keep bit 0, the slave-port gate) once paging is enabled.
> +                */
> +               for (i = 0; i < iommu->num_mmu; i++)
> +                       rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, 0x2);
> +       }
> +
>  out_disable_stall:
>         rk_iommu_disable_stall(iommu);
>  out_disable_clocks:
> --
> 2.39.5
>


From macroalpha82 at gmail.com  Thu Jun  4 13:18:22 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:22 -0500
Subject: [PATCH V10 0/9] Add Invensense ICM42607
Message-ID: <20260604201832.60656-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.

This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.

Changes Since V1:
 - Instead of creating a new driver, merged with the existing inv_icm42600
   driver. This necessitated adding some code to the existing driver to
   permit using a different register layout for the same functionality.
 - Split changes up a bit more to decrease the size of the individual
   patches. Note that patch 0004 is still pretty hefty; if I need to split
   further I may need to create some temporary stub functions.
 - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
   per Jonathan's recommendations.

Changes Since V2:
 - Went back to using a new driver on advice from Invensense engineer.
 - Further split changes up into smaller chunks of functionality. Note
   still that the largest patch is approximately 900 lines, and that while
   the driver compiles cleanly at each commit it is not able to drive the
   hardware until the commit that adds the Interrupt (as it also adds the
   Makefile).
 - Change the error to a warning when the devicetree binding does not match
   the hardware ID.
 - Dropped the ack on the devicetree bindings, as I am creating a new file
   (for a new driver) instead of modifying the existing one.

Changes Since V3:
 - Numerous small fixes (too many to list here). Thank you to everyone who
   provided feedback.
 - Split power management additions into an additional commit to break
   things up further.
 - Consolidated devicetree documentation in existing
   invensense,icm42600.yaml file.
 - Removed most of the FIELD_PREP from header file to c files to make code
   easier to read.
 - Changed scale values to 2D arrays for Gyro and Accelerometer.
 - Removed IIO_CHAN_INFO_CALIBBIAS attribute.

Changes Since V4:
 - Additional numerous small fixes, thank you again for all the feedback.
 - Dropped power control API and instead run device in low noise mode.
 - Split devicetree bindings into two distinct changes.
 - Reordered adding of enums and structs to main header file so that they
   are only brought in when needed.
 - Stopped using enum for driver data and instead am using pointer to
   device specific driver data.

Changes Since V5:
 - Corrected use of "dev_warn_probe" to just "dev_warn".
 - Fixed some return scenarios which would unconditionally return 0
   when an error was present.
 - Corrected use of max() to min() for bounds checking. max() was
   incorrect.
 - Fixed using "st->conf.accel.odr" in the gyroscope function. It
   should have been "st->conf.gyro.odr" which it now is.
 - Additional small fixes suggested by "sashiko.dev".
 - Added a regmap cache. I used the datasheet to try and determine
   which registers might change without explicit writes.

Changes Since V6:
 - Corrected additional errors identified by sashiko.dev, mostly
   fixing potential deadlocks, missing calls for pm runtime, and
   potential overflow issues.

Changes Since V7:
 - Dropped Wake on Movement patches, since some of the functionality
   was only available for a device on which I cannot test.
 - Dropped support for SPI 3-Wire mode, since it complicated the
   bus setup (and I lack the hardware to test such features anyway).
 - Fixed a few additional bugs identified by sashiko.dev bot.

Changes Since V8:
 - Added back IRQ dropped accidentally when dropping wake on movement
   patches.
 - Dropped "Reviewed-By" tag on patch 2 because of substantial changes
   made to devicetree binding documentation.
 - Additional small fixes as suggested.

Changes Since V9:
 - Removed interrupts (and buffers) from the driver. I previously was
   unable to detect deadlocks because it turns out my IRQ was not even
   wired correctly in my device.
 - Updated devicetree binding commits to make interrupts optional for
   users of the icm42607 driver.

Chris Morgan (9):
  dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
  dt-bindings: iio: imu: icm42600: Add icm42607 binding
  iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
  iio: imu: inv_icm42607: Add I2C and SPI For icm42607
  iio: imu: inv_icm42607: Add PM support for icm42607
  iio: imu: inv_icm42607: Add Temp Support in icm42607
  iio: imu: inv_icm42607: Add Accelerometer for icm42607
  iio: imu: inv_icm42607: Add Gyroscope to icm42607
  arm64: dts: rockchip: Add icm42607p IMU for RG-DS

 .../bindings/iio/imu/invensense,icm42600.yaml |  20 +-
 .../dts/rockchip/rk3568-anbernic-rg-ds.dts    |   8 +-
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 +
 drivers/iio/imu/inv_icm42607/Makefile         |  13 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 421 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 465 +++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 539 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 437 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  95 +++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 107 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  |  82 +++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  |  33 ++
 14 files changed, 2250 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:23 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:23 -0500
Subject: [PATCH V10 1/9] dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add mount-matrix attribute to schema. This attribute has been supported
since the first revision of this driver, but was not documented.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/iio/imu/invensense,icm42600.yaml        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd3..9b2af104f186d 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -53,6 +53,8 @@ properties:
   drive-open-drain:
     type: boolean
 
+  mount-matrix: true
+
   vdd-supply:
     description: Regulator that provides power to the sensor
 
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:24 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:24 -0500
Subject: [PATCH V10 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the ICM42607 and ICM42607P inertial measurement unit.

This device is functionally very similar to the icm42600 series with a
very different register layout. The driver does not require an
interrupt for these specific chip revisions.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../bindings/iio/imu/invensense,icm42600.yaml  | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 9b2af104f186d..81b6e85decd52 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
       - invensense,icm42600
       - invensense,icm42602
       - invensense,icm42605
+      - invensense,icm42607
+      - invensense,icm42607p
       - invensense,icm42622
       - invensense,icm42631
       - invensense,icm42686
@@ -67,10 +69,24 @@ properties:
 required:
   - compatible
   - reg
-  - interrupts
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - invensense,icm42600
+              - invensense,icm42602
+              - invensense,icm42605
+              - invensense,icm42622
+              - invensense,icm42631
+              - invensense,icm42686
+              - invensense,icm42688
+    then:
+      required:
+        - interrupts
 
 unevaluatedProperties: false
 
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:25 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:25 -0500
Subject: [PATCH V10 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the core component of a new inv_icm42607 driver. This includes
a few setup functions and the full register definition in the
header file.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 200 +++++++++++
 2 files changed, 534 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 0000000000000..1fa9e4e11b2ee
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,334 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+enum inv_icm42607_sensor_mode {
+	INV_ICM42607_SENSOR_MODE_OFF,
+	INV_ICM42607_SENSOR_MODE_STANDBY,
+	INV_ICM42607_SENSOR_MODE_LOW_POWER,
+	INV_ICM42607_SENSOR_MODE_LOW_NOISE,
+	INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+	INV_ICM42607_GYRO_FS_2000DPS,
+	INV_ICM42607_GYRO_FS_1000DPS,
+	INV_ICM42607_GYRO_FS_500DPS,
+	INV_ICM42607_GYRO_FS_250DPS,
+	INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+	INV_ICM42607_ACCEL_FS_16G,
+	INV_ICM42607_ACCEL_FS_8G,
+	INV_ICM42607_ACCEL_FS_4G,
+	INV_ICM42607_ACCEL_FS_2G,
+	INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values */
+enum inv_icm42607_odr {
+	INV_ICM42607_ODR_1600HZ = 5,
+	INV_ICM42607_ODR_800HZ,
+	INV_ICM42607_ODR_400HZ,
+	INV_ICM42607_ODR_200HZ,
+	INV_ICM42607_ODR_100HZ,
+	INV_ICM42607_ODR_50HZ,
+	INV_ICM42607_ODR_25HZ,
+	INV_ICM42607_ODR_12_5HZ,
+	INV_ICM42607_ODR_6_25HZ_LP,
+	INV_ICM42607_ODR_3_125HZ_LP,
+	INV_ICM42607_ODR_1_5625HZ_LP,
+	INV_ICM42607_ODR_NB
+};
+
+enum inv_icm42607_filter_bw {
+	/* Low-Noise mode sensor data filter (bandwidth) */
+	INV_ICM42607_FILTER_BYPASS,
+	INV_ICM42607_FILTER_BW_180HZ,
+	INV_ICM42607_FILTER_BW_121HZ,
+	INV_ICM42607_FILTER_BW_73HZ,
+	INV_ICM42607_FILTER_BW_53HZ,
+	INV_ICM42607_FILTER_BW_34HZ,
+	INV_ICM42607_FILTER_BW_25HZ,
+	INV_ICM42607_FILTER_BW_16HZ,
+	INV_ICM42607_FILTER_BW_NB
+};
+
+struct inv_icm42607_sensor_conf {
+	int mode;
+	int fs;
+	int odr;
+	int filter;
+};
+
+struct inv_icm42607_conf {
+	struct inv_icm42607_sensor_conf gyro;
+	struct inv_icm42607_sensor_conf accel;
+	bool temp_en;
+};
+
+struct inv_icm42607_hw {
+	uint8_t whoami;
+	const char *name;
+	const struct inv_icm42607_conf *conf;
+};
+
+/**
+ *  struct inv_icm42607_state - driver state variables
+ *  @lock:		lock for serializing multiple registers access.
+ *  @hw:		Hardware specific data.
+ *  @map:		regmap pointer.
+ *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @orientation:	sensor chip orientation relative to main hardware.
+ *  @conf:		chip sensors configurations.
+ */
+struct inv_icm42607_state {
+	struct mutex lock;
+	const struct inv_icm42607_hw *hw;
+	struct regmap *map;
+	struct regulator *vddio_supply;
+	struct iio_mount_matrix orientation;
+	struct inv_icm42607_conf conf;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY			0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG			0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE		BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE		BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET		0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET	BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH	BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1			0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2			0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3			0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG			0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED		BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL		BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH	BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW		0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED		BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL		BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH	BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW		0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1			0x09
+#define INV_ICM42607_REG_TEMP_DATA0			0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1			0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0			0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1			0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0			0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1			0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0			0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1			0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0			0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1			0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0			0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1			0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0			0x16
+#define INV_ICM42607_DATA_INVALID			-32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH			0x17
+#define INV_ICM42607_REG_TMST_FSYNCL			0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0			0x31
+#define INV_ICM42607_REG_APEX_DATA1			0x32
+#define INV_ICM42607_REG_APEX_DATA2			0x33
+#define INV_ICM42607_REG_APEX_DATA3			0x34
+#define INV_ICM42607_REG_APEX_DATA4			0x1D
+#define INV_ICM42607_REG_APEX_DATA5			0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0			0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL		BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE			BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK		GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0			0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0			0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0			0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK		GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1			0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1			0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK		GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0			0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN	BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN		BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN	BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1			0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE		BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE		BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE		BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE		BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG			0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK		GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE		BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE			BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN			BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1			0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE			BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2			0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3			0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm)		\
+		cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX			(2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE		8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE		16
+
+#define INV_ICM42607_REG_INT_SOURCE0			0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1			0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3			0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4			0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN		BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN		BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0			0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1			0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0			0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42607_REG_INTF_CONFIG1			0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN		BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN		BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK		GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT		0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL		1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF		2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY		0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY		BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS			0x3A
+#define INV_ICM42607_INT_STATUS_ST			BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC			BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY			BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE		BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS		BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL		BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY			BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2			0x3B
+#define INV_ICM42607_INT_STATUS2_SMD			BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3			0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET		BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF		BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET		BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET			BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH			0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL			0x3E
+#define INV_ICM42607_REG_FIFO_DATA			0x3F
+
+#define INV_ICM42607_REG_ACCEL_WOM_X_THR		0x4b
+#define INV_ICM42607_REG_ACCEL_WOM_Y_THR		0x4c
+#define INV_ICM42607_REG_ACCEL_WOM_Z_THR		0x4d
+
+#define INV_ICM42607_REG_WHOAMI				0x75
+#define INV_ICM42607P_WHOAMI				0x60
+#define INV_ICM42607_WHOAMI				0x67
+
+/* Timings as listed in section 3 of datasheet */
+#define INV_ICM42607_POWER_UP_TIME_US			100000
+#define INV_ICM42607_RESET_TIME_MS			1
+#define INV_ICM42607_ACCEL_STARTUP_TIME_MS		10
+#define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
+#define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 0000000000000..74d4cb03f7b86
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
+				 const struct inv_icm42607_conf *conf)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+	/*
+	 * No temperature enable reg in datasheet, but BSP driver selected RC
+	 * oscillator clock in LP mode when temperature was disabled.
+	 */
+	if (!conf->temp_en)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+	val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+	val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+				 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+				 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	st->conf = *conf;
+
+	return 0;
+}
+
+/**
+ *  inv_icm42607_setup() - check and setup chip
+ *  @st:	driver internal state
+ *  @bus_setup:	callback for setting up bus specific registers
+ *
+ *  Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+			      inv_icm42607_bus_setup bus_setup)
+{
+	const struct device *dev = regmap_get_device(st->map);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+	if (ret)
+		return ret;
+
+	if (val != st->hw->whoami)
+		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+			 val, st->hw->whoami, st->hw->name);
+
+	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_RESET_TIME_MS * 1000);
+
+	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+				       INV_ICM42607_RESET_TIME_MS * 100,
+				       INV_ICM42607_RESET_TIME_MS * 10000);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "reset error, reset done bit not set\n");
+
+	/* Sync the regcache again after a reset. */
+	regcache_mark_dirty(st->map);
+	ret = regcache_sync(st->map);
+	if (ret)
+		return ret;
+
+	ret = bus_setup(st);
+	if (ret)
+		return ret;
+
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+	int ret;
+
+	ret = regulator_enable(st->vddio_supply);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+	return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+	struct inv_icm42607_state *st = _data;
+
+	regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup bus_setup)
+{
+	struct device *dev = regmap_get_device(regmap);
+	struct inv_icm42607_state *st;
+	int ret;
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
+	st->hw = hw;
+	st->map = regmap;
+
+	ret = iio_read_mount_matrix(dev, &st->orientation);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to retrieve mounting matrix %d\n", ret);
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get vdd regulator\n");
+
+	st->vddio_supply = devm_regulator_get(dev, "vddio");
+	if (IS_ERR(st->vddio_supply))
+		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+				     "Failed to get vddio regulator\n");
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+	if (ret)
+		return ret;
+
+	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+	ret = inv_icm42607_setup(st, bus_setup);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:26 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:26 -0500
Subject: [PATCH V10 4/9] iio: imu: inv_icm42607: Add I2C and SPI For icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add I2C and SPI driver support for InvenSense ICM-42607 devices.
Add necessary Kconfig and Makefile to allow building of (incomplete)
driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 +++++
 drivers/iio/imu/inv_icm42607/Makefile         |  10 ++
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  16 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  57 ++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  94 ++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 106 ++++++++++++++++++
 8 files changed, 315 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c

diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb69..8bab4616be208 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
 source "drivers/iio/imu/inv_icm45600/Kconfig"
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c98..3268dc2371aed 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
 obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
 
 obj-y += inv_icm42600/
+obj-y += inv_icm42607/
 obj-y += inv_icm45600/
 obj-y += inv_mpu6050/
 
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 0000000000000..7ba64e6e8d806
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+	tristate
+	select IIO_BUFFER
+	select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+	tristate "InvenSense ICM-42607X I2C driver"
+	depends on I2C
+	select INV_ICM42607
+	select REGMAP_I2C
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over I2C.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+	tristate "InvenSense ICM-42607X SPI driver"
+	depends on SPI_MASTER
+	select INV_ICM42607
+	select REGMAP_SPI
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over SPI.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 0000000000000..be109102e2035
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 1fa9e4e11b2ee..7928f81300ed8 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -13,6 +13,22 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+	INV_ICM42607_SLEW_RATE_20_60NS,
+	INV_ICM42607_SLEW_RATE_12_36NS,
+	INV_ICM42607_SLEW_RATE_6_19NS,
+	INV_ICM42607_SLEW_RATE_4_14NS,
+	INV_ICM42607_SLEW_RATE_2_8NS,
+	INV_ICM42607_SLEW_RATE_2NS,
+	INV_ICM42607_SLEW_RATE_NB
+};
+
 enum inv_icm42607_sensor_mode {
 	INV_ICM42607_SENSOR_MODE_OFF,
 	INV_ICM42607_SENSOR_MODE_STANDBY,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 74d4cb03f7b86..4448d63e95fd7 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -15,6 +15,63 @@
 
 #include "inv_icm42607.h"
 
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY:
+	case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+	case INV_ICM42607_REG_APEX_CONFIG0:
+	case INV_ICM42607_REG_FIFO_CONFIG2 ... INV_ICM42607_REG_FIFO_CONFIG3:
+	case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+	case INV_ICM42607_REG_INT_STATUS_DRDY:
+	case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = INV_ICM42607_REG_WHOAMI,
+	.cache_type = REGCACHE_MAPLE,
+	.volatile_reg = inv_icm42607_is_volatile_reg,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+	.gyro = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_GYRO_FS_1000DPS,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.accel = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_ACCEL_FS_4G,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.temp_en = false,
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+	.whoami = INV_ICM42607_WHOAMI,
+	.name = "icm42607",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+	.whoami = INV_ICM42607P_WHOAMI,
+	.name = "icm42607p",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 0000000000000..22ac51108cd3b
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+			 INV_ICM42607_SLEW_RATE_12_36NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+				 INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = i2c_get_match_data(client);
+	if (!hw)
+		return dev_err_probe(&client->dev, -ENODEV,
+				     "Failed to get i2c data\n");
+
+	regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&client->dev, PTR_ERR(regmap),
+				     "Failed to register i2c regmap %ld\n",
+				     PTR_ERR(regmap));
+
+	return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	}, {
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-i2c",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_id,
+	.probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 0000000000000..421d3ec1cded3
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	/* Only support 4-wire mode for now. */
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+				      INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+	if (ret)
+		return ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+			 INV_ICM42607_SLEW_RATE_2NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+				 INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = spi_get_device_match_data(spi);
+	if (!hw)
+		return dev_err_probe(&spi->dev, -ENODEV,
+				     "Failed to get SPI data\n");
+
+	if (spi->mode & SPI_3WIRE)
+		return dev_err_probe(&spi->dev, -ENODEV,
+				     "SPI 3-wire mode not supported\n");
+
+	regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+				     "Failed to register spi regmap %ld\n",
+				     PTR_ERR(regmap));
+
+	return inv_icm42607_core_probe(regmap, hw,
+				       inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	},
+	{
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-spi",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_spi_id_table,
+	.probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:27 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:27 -0500
Subject: [PATCH V10 5/9] iio: imu: inv_icm42607: Add PM support for icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add power management support for the ICM42607 device driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  18 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 123 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |   1 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   |   1 +
 4 files changed, 143 insertions(+)

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 7928f81300ed8..72327381b6dbc 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -10,6 +10,7 @@
 #include <linux/bitops.h>
 #include <linux/iio/iio.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
@@ -103,22 +104,32 @@ struct inv_icm42607_hw {
 	const struct inv_icm42607_conf *conf;
 };
 
+struct inv_icm42607_suspended {
+	enum inv_icm42607_sensor_mode gyro;
+	enum inv_icm42607_sensor_mode accel;
+	bool temp;
+};
+
 /**
  *  struct inv_icm42607_state - driver state variables
  *  @lock:		lock for serializing multiple registers access.
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
  *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @vddio_en:		I/O voltage status for runtime PM.
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
+ *  @suspended:		suspended sensors configuration.
  */
 struct inv_icm42607_state {
 	struct mutex lock;
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
 	struct regulator *vddio_supply;
+	bool vddio_en;
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
+	struct inv_icm42607_suspended suspended;
 };
 
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -337,11 +348,18 @@ struct inv_icm42607_state {
 #define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
 #define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
 
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS			2000
+
 typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
 
 extern const struct regmap_config inv_icm42607_regmap_config;
 extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 4448d63e95fd7..39620da92bd43 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -9,6 +9,7 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
@@ -72,6 +73,51 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+				      enum inv_icm42607_sensor_mode gyro,
+				      enum inv_icm42607_sensor_mode accel,
+				      bool temp, unsigned int *sleep_ms)
+{
+	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
+	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
+	bool oldtemp = st->conf.temp_en;
+	unsigned int sleepval;
+	unsigned int val;
+	int ret;
+
+	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+		return 0;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+	if (!temp)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	st->conf.gyro.mode = gyro;
+	st->conf.accel.mode = accel;
+	st->conf.temp_en = temp;
+
+	sleepval = 0;
+	if (temp && !oldtemp)
+		sleepval = max(sleepval, INV_ICM42607_TEMP_STARTUP_TIME_MS);
+
+	if (accel != oldaccel)
+		sleepval = max(sleepval, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
+
+	if (gyro != oldgyro)
+		sleepval = max(sleepval, INV_ICM42607_GYRO_STARTUP_TIME_MS);
+
+	if (sleep_ms)
+		*sleep_ms = sleepval;
+	else if (sleepval)
+		fsleep(sleepval * 1000);
+
+	return 0;
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
@@ -184,12 +230,17 @@ static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
 {
 	int ret;
 
+	if (st->vddio_en)
+		return 0;
+
 	ret = regulator_enable(st->vddio_supply);
 	if (ret)
 		return ret;
 
 	fsleep(INV_ICM42607_POWER_UP_TIME_US);
 
+	st->vddio_en = true;
+
 	return 0;
 }
 
@@ -197,7 +248,12 @@ static void inv_icm42607_disable_vddio_reg(void *_data)
 {
 	struct inv_icm42607_state *st = _data;
 
+	if (!st->vddio_en)
+		return;
+
 	regulator_disable(st->vddio_supply);
+
+	st->vddio_en = false;
 }
 
 int inv_icm42607_core_probe(struct regmap *regmap,
@@ -247,10 +303,77 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (ret)
 		return ret;
 
+	ret = devm_pm_runtime_set_active_enabled(dev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(dev);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
 
+static int inv_icm42607_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		return ret;
+
+	inv_icm42607_disable_vddio_reg(st);
+
+	return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* save sensors state */
+	st->suspended.gyro = st->conf.gyro.mode;
+	st->suspended.accel = st->conf.accel.mode;
+	st->suspended.temp = st->conf.temp_en;
+
+	return inv_icm42607_set_pwr_mgmt0(st, INV_ICM42607_SENSOR_MODE_OFF,
+					  INV_ICM42607_SENSOR_MODE_OFF, false,
+					  NULL);
+}
+
+static int inv_icm42607_runtime_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* restore sensors state */
+	return inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
+					  st->suspended.accel,
+					  st->suspended.temp, NULL);
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+	SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
+		       inv_icm42607_runtime_resume, NULL)
+};
+
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
index 22ac51108cd3b..cd08bb9514f2d 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -82,6 +82,7 @@ static struct i2c_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-i2c",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_id,
 	.probe = inv_icm42607_probe,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
index 421d3ec1cded3..8a82e1610531b 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -94,6 +94,7 @@ static struct spi_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-spi",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_spi_id_table,
 	.probe = inv_icm42607_probe,
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:28 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:28 -0500
Subject: [PATCH V10 6/9] iio: imu: inv_icm42607: Add Temp Support in icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add functions for reading temperature sensor data.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |  1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  5 ++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 18 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  | 82 +++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  | 33 ++++++++
 5 files changed, 139 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index be109102e2035..c04953ed42ce9 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 72327381b6dbc..13a5b06e80142 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -120,6 +120,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @buffer:		data transfer buffer aligned for DMA.
  */
 struct inv_icm42607_state {
 	struct mutex lock;
@@ -130,6 +131,7 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
 
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -361,6 +363,9 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 39620da92bd43..a438e6fbe508b 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -118,6 +118,24 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+			 INV_ICM42607_FILTER_BW_34HZ);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+				 INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+					  st->conf.accel.mode, enable,
+					  sleep_ms);
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
new file mode 100644
index 0000000000000..55260082a19ed
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp)
+{
+	struct device *dev = regmap_get_device(st->map);
+	__be16 *raw;
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_temp_conf(st, true, NULL);
+	if (ret)
+		return ret;
+
+	raw = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1,
+			       raw, sizeof(*raw));
+	if (ret)
+		return ret;
+
+	*temp = be16_to_cpup(raw);
+	if (*temp == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 temp;
+	int ret;
+
+	if (chan->type != IIO_TEMP)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_temp_read(st, &temp);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = temp;
+		return IIO_VAL_INT;
+	/*
+	 * T?C = (temp / 128) + 25
+	 * Tm?C = 1000 * ((temp * 100 / 12800) + 25)
+	 * scale: 100000 / 12800 ~= 7.8125
+	 * offset: 3200
+	 */
+	case IIO_CHAN_INFO_SCALE:
+		*val = 7;
+		*val2 = 812500000;
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 3200;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
new file mode 100644
index 0000000000000..e03924e308662
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_TEMP_H_
+#define INV_ICM42607_TEMP_H_
+
+#include <linux/bitops.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+#define INV_ICM42607_TEMP_CHAN(_index)				\
+{								\
+	.type = IIO_TEMP,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW) |			\
+		BIT(IIO_CHAN_INFO_OFFSET) |			\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+	},							\
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long mask);
+
+#endif
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:29 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:29 -0500
Subject: [PATCH V10 7/9] iio: imu: inv_icm42607: Add Accelerometer for icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-8-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add icm42607 accelerometer sensor for icm42607.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  40 ++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 465 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  93 ++++
 4 files changed, 599 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index c04953ed42ce9..d74b23b1e1bec 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 13a5b06e80142..fb4bcc2b7da54 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -14,6 +14,8 @@
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
 /*
  * Serial bus slew rates. Rates are expressed as range between the two
  * values with the midpoint as the typical rate. For the final value of
@@ -85,12 +87,24 @@ enum inv_icm42607_filter_bw {
 	INV_ICM42607_FILTER_BW_NB
 };
 
+enum inv_icm42607_filter_avg {
+	/* Low-Power mode sensor data filter (averaging) */
+	INV_ICM42607_FILTER_AVG_2X = 0,
+	INV_ICM42607_FILTER_AVG_4X,
+	INV_ICM42607_FILTER_AVG_8X,
+	INV_ICM42607_FILTER_AVG_16X,
+	INV_ICM42607_FILTER_AVG_32X,
+	INV_ICM42607_FILTER_AVG_64X,
+	/* values 7 and 8 also correspond to 64x. */
+};
+
 struct inv_icm42607_sensor_conf {
 	int mode;
 	int fs;
 	int odr;
 	int filter;
 };
+#define INV_ICM42607_SENSOR_CONF_INIT		{ -1, -1, -1, -1 }
 
 struct inv_icm42607_conf {
 	struct inv_icm42607_sensor_conf gyro;
@@ -120,6 +134,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @indio_accel:	accelerometer IIO device.
  *  @buffer:		data transfer buffer aligned for DMA.
  */
 struct inv_icm42607_state {
@@ -131,9 +146,22 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	struct iio_dev *indio_accel;
 	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
 
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @power_mode:		sensor requested power mode (for common frequencies)
+ * @filter:		sensor filter.
+ * @ts:			timestamp module states.
+ */
+struct inv_icm42607_sensor_state {
+	enum inv_icm42607_sensor_mode power_mode;
+	int filter;
+	struct inv_sensors_timestamp ts;
+};
+
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
 
 /* Register Map for User Bank 0 */
@@ -363,6 +391,16 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr);
+
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan);
+
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -370,4 +408,6 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
+
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
new file mode 100644
index 0000000000000..6c1f88688c3f4
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+
+#include <linux/iio/common/inv_sensors_timestamp.h>
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)		\
+{									\
+	.type = IIO_ACCEL,						\
+	.modified = 1,							\
+	.channel2 = _modifier,						\
+	.info_mask_separate =						\
+		BIT(IIO_CHAN_INFO_RAW),					\
+	.info_mask_shared_by_type =					\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_type_available =				\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_all =					\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.info_mask_shared_by_all_available =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.scan_index = _index,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 16,						\
+		.storagebits = 16,					\
+		.endianness = IIO_BE,					\
+	},								\
+	.ext_info = _ext_info,						\
+}
+
+#define INV_ICM42607_ACCEL_EVENT_CHAN(_modifier, _events, _events_nb)	\
+	{								\
+		.type = IIO_ACCEL,					\
+		.modified = 1,						\
+		.channel2 = _modifier,					\
+		.event_spec = _events,					\
+		.num_event_specs = _events_nb,				\
+		.scan_index = -1,					\
+	}
+
+enum inv_icm42607_accel_scan {
+	INV_ICM42607_ACCEL_SCAN_X,
+	INV_ICM42607_ACCEL_SCAN_Y,
+	INV_ICM42607_ACCEL_SCAN_Z,
+	INV_ICM42607_ACCEL_SCAN_TEMP,
+	INV_ICM42607_ACCEL_SCAN_TIMESTAMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP),
+	IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42607_ACCEL_SCAN_TIMESTAMP),
+};
+
+#define INV_ICM42607_SCAN_MASK_ACCEL_3AXIS				\
+	(BIT(INV_ICM42607_ACCEL_SCAN_X) |				\
+	 BIT(INV_ICM42607_ACCEL_SCAN_Y) |				\
+	 BIT(INV_ICM42607_ACCEL_SCAN_Z))
+
+#define INV_ICM42607_SCAN_MASK_TEMP	BIT(INV_ICM42607_ACCEL_SCAN_TEMP)
+
+static const unsigned long inv_icm42607_accel_scan_masks[] = {
+	INV_ICM42607_SCAN_MASK_ACCEL_3AXIS,
+	INV_ICM42607_SCAN_MASK_ACCEL_3AXIS | INV_ICM42607_SCAN_MASK_TEMP,
+	0
+};
+
+/* enable accelerometer sensor */
+static int inv_icm42607_accel_update_scan_mode(struct iio_dev *indio_dev,
+					       const unsigned long *scan_mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int sleep_temp = 0;
+	unsigned int sleep_accel = 0;
+	int ret;
+
+	mutex_lock(&st->lock);
+
+	if (*scan_mask & INV_ICM42607_SCAN_MASK_TEMP) {
+		/* enable temp sensor */
+		ret = inv_icm42607_set_temp_conf(st, true, &sleep_temp);
+		if (ret)
+			goto out_unlock;
+	}
+
+	if (*scan_mask & INV_ICM42607_SCAN_MASK_ACCEL_3AXIS) {
+		/* enable accel sensor */
+		conf.mode = accel_st->power_mode;
+		conf.filter = accel_st->filter;
+		ret = inv_icm42607_set_accel_conf(st, &conf, &sleep_accel);
+		if (ret)
+			goto out_unlock;
+	}
+
+out_unlock:
+	mutex_unlock(&st->lock);
+	/*
+	 * Choose the highest enable-delay time of the two sensors being
+	 * enabled, and sleep for that amount of time.
+	 */
+	msleep(max(sleep_accel, sleep_temp));
+
+	return ret;
+}
+
+static int inv_icm42607_accel_read_sensor(struct iio_dev *indio_dev,
+					  struct iio_chan_spec const *chan,
+					  s16 *val)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable accel sensor */
+	conf.mode = accel_st->power_mode;
+	conf.filter = accel_st->filter;
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read accel register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_accel_scale_nano[][2] = {
+	[INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 },
+	[INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 },
+	[INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 },
+	[INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 }
+};
+
+static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev,
+					 int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	idx = st->conf.accel.fs;
+
+	*val = inv_icm42607_accel_scale_nano[idx][0];
+	*val2 = inv_icm42607_accel_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev,
+					  int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_accel_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_accel_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_accel_conf(st, &conf, NULL);
+}
+
+/* IIO format int + micro , values 0-5 reserved. */
+static const int inv_icm42607_accel_odr[][2] = {
+	[INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 },
+	[INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 },
+	[INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 },
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 }
+};
+
+static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
+				       int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	odr = st->conf.accel.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_accel_odr[i][0];
+	*val2 = inv_icm42607_accel_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
+					int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct inv_sensors_timestamp *ts = &accel_st->ts;
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
+		if (val == inv_icm42607_accel_odr[idx][0] &&
+		    val2 == inv_icm42607_accel_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_sensors_timestamp_update_odr(ts, inv_icm42607_odr_to_period(conf.odr),
+					       iio_buffer_enabled(indio_dev));
+	if (ret)
+		return ret;
+
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ACCEL:
+		break;
+	case IIO_TEMP:
+		return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_accel_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_read_avail(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 const int **vals,
+					 int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_accel_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_accel_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_accel_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
+		iio_device_release_direct(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
+						struct iio_chan_spec const *chan,
+						long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_accel_info = {
+	.read_raw = inv_icm42607_accel_read_raw,
+	.read_avail = inv_icm42607_accel_read_avail,
+	.write_raw = inv_icm42607_accel_write_raw,
+	.write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt,
+	.update_scan_mode = inv_icm42607_accel_update_scan_mode,
+};
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *accel_st;
+	struct inv_sensors_timestamp_chip ts_chip;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	accel_st = iio_priv(indio_dev);
+
+	accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+	accel_st->filter = INV_ICM42607_FILTER_AVG_16X;
+
+	/*
+	 * clock period is 32kHz (31250ns)
+	 * jitter is +/- 2% (20 per mille)
+	 */
+	ts_chip.clock_period = 31250;
+	ts_chip.jitter = 20;
+	ts_chip.init_period = inv_icm42607_odr_to_period(st->conf.accel.odr);
+	inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_accel_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_accel_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+	indio_dev->available_scan_masks = inv_icm42607_accel_scan_masks;
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index a438e6fbe508b..5f311cba0572c 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -73,6 +73,47 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr)
+{
+	static const u32 odr_periods[INV_ICM42607_ODR_NB] = {
+		/* 1600Hz */
+		[INV_ICM42607_ODR_1600HZ] = 625000,
+		/* 800Hz */
+		1250000,
+		/* 400Hz */
+		2500000,
+		/* 200Hz */
+		5000000,
+		/* 100 Hz */
+		10000000,
+		/* 50Hz */
+		20000000,
+		/* 25Hz */
+		40000000,
+		/* 12.5Hz */
+		80000000,
+		/* 6.25Hz */
+		160000000,
+		/* 3.125Hz */
+		320000000,
+		/* 1.5625Hz */
+		640000000,
+	};
+
+	odr = clamp(odr, INV_ICM42607_ODR_1600HZ, INV_ICM42607_ODR_1_5625HZ_LP);
+
+	return odr_periods[odr];
+}
+
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan)
+{
+	const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+	return &st->orientation;
+}
+
 static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 				      enum inv_icm42607_sensor_mode gyro,
 				      enum inv_icm42607_sensor_mode accel,
@@ -118,6 +159,53 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.accel;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		if (conf->mode == INV_ICM42607_SENSOR_MODE_LOW_POWER) {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
+		} else {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
+					 conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+		}
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -328,6 +416,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
 	pm_runtime_use_autosuspend(dev);
 
+	/* Initialize IIO device for Accel */
+	st->indio_accel = inv_icm42607_accel_init(st);
+	if (IS_ERR(st->indio_accel))
+		return PTR_ERR(st->indio_accel);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:30 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:30 -0500
Subject: [PATCH V10 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-9-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add gyroscope functions to the icm42607 driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |   8 +
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  48 ++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 437 ++++++++++++++++++
 4 files changed, 494 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index d74b23b1e1bec..7b907e0196017 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_gyro.o
 inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index fb4bcc2b7da54..b2f081ec8776c 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -134,6 +134,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @indio_gyro:	gyroscope IIO device.
  *  @indio_accel:	accelerometer IIO device.
  *  @buffer:		data transfer buffer aligned for DMA.
  */
@@ -146,6 +147,7 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	struct iio_dev *indio_gyro;
 	struct iio_dev *indio_accel;
 	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
@@ -401,6 +403,10 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 				struct inv_icm42607_sensor_conf *conf,
 				unsigned int *sleep_ms);
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -408,6 +414,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st);
+
 struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
 
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 5f311cba0572c..fd06ef5ab1e6f 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -206,6 +206,49 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 					  st->conf.temp_en, sleep_ms);
 }
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.gyro;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK,
+				 conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK,
+				  conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
+				 conf->filter);
+		ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+					 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -421,6 +464,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (IS_ERR(st->indio_accel))
 		return PTR_ERR(st->indio_accel);
 
+	/* Initialize IIO device for Gyro */
+	st->indio_gyro = inv_icm42607_gyro_init(st);
+	if (IS_ERR(st->indio_gyro))
+		return PTR_ERR(st->indio_gyro);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
new file mode 100644
index 0000000000000..0f2703342122b
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/math64.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/common/inv_sensors_timestamp.h>
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info)	\
+{								\
+	.type = IIO_ANGL_VEL,					\
+	.modified = 1,						\
+	.channel2 = _modifier,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW),				\
+	.info_mask_shared_by_type =				\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_BE,				\
+	},							\
+	.ext_info = _ext_info,					\
+}
+
+enum inv_icm42607_gyro_scan {
+	INV_ICM42607_GYRO_SCAN_X,
+	INV_ICM42607_GYRO_SCAN_Y,
+	INV_ICM42607_GYRO_SCAN_Z,
+	INV_ICM42607_GYRO_SCAN_TEMP,
+	INV_ICM42607_GYRO_SCAN_TIMESTAMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP),
+	IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42607_GYRO_SCAN_TIMESTAMP),
+};
+
+#define INV_ICM42607_SCAN_MASK_GYRO_3AXIS				\
+	(BIT(INV_ICM42607_GYRO_SCAN_X) |				\
+	 BIT(INV_ICM42607_GYRO_SCAN_Y) |				\
+	 BIT(INV_ICM42607_GYRO_SCAN_Z))
+
+#define INV_ICM42607_SCAN_MASK_TEMP	BIT(INV_ICM42607_GYRO_SCAN_TEMP)
+
+static const unsigned long inv_icm42607_gyro_scan_masks[] = {
+	INV_ICM42607_SCAN_MASK_GYRO_3AXIS,
+	INV_ICM42607_SCAN_MASK_GYRO_3AXIS | INV_ICM42607_SCAN_MASK_TEMP,
+	0
+};
+
+/* enable gyroscope sensor */
+static int inv_icm42607_gyro_update_scan_mode(struct iio_dev *indio_dev,
+					      const unsigned long *scan_mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int sleep_gyro = 0;
+	unsigned int sleep_temp = 0;
+	int ret;
+
+	mutex_lock(&st->lock);
+
+	if (*scan_mask & INV_ICM42607_SCAN_MASK_TEMP) {
+		/* enable temp sensor */
+		ret = inv_icm42607_set_temp_conf(st, true, &sleep_temp);
+		if (ret)
+			goto out_unlock;
+	}
+
+	if (*scan_mask & INV_ICM42607_SCAN_MASK_GYRO_3AXIS) {
+		/* enable gyro sensor */
+		conf.mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+		ret = inv_icm42607_set_gyro_conf(st, &conf, &sleep_gyro);
+		if (ret)
+			goto out_unlock;
+	}
+
+out_unlock:
+	mutex_unlock(&st->lock);
+	/* sleep maximum required time */
+	msleep(max(sleep_gyro, sleep_temp));
+	return ret;
+}
+
+static int inv_icm42607_gyro_read_sensor(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 s16 *val)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_GYRO_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable gyro sensor */
+	conf.mode = gyro_st->power_mode;
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read gyro register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_gyro_scale_nano[][2] = {
+	[INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 },
+	[INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 },
+	[INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 },
+	[INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 },
+};
+
+static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev,
+					int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	idx = st->conf.gyro.fs;
+
+	*val = inv_icm42607_gyro_scale_nano[idx][0];
+	*val2 = inv_icm42607_gyro_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev,
+					 int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano);
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_gyro_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_gyro_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
+}
+
+static const int inv_icm42607_gyro_odr[][2] = {
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+};
+
+static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st,
+				      int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	odr = st->conf.gyro.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_gyro_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_gyro_odr[i][0];
+	*val2 = inv_icm42607_gyro_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
+				       int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
+	struct inv_sensors_timestamp *ts = &gyro_st->ts;
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); ++idx) {
+		if (val == inv_icm42607_gyro_odr[idx][0] &&
+		    val2 == inv_icm42607_gyro_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_sensors_timestamp_update_odr(ts, inv_icm42607_odr_to_period(conf.odr),
+					       iio_buffer_enabled(indio_dev));
+	if (ret)
+		return ret;
+
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ANGL_VEL:
+		break;
+	case IIO_TEMP:
+		return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_gyro_read_sensor(indio_dev, chan, &data);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_gyro_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_read_avail(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					const int **vals,
+					int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_gyro_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_gyro_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_gyro_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2);
+		iio_device_release_direct(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
+					       struct iio_chan_spec const *chan,
+					       long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_gyro_info = {
+	.read_raw = inv_icm42607_gyro_read_raw,
+	.read_avail = inv_icm42607_gyro_read_avail,
+	.write_raw = inv_icm42607_gyro_write_raw,
+	.write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt,
+	.update_scan_mode = inv_icm42607_gyro_update_scan_mode,
+};
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *gyro_st;
+	struct inv_sensors_timestamp_chip ts_chip;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	gyro_st = iio_priv(indio_dev);
+
+	gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+
+	/*
+	 * clock period is 32kHz (31250ns)
+	 * jitter is +/- 2% (20 per mille)
+	 */
+	ts_chip.clock_period = 31250;
+	ts_chip.jitter = 20;
+	ts_chip.init_period = inv_icm42607_odr_to_period(st->conf.gyro.odr);
+	inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_gyro_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_gyro_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+	indio_dev->available_scan_masks = inv_icm42607_gyro_scan_masks;
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 13:18:31 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 15:18:31 -0500
Subject: [PATCH V10 9/9] arm64: dts: rockchip: Add icm42607p IMU for RG-DS
In-Reply-To: <20260604201832.60656-1-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
Message-ID: <20260604201832.60656-10-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix
was tested with iio-sensor-proxy and reports correct orientation.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
index 8d906ab02c5fb..b770bfd5268d8 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
@@ -871,7 +871,13 @@ aw87391_pa_r: audio-codec at 5b {
 		sound-name-prefix = "Right Amp";
 	};
 
-	/* invensense,icm42607p at 0x68 */
+	icm42607p: imu at 68 {
+		compatible = "invensense,icm42607p";
+		reg = <0x68>;
+		mount-matrix = "-1", "0", "0",
+			       "0", "1", "0",
+			       "0", "0", "-1";
+	};
 };
 
 &i2c3 {
-- 
2.43.0



From sebastian.reichel at collabora.com  Thu Jun  4 14:58:12 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Thu, 4 Jun 2026 23:58:12 +0200
Subject: [PATCH V4 2/6] power: supply: sgm41542: Add SG Micro sgm41542
 charger
In-Reply-To: <20260602212512.418166-3-macroalpha82@gmail.com>
References: <20260602212512.418166-1-macroalpha82@gmail.com>
 <20260602212512.418166-3-macroalpha82@gmail.com>
Message-ID: <aiHgeP2mCISWLliq@venus>

Hi,

On Tue, Jun 02, 2026 at 04:25:08PM -0500, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add support for the SG Micro SGM41542 charger/boost converter.
> Driver was adapted from Rockchip BSP driver [1] and confirmed
> with vendor datasheet [2].
> 
> [1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
> [2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---

This looks mostly okay, but I have a few comments; please find them
inline.

>  drivers/power/supply/Kconfig            |    8 +
>  drivers/power/supply/Makefile           |    1 +
>  drivers/power/supply/sgm41542_charger.c | 1065 +++++++++++++++++++++++
>  3 files changed, 1074 insertions(+)
>  create mode 100644 drivers/power/supply/sgm41542_charger.c
> 
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 83392ed6a8da..57dae0913472 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -856,6 +856,14 @@ config CHARGER_RK817
>  	help
>  	  Say Y to include support for Rockchip RK817 Battery Charger.
>  
> +config CHARGER_SGM41542
> +	tristate "SGM41542 charger driver"
> +	depends on I2C
> +	depends on GPIOLIB || COMPILE_TEST
> +	select REGMAP_I2C
> +	help
> +	  Say Y to enable support for the SGM41542 battery charger.
> +
>  config CHARGER_SMB347
>  	tristate "Summit Microelectronics SMB3XX Battery Charger"
>  	depends on I2C
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 7ee839dca7f3..c376889db317 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
>  obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
>  obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
>  obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
> +obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
>  obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
>  obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
>  obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
> diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
> new file mode 100644
> index 000000000000..334767df3d9e
> --- /dev/null
> +++ b/drivers/power/supply/sgm41542_charger.c
> @@ -0,0 +1,1065 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Chrager driver for Sgm4154x

Charger

> + *
> + * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
> + *
> + * Author: Xu Shengfei <xsf at rock-chips.com>
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/power_supply.h>

#include <linux/property.h>

> +#include <linux/regmap.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/of_regulator.h>
> +#include <linux/regulator/machine.h>

machine.h?

> +#include <linux/types.h>
> +
> +#define SGM4154X_MANUFACTURER			"SGMICRO"
> +#define SGM4154X_NAME				"sgm41542"
> +
> +#define SGM4154X_CHRG_CTRL_0			0x00
> +#define SGM4154X_HIZ_EN				BIT(7)
> +#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
> +#define SGM4154X_IINDPM_I_MIN_UA		100000
> +#define SGM4154X_IINDPM_I_MAX_UA		3800000
> +#define SGM4154X_IINDPM_STEP_UA			100000
> +#define SGM4154X_IINDPM_DEF_UA			2400000
> +
> +#define SGM4154X_CHRG_CTRL_1			0x01
> +#define SGM4154X_WDT_RST			BIT(6)
> +#define SGM4154X_OTG_EN				BIT(5)
> +#define SGM4154X_CHRG_EN			BIT(4)
> +
> +#define SGM4154X_CHRG_CTRL_2			0x02
> +#define SGM4154X_BOOST_LIM			BIT(7)
> +#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
> +#define SGM4154X_ICHRG_I_STEP_UA		60000
> +#define SGM4154X_ICHRG_I_MIN_UA			0
> +#define SGM4154X_ICHRG_I_MAX_UA			3780000
> +#define SGM4154X_ICHRG_I_DEF_UA			2040000
> +
> +#define SGM4154X_CHRG_CTRL_3			0x03
> +#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
> +#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
> +#define SGM4154X_PRECHRG_I_MIN_UA		60000
> +#define SGM4154X_PRECHRG_I_MAX_UA		780000
> +#define SGM4154X_PRECHRG_I_DEF_UA		180000
> +#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
> +#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
> +#define SGM4154X_TERMCHRG_I_MIN_UA		60000
> +#define SGM4154X_TERMCHRG_I_MAX_UA		960000
> +#define SGM4154X_TERMCHRG_I_DEF_UA		180000
> +
> +#define SGM4154X_CHRG_CTRL_4			0x04
> +#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
> +#define SGM4154X_VREG_V_MAX_UV			4624000
> +#define SGM4154X_VREG_V_MIN_UV			3856000
> +#define SGM4154X_VREG_V_DEF_UV			4208000
> +#define SGM4154X_VREG_V_STEP_UV			32000
> +#define SGM4154X_VRECHARGE			BIT(0)
> +#define SGM4154X_VRECHRG_STEP_MV		100
> +#define SGM4154X_VRECHRG_OFFSET_MV		100
> +
> +#define SGM4154X_CHRG_CTRL_5			0x05
> +#define SGM4154X_TERM_EN			BIT(7)
> +#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
> +#define SGM4154X_WDT_TIMER_40S			BIT(4)
> +#define SGM4154X_WDT_TIMER_80S			BIT(5)
> +#define SGM4154X_WDT_TIMER_160S			(BIT(4) | BIT(5))
> +#define SGM4154X_WDT_TIMER_DISABLE		0
> +
> +#define SGM4154X_CHRG_CTRL_6			0x06
> +#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
> +#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
> +#define SGM4154X_OVP_10_5V			BIT(7)
> +#define SGM4154X_OVP_6_5V			BIT(6)
> +#define SGM4154X_OVP_5_5V			0
> +#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
> +#define SGM4154X_BOOSTV				GENMASK(5, 4)
> +#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
> +#define SGM4154X_VINDPM_V_MIN_UV		3900000
> +#define SGM4154X_VINDPM_V_MAX_UV		12000000
> +#define SGM4154X_VINDPM_STEP_UV			100000
> +#define SGM4154X_VINDPM_DEF_UV			4500000
> +
> +#define SGM4154X_CHRG_CTRL_7			0x07
> +
> +#define SGM4154X_CHRG_STAT		0x08
> +#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
> +#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
> +#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
> +#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
> +#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
> +#define SGM4154X_USB_CDP		BIT(6)
> +#define SGM4154X_USB_SDP		BIT(5)
> +#define SGM4154X_NOT_CHRGING		0
> +#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
> +#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
> +#define SGM4154X_FAST_CHRG		BIT(4)
> +#define SGM4154X_PRECHRG		BIT(3)
> +#define SGM4154X_PG_STAT		BIT(2)
> +#define SGM4154X_THERM_STAT		BIT(1)
> +#define SGM4154X_VSYS_STAT		BIT(0)
> +
> +#define SGM4154X_CHRG_FAULT		0x09
> +#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
> +#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
> +#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
> +#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
> +#define SGM4154X_TEMP_WARM		BIT(1)
> +#define SGM4154X_TEMP_NORMAL		BIT(0)
> +
> +#define SGM4154X_CHRG_CTRL_A		0x0a
> +#define SGM4154X_VBUS_GOOD		BIT(7)
> +#define SGM4154X_VINDPM_INT_MASK	BIT(1)
> +#define SGM4154X_IINDPM_INT_MASK	BIT(0)
> +
> +#define SGM4154X_CHRG_CTRL_B		0x0b
> +#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
> +#define SGM4154X_PN_MASK		GENMASK(6, 3)
> +
> +#define SGM4154X_CHRG_CTRL_C		0x0c
> +
> +#define SGM4154X_CHRG_CTRL_D		0x0d
> +#define SGM4154X_JEITA_EN		BIT(0)
> +
> +#define SGM4154X_INPUT_DET		0x0e
> +#define SGM4154X_DPDM_ONGOING		BIT(7)
> +
> +#define SGM4154X_CHRG_CTRL_F		0x0f
> +#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
> +
> +#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
> +
> +struct sgm4154x_init_data {
> +	int ilim;	/* input current limit */
> +	int vlim;	/* minimum system voltage limit */
> +	int iterm;	/* termination current */
> +	int iprechg;	/* precharge current */
> +	int max_ichg;	/* maximum charge current */
> +	int max_vreg;	/* maximum charge voltage */
> +};
> +
> +struct sgm4154x_state {
> +	bool vsys_stat;
> +	bool therm_stat;
> +	bool online;
> +	u8 chrg_stat;
> +	bool chrg_en;
> +	bool vbus_gd;
> +	u8 chrg_type;
> +	u8 health;
> +	u8 chrg_fault;
> +	u8 ntc_fault;
> +};
> +
> +struct sgm4154x_device {
> +	struct i2c_client *client;
> +	struct device *dev;
> +	struct power_supply *charger;
> +	struct regmap *regmap;
> +	char model_name[I2C_NAME_SIZE];
> +	struct sgm4154x_init_data init_data;
> +	struct sgm4154x_state state;
> +	struct regulator_dev *otg_rdev;
> +	bool watchdog_enable;
> +	struct workqueue_struct *sgm_monitor_wq;
> +	struct delayed_work sgm_delay_work;
> +};
> +
> +enum SGM4154X_VINDPM_OS {
> +	VINDPM_OS_3900MV,
> +	VINDPM_OS_5900MV,
> +	VINDPM_OS_7500MV,
> +	VINDPM_OS_10500MV,
> +};
> +
> +static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
> +	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_3,
> +				 SGM4154X_TERMCHRG_CUR_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set term current error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
> +	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
> +
> +	reg_val = reg_val << 4;

FIELD_PREP(SGM4154X_PRECHRG_CUR_MASK, reg_val);

> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_3,
> +				 SGM4154X_PRECHRG_CUR_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set precharge current error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, SGM4154X_ICHRG_I_MAX_UA);
> +	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_2,
> +				 SGM4154X_ICHRG_CUR_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set icharge current error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
> +{
> +	u32 reg;
> +	int ret, val;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
> +	if (ret) {
> +		dev_err(sgm->dev, "get charge current error!\n");
> +		return ret;
> +	}
> +
> +	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
> +
> +	return val * SGM4154X_ICHRG_I_STEP_UA;
> +}
> +
> +static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	/*
> +	 * Note that the value of 0x01111 represents a "special value"
> +	 * corresponding to 4352000uV instead of the expected 4336000uV,
> +	 * per the datasheet. All other values are as expected. So not
> +	 * only do we need to clamp between max and min values, but
> +	 * also clamp anything below 4352000uv to 4304000uv to prevent
> +	 * overcharging.
> +	 */
> +	if (chrg_volt < 4352000)
> +		chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, 4304000);
> +	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
> +	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
> +	reg_val = reg_val << 3;

FIELD_PREP

> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_4,
> +				 SGM4154X_VREG_V_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set charge voltage error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
> +{
> +	u32 reg;
> +	int ret, val;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
> +	if (ret) {
> +		dev_err(sgm->dev, "get charge voltage error!\n");
> +		return ret;
> +	}
> +
> +	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
> +
> +	/*
> +	 * 0x01111 is a special value meaning 4352000uV, all other
> +	 * values are as expected based on the offset and step values.
> +	 */
> +	if (val == 0x0f)
> +		return 4352000;
> +
> +	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
> +}
> +
> +static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
> +				       unsigned int vindpm)
> +{
> +	enum SGM4154X_VINDPM_OS os_val;
> +	unsigned int offset;
> +	u8 reg_val;
> +	int ret;
> +
> +
> +	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
> +	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
> +		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * Supported ranges per the datasheet are as follows:
> +	 * 3.9v - 5.4v with a 3.9v offset
> +	 * 5.9v - 7.4v with a 5.9v offset
> +	 * 7.5v - 9.0v with a 7.5v offset
> +	 * 10.5v - 12.0v with a 10.5v offset
> +	 * Step size is a constant 100mv
> +	 */
> +	if (vindpm < 5900000) {
> +		vindpm = clamp(vindpm, VINDPM_OS_3900MV, 5400000);

As far as I can tell the lower clamp value is wrong here
and in the following else branches. I doubt you want the
enum values.

> +		os_val = VINDPM_OS_3900MV;
> +		offset = 3900000;
> +	} else if (vindpm >= 5900000 && vindpm < 7500000) {

You can drop the "vindpm >= 5900000 &&", that already covered
by the previous if.

> +		vindpm = clamp(vindpm, VINDPM_OS_5900MV, 7400000);
> +		os_val = VINDPM_OS_5900MV;
> +		offset = 5900000;
> +	} else if (vindpm >= 7500000 && vindpm < 10500000) {
> +		vindpm = clamp(vindpm, VINDPM_OS_7500MV, 9000000);
> +		os_val = VINDPM_OS_7500MV;
> +		offset = 7500000;
> +	} else {
> +		vindpm = clamp(vindpm, VINDPM_OS_10500MV, 12000000);
> +		os_val = VINDPM_OS_10500MV;
> +		offset = 10500000;
> +	}
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_F,
> +				 SGM4154X_VINDPM_OS_MASK,
> +				 os_val);
> +	if (ret) {
> +		dev_err(sgm->dev, "set vin dpm error!\n");
> +		return ret;
> +	}
> +
> +	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
> +
> +	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
> +				 SGM4154X_VINDPM_V_MASK, reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "input voltage error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
> +		return -EINVAL;
> +
> +	/*
> +	 * Per the datasheet, values between 100000uA and 3100000uA work
> +	 * as expected with the register defined as having a step of
> +	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
> +	 * The register value of 0x1f however corresponds to 3800000uA not
> +	 * 3200000uA as one would expect.
> +	 */
> +	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
> +		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
> +
> +	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
> +		iindpm = 3100000;
> +
> +	if (iindpm == SGM4154X_IINDPM_I_MAX_UA)
> +		reg_val = 0x1f;
> +	else
> +		reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_0,
> +				 SGM4154X_IINDPM_I_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set input current limit error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
> +{
> +	int ret;
> +	int ilim;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
> +	if (ret) {
> +		dev_err(sgm->dev, "get input current limit error!\n");
> +		return ret;
> +	}

ilim &= SGM4154X_IINDPM_I_MASK;

Then you can just use ilim in the following code.

> +	/* Max value is not 3200000uA as expected but is 3800000uA */
> +	if (SGM4154X_IINDPM_I_MASK == (ilim & SGM4154X_IINDPM_I_MASK))
> +		return SGM4154X_IINDPM_I_MAX_UA;
> +
> +	ilim = (ilim & SGM4154X_IINDPM_I_MASK) * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
> +
> +	return ilim;
> +}
> +
> +static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_1,
> +				 SGM4154X_WDT_RST,
> +				 SGM4154X_WDT_RST);
> +
> +	if (ret)
> +		dev_err(sgm->dev, "set watchdog timer error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, int time)
> +{
> +	u8 reg_val;
> +	int ret;
> +
> +	if (time == 0)
> +		reg_val = SGM4154X_WDT_TIMER_DISABLE;
> +	else if (time == 40)
> +		reg_val = SGM4154X_WDT_TIMER_40S;
> +	else if (time == 80)
> +		reg_val = SGM4154X_WDT_TIMER_80S;
> +	else
> +		reg_val = SGM4154X_WDT_TIMER_160S;

enum sgm4154x_wdt_timer {
    SGM4154X_WDT_TIMER_DISABLE = 0,
    SGM4154X_WDT_TIMER_40S = 1,
    SGM4154X_WDT_TIMER_80S = 2,
    SGM4154X_WDT_TIMER_160S = 3,
};

static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, enum sgm4154x_wdt_timer time) {
    ...
    reg_val = FIELD_PREP(SGM4154X_WDT_TIMER_MASK, time);
    ...

This is less code, easier to read and also fixes the bug you have
down below, where the function is already called with
SGM4154X_WDT_TIMER_40S as argument, which right now would result in
160 seconds being configured...

> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_5,
> +				 SGM4154X_WDT_TIMER_MASK,
> +				 reg_val);
> +
> +	if (ret) {
> +		dev_err(sgm->dev, "set watchdog timer error!\n");
> +		return ret;
> +	}
> +
> +	if (time) {
> +		if (!sgm->watchdog_enable)
> +			queue_delayed_work(sgm->sgm_monitor_wq,
> +					   &sgm->sgm_delay_work,
> +					   msecs_to_jiffies(1000 * 5));
> +		sgm->watchdog_enable = true;
> +	} else {
> +		sgm->watchdog_enable = false;
> +		sgm4154x_watchdog_timer_reset(sgm);
> +	}
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_1,
> +				 SGM4154X_CHRG_EN,
> +				 SGM4154X_CHRG_EN);
> +	if (ret)
> +		dev_err(sgm->dev, "enable charger error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_1,
> +				 SGM4154X_CHRG_EN,
> +				 0);
> +	if (ret)
> +		dev_err(sgm->dev, "disable charger error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
> +
> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_6,
> +				 SGM4154X_VAC_OVP_MASK,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set vac ovp error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_set_recharge_volt(struct sgm4154x_device *sgm, int recharge_volt)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;

I think it makes sense to convert the function to microvolt to be
consistent.

> +	ret = regmap_update_bits(sgm->regmap,
> +				 SGM4154X_CHRG_CTRL_4,
> +				 SGM4154X_VRECHARGE,
> +				 reg_val);
> +	if (ret)
> +		dev_err(sgm->dev, "set recharger error!\n");
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_get_state(struct sgm4154x_device *sgm,
> +			      struct sgm4154x_state *state)
> +{
> +	int reg, ret;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
> +	if (ret) {
> +		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
> +		return ret;
> +	}
> +	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
> +	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
> +	state->online = !!(reg & SGM4154X_PG_STAT);
> +	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
> +	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
> +	if (ret) {
> +		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
> +		return ret;
> +	}
> +	state->chrg_fault = reg;
> +	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
> +	state->health = state->ntc_fault;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
> +	if (ret) {
> +		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
> +		return ret;
> +	}
> +	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_property_is_writeable(struct power_supply *psy,
> +					  enum power_supply_property prop)
> +{
> +	switch (prop) {
> +	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
> +	case POWER_SUPPLY_PROP_ONLINE:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static int sgm4154x_charger_set_property(struct power_supply *psy,
> +					 enum power_supply_property prop,
> +					 const union power_supply_propval *val)
> +{
> +	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
> +	int ret = -EINVAL;
> +
> +	switch (prop) {
> +	case POWER_SUPPLY_PROP_ONLINE:
> +		if (val->intval) {
> +			ret = sgm4154x_enable_charger(sgm);
> +			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
> +		} else {
> +			sgm4154x_set_watchdog_timer(sgm, 0);
> +			ret = sgm4154x_disable_charger(sgm);
> +		}
> +		break;
> +
> +	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
> +		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
> +		break;
> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
> +		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
> +		break;
> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
> +		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int sgm4154x_charger_get_property(struct power_supply *psy,
> +					 enum power_supply_property psp,
> +					 union power_supply_propval *val)
> +{
> +	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
> +	struct sgm4154x_state state;
> +	int ret;
> +
> +	ret = sgm4154x_get_state(sgm, &state);
> +	if (ret) {
> +		dev_err(sgm->dev, "get state error!\n");
> +		return ret;
> +	}
> +	sgm->state = state;
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_STATUS:
> +		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
> +			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
> +		else if (!state.chrg_stat)
> +			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
> +		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
> +			val->intval = POWER_SUPPLY_STATUS_FULL;
> +		else
> +			val->intval = POWER_SUPPLY_STATUS_CHARGING;
> +		break;
> +	case POWER_SUPPLY_PROP_CHARGE_TYPE:
> +		switch (state.chrg_stat) {
> +		case SGM4154X_PRECHRG:
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
> +			break;
> +		case SGM4154X_FAST_CHRG:
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
> +			break;
> +		case SGM4154X_TERM_CHRG:
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
> +			break;
> +		case SGM4154X_NOT_CHRGING:
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
> +			break;
> +		default:
> +			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
> +		}
> +		break;
> +	case POWER_SUPPLY_PROP_MANUFACTURER:
> +		val->strval = SGM4154X_MANUFACTURER;
> +		break;
> +
> +	case POWER_SUPPLY_PROP_MODEL_NAME:
> +		val->strval = SGM4154X_NAME;
> +		break;
> +
> +	case POWER_SUPPLY_PROP_ONLINE:
> +		val->intval = state.online;
> +		break;
> +	case POWER_SUPPLY_PROP_PRESENT:
> +		val->intval = state.vbus_gd;
> +		break;
> +	case POWER_SUPPLY_PROP_TYPE:
> +		val->intval = POWER_SUPPLY_TYPE_USB;
> +		break;

Drop. POWER_SUPPLY_PROP_TYPE is exposed and handled automatically.

> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
> +		val->intval = sgm4154x_get_chrg_volt(sgm);
> +		if (val->intval < 0)
> +			return -EINVAL;
> +		break;
> +	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
> +		val->intval = sgm4154x_get_ichrg_curr(sgm);
> +		if (val->intval < 0)
> +			return -EINVAL;
> +		break;
> +	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
> +		val->intval = sgm->init_data.vlim;
> +		break;
> +	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
> +		val->intval = sgm4154x_get_input_curr_lim(sgm);
> +		if (val->intval < 0)
> +			return  -EINVAL;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
> +{
> +	struct sgm4154x_device *sgm4154x = private;
> +	struct sgm4154x_state state;
> +	int ret;
> +
> +	ret = sgm4154x_get_state(sgm4154x, &state);
> +	if (ret) {
> +		dev_err(sgm4154x->dev, "get state error!\n");
> +		return IRQ_NONE;
> +	}
> +	sgm4154x->state = state;
> +	if (state.vbus_gd) {
> +		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
> +			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
> +			if (ret) {
> +				dev_err(sgm4154x->dev, "set input current error!\n");
> +				return IRQ_NONE;
> +			}
> +		}
> +	}
> +	power_supply_changed(sgm4154x->charger);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static enum power_supply_property sgm4154x_power_supply_props[] = {
> +	POWER_SUPPLY_PROP_TYPE,

Also drop it from here :)

> +	POWER_SUPPLY_PROP_MANUFACTURER,
> +	POWER_SUPPLY_PROP_MODEL_NAME,
> +	POWER_SUPPLY_PROP_STATUS,
> +	POWER_SUPPLY_PROP_ONLINE,
> +	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
> +	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
> +	POWER_SUPPLY_PROP_CHARGE_TYPE,
> +	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
> +	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
> +	POWER_SUPPLY_PROP_PRESENT
> +};
> +
> +static char *sgm4154x_charger_supplied_to[] = {
> +	"battery-monitor",
> +};

why?

> +static struct power_supply_desc sgm4154x_power_supply_desc = {
> +	.name = "sgm4154x-charger",
> +	.type = POWER_SUPPLY_TYPE_USB,
> +	.properties = sgm4154x_power_supply_props,battery-monitor
> +	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
> +	.get_property = sgm4154x_charger_get_property,
> +	.set_property = sgm4154x_charger_set_property,
> +	.property_is_writeable = sgm4154x_property_is_writeable,
> +};
> +
> +static const struct regmap_config sgm4154x_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.max_register = SGM4154X_CHRG_CTRL_F,
> +	.cache_type = REGCACHE_NONE,
> +};
> +
> +static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
> +				      struct device *dev)
> +{
> +	struct power_supply_config psy_cfg = { .drv_data = sgm,
> +					       .fwnode = dev->fwnode, };
> +
> +	psy_cfg.supplied_to = sgm4154x_charger_supplied_to;
> +	psy_cfg.num_supplicants = ARRAY_SIZE(sgm4154x_charger_supplied_to);

I doubt you want to set any hardcoded supplied data and rely on the
DT setup (i.e. add "power-supplies" property).

> +	psy_cfg.fwnode = dev->fwnode;

You already set that a few lines above.

> +	sgm->charger = devm_power_supply_register(sgm->dev,
> +						  &sgm4154x_power_supply_desc,
> +						  &psy_cfg);
> +	if (IS_ERR(sgm->charger))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
> +{
> +	struct power_supply_battery_info *bat_info;
> +	int ret;
> +	u32 val;
> +
> +	/*
> +	 * If unable to read devicetree info, use default/reset
> +	 * values from hardware.
> +	 */
> +	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
> +	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
> +	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
> +	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
> +	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
> +	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
> +
> +	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
> +	if (ret)
> +		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
> +	else {
> +		if (bat_info->constant_charge_current_max_ua)
> +			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
> +		if (bat_info->constant_charge_voltage_max_uv)
> +			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
> +		if (bat_info->charge_term_current_ua)
> +			sgm->init_data.iterm = bat_info->charge_term_current_ua;
> +		if (bat_info->precharge_current_ua)
> +			sgm->init_data.iprechg = bat_info->precharge_current_ua;
> +
> +		power_supply_put_battery_info(sgm->charger, bat_info);
> +	}
> +
> +	ret = device_property_read_u32(sgm->dev,
> +				       "input-voltage-limit-microvolt",
> +				       &val);
> +	if (!ret)
> +		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
> +					    SGM4154X_VINDPM_V_MAX_UV);
> +
> +	ret = device_property_read_u32(sgm->dev,
> +				       "input-current-limit-microamp",
> +				       &val);
> +	if (!ret)
> +		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
> +					    SGM4154X_IINDPM_I_MAX_UA);
> +
> +	ret = sgm4154x_set_watchdog_timer(sgm, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
> +	if (ret)
> +		return ret;
> +
> +	ret = sgm4154x_set_vac_ovp(sgm);
> +	if (ret)
> +		return ret;
> +
> +	regmap_update_bits(sgm->regmap,
> +			   SGM4154X_CHRG_CTRL_D,
> +			   SGM4154X_JEITA_EN,
> +			   0);
> +
> +	regmap_update_bits(sgm->regmap,
> +			   SGM4154X_CHRG_CTRL_A,
> +			   SGM4154X_IINDPM_INT_MASK,
> +			   SGM4154X_IINDPM_INT_MASK);
> +
> +	regmap_update_bits(sgm->regmap,
> +			   SGM4154X_CHRG_CTRL_A,
> +			   SGM4154X_VINDPM_INT_MASK,
> +			   SGM4154X_VINDPM_INT_MASK);
> +
> +	/*
> +	 * Recharge voltage set to 200 by BSP driver instead of hardware
> +	 * default value of 100.
> +	 */
> +	ret = sgm4154x_set_recharge_volt(sgm, 200);
> +
> +	return ret;
> +}
> +
> +static const u32 sgm4154x_chg_otg_cur_ua[] = {
> +	1200000, 2000000,
> +};
> +
> +static const struct regulator_ops sgm4154x_vbus_ops = {
> +	.list_voltage = regulator_list_voltage_linear,
> +	.enable = regulator_enable_regmap,
> +	.disable = regulator_disable_regmap,
> +	.is_enabled = regulator_is_enabled_regmap,
> +	.set_voltage_sel = regulator_set_voltage_sel_regmap,
> +	.get_voltage_sel = regulator_get_voltage_sel_regmap,
> +	.set_current_limit = regulator_set_current_limit_regmap,
> +	.get_current_limit = regulator_get_current_limit_regmap,
> +};
> +
> +static const struct regulator_desc sgm4154x_otg_rdesc = {
> +	.of_match = "otg-vbus",
> +	.name = "otg-vbus",
> +	.regulators_node = of_match_ptr("regulators"),
> +	.ops = &sgm4154x_vbus_ops,
> +	.owner = THIS_MODULE,
> +	.type = REGULATOR_VOLTAGE,
> +	.min_uV = 4850000,
> +	.uV_step = 150000,
> +	.n_voltages = 4,
> +	.vsel_reg = SGM4154X_CHRG_CTRL_6,
> +	.vsel_mask = SGM4154X_BOOSTV,
> +	.enable_reg = SGM4154X_CHRG_CTRL_1,
> +	.enable_mask = SGM4154X_OTG_EN,
> +	.curr_table = sgm4154x_chg_otg_cur_ua,
> +	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
> +	.csel_reg = SGM4154X_CHRG_CTRL_2,
> +	.csel_mask = SGM4154X_BOOST_LIM,
> +};
> +
> +static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
> +{
> +	struct regulator_config config = {
> +		.dev = sgm->dev,
> +		.regmap = sgm->regmap,
> +		.driver_data = sgm,
> +	};
> +
> +	sgm->otg_rdev = devm_regulator_register(sgm->dev,
> +						&sgm4154x_otg_rdesc,
> +						&config);
> +
> +	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
> +}
> +
> +static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
> +{
> +	int ret;
> +	int val;
> +
> +	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
> +	if (ret)
> +		return ret;
> +
> +	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
> +		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
> +
> +	return 0;
> +}
> +
> +static void sgm_charger_work(struct work_struct *work)
> +{
> +	struct sgm4154x_device *sgm =
> +		container_of(work,
> +			     struct sgm4154x_device,
> +			     sgm_delay_work.work);
> +
> +	sgm4154x_watchdog_timer_reset(sgm);
> +	if (sgm->watchdog_enable)
> +		queue_delayed_work(sgm->sgm_monitor_wq,
> +				   &sgm->sgm_delay_work,
> +				   msecs_to_jiffies(1000 * 5));
> +}
> +
> +static int sgm4154x_probe(struct i2c_client *client)
> +{
> +	const struct i2c_device_id *id = i2c_client_get_device_id(client);
> +	struct device *dev = &client->dev;
> +	struct sgm4154x_device *sgm;
> +	int ret;
> +
> +	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
> +	if (!sgm)
> +		return -ENOMEM;
> +
> +	sgm->client = client;

You can drop sgm->client as it is unused.

> +	sgm->dev = dev;
> +
> +	strscpy(sgm->model_name, id->name, I2C_NAME_SIZE);
> +
> +	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
> +	if (IS_ERR(sgm->regmap))
> +		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
> +				     "Failed to allocate register map\n");
> +
> +	i2c_set_clientdata(client, sgm);
> +
> +	ret = sgm4154x_hw_chipid_detect(sgm);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Unable to read HW ID\n");
> +
> +	device_init_wakeup(dev, 1);
> +
> +	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "%s",
> +			WQ_MEM_RECLAIM | WQ_FREEZABLE, "sgm-monitor-wq");

For a fixed name you don't need "%s".

> +	if (!sgm->sgm_monitor_wq)
> +		return -EINVAL;
> +
> +	ret = sgm4154x_power_supply_init(sgm, dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to register power supply\n");
> +
> +	ret = sgm4154x_hw_init(sgm);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
> +
> +	if (client->irq) {
> +		ret = devm_request_threaded_irq(dev, client->irq, NULL,
> +						sgm4154x_irq_handler_thread,
> +						IRQF_TRIGGER_FALLING |
> +						IRQF_ONESHOT,
> +						"sgm41542-irq", sgm);
> +		if (ret)
> +			return ret;
> +
> +		enable_irq_wake(client->irq);

missing disable on module removal, use devm_add_action_or_reset() to
register disable_irq_wake. Then you can also drop the extra call a
few lines below.

> +	}
> +
> +	INIT_DELAYED_WORK(&sgm->sgm_delay_work, sgm_charger_work);

devm_delayed_work_autocancel(), otherwise the delayed work may run
after module removal.

> +	ret = sgm4154x_vbus_regulator_register(sgm);
> +	if (ret) {
> +		disable_irq_wake(client->irq);
> +		return dev_err_probe(dev, ret,
> +				     "Unable to register VBUS regulator\n");
> +	}
> +
> +	return 0;
> +}
> +
> +static void sgm4154x_charger_shutdown(struct i2c_client *client)
> +{
> +	struct sgm4154x_device *sgm = i2c_get_clientdata(client);
> +
> +	sgm4154x_set_prechrg_curr(sgm, SGM4154X_PRECHRG_I_DEF_UA);
> +	sgm4154x_disable_charger(sgm);
> +}
> +
> +static const struct i2c_device_id sgm4154x_i2c_ids[] = {
> +	{ "sgm41542" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
> +
> +static const struct of_device_id sgm4154x_of_match[] = {
> +	{ .compatible = "sgmicro,sgm41542", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
> +
> +static struct i2c_driver sgm4154x_driver = {
> +	.driver = {
> +		.name = "sgm4154x-charger",
> +		.of_match_table = sgm4154x_of_match,
> +	},
> +	.probe = sgm4154x_probe,
> +	.shutdown = sgm4154x_charger_shutdown,
> +	.id_table = sgm4154x_i2c_ids,
> +};
> +
> +module_i2c_driver(sgm4154x_driver);
> +
> +MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
> +MODULE_DESCRIPTION("sgm4154x charger driver");
> +MODULE_LICENSE("GPL");

Greetings,

-- Sebastian
-------------- 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-rockchip/attachments/20260604/a657ccaf/attachment-0001.sig>

From macroalpha82 at gmail.com  Thu Jun  4 15:07:55 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:07:55 -0500
Subject: [PATCH V5 0/6] Add Anbernic RG Vita-Pro
Message-ID: <20260604220802.119107-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the Anbernic RG Vita-Pro, based on the Rockchip RK3576 SoC.

Changes Since V1:
 - Updated documentation filename to matche compatible string.
 - Corrected order of allocating IRQ in charger driver and switched
   to using devm managed function to allocate work queue.
Changes Since V2:
 - Corrected issue with naming of panel binding document and added
   fallback compatible string.
 - Switched to devm helpers in panel driver. Note that
   devm_drm_panel_add() is currently only in the drm-next branch.
 - Optimized setting GPIOs for panel driver.
Changes Since V3:
 - Fixed numerous issues identifed by Sashiko bot, mainly relating
   to unclamped or improperly clamped values from within the
   charger driver.
 - Corrected hard-coded values in the panel driver unprepare routine
   as well as correcting an improperly checked return condition.
Changes Since V4:
 - Fixed errors identified by Sashiko bot on charger driver that could
   result in an improper value being written to the registers.
 - Corrected some error handling in the panel driver.

Chris Morgan (6):
  dt-bindings: power: supply: sgm41542: document sgm41542
  power: supply: sgm41542: Add SG Micro sgm41542 charger
  dt-bindings: display: panel: Add Anbernic TD4310 panel
  drm/panel: anbernic-td4310: Add RG Vita Pro panel
  dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
  arm64: dts: rockchip: Add Anbernic RG Vita-Pro

 .../devicetree/bindings/arm/rockchip.yaml     |    6 +
 .../display/panel/anbernic,td4310.yaml        |   66 +
 .../power/supply/sgmicro,sgm41542.yaml        |  104 ++
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 drivers/gpu/drm/panel/Kconfig                 |   10 +
 drivers/gpu/drm/panel/Makefile                |    1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c |  256 ++++
 drivers/power/supply/Kconfig                  |    8 +
 drivers/power/supply/Makefile                 |    1 +
 drivers/power/supply/sgm41542_charger.c       | 1075 +++++++++++++
 11 files changed, 2855 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
 create mode 100644 drivers/power/supply/sgm41542_charger.c

-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:07:56 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:07:56 -0500
Subject: [PATCH V5 1/6] dt-bindings: power: supply: sgm41542: document sgm41542
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Document the SG Micro sgm41542 battery charger/boost converter.
The parameters of input-current-limit-microamp and
input-voltage-limit-microvolt are defined as such since they are in
common use among multiple bindings currently.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../power/supply/sgmicro,sgm41542.yaml        | 104 ++++++++++++++++++
 1 file changed, 104 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
new file mode 100644
index 000000000000..a97afea83700
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SGM41542 Battery Charger
+
+description:
+  The SGMicro SGM41542 is a single cell battery charger/boost controller.
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+  - Xu Shengfei <xsf at rock-chips.com>
+
+allOf:
+  - $ref: power-supply.yaml#
+
+properties:
+  compatible:
+    const: sgmicro,sgm41542
+
+  input-current-limit-microamp:
+    description:
+      Optional value to clamp the maximum input current limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (2400000).
+    minimum: 100000
+    maximum: 3800000
+
+  input-voltage-limit-microvolt:
+    description:
+      Optional value to clamp the maximum input voltage limit to for
+      the device. If omitted, the default value for the hardware will
+      be used (4500000).
+    minimum: 3900000
+    maximum: 12000000
+
+  interrupts:
+    maxItems: 1
+
+  monitored-battery:
+    description: |
+        A phandle to a monitored battery node. Values for the following
+        are used by the driver and if not present will result in default
+        values being applied:
+        constant-charge-current-max-microamp
+        constant-charge-voltage-max-microvolt
+        charge-term-current-microamp
+        precharge-current-microamp
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    properties:
+      otg-vbus:
+        type: object
+        description: OTG boost regulator
+        $ref: /schemas/regulator/regulator.yaml
+        unevaluatedProperties: false
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    battery: battery {
+      compatible = "simple-battery";
+      constant-charge-current-max-microamp = <10000000>;
+      constant-charge-voltage-max-microvolt = <4350000>;
+      precharge-current-microamp = <180000>;
+      charge-term-current-microamp = <300000>;
+    };
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      charger at 3b {
+        compatible = "sgmicro,sgm41542";
+        reg = <0x3b>;
+        input-current-limit-microamp = <3000000>;
+        input-voltage-limit-microvolt = <4500000>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        monitored-battery = <&battery>;
+
+        regulators {
+          otg-vbus {
+            regulator-max-microvolt = <5000000>;
+            regulator-min-microvolt = <5000000>;
+          };
+        };
+      };
+    };
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:07:57 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:07:57 -0500
Subject: [PATCH V5 2/6] power: supply: sgm41542: Add SG Micro sgm41542 charger
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the SG Micro SGM41542 charger/boost converter.
Driver was adapted from Rockchip BSP driver [1] and confirmed
with vendor datasheet [2].

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
[2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/power/supply/Kconfig            |    8 +
 drivers/power/supply/Makefile           |    1 +
 drivers/power/supply/sgm41542_charger.c | 1074 +++++++++++++++++++++++
 3 files changed, 1084 insertions(+)
 create mode 100644 drivers/power/supply/sgm41542_charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 83392ed6a8da..57dae0913472 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -856,6 +856,14 @@ config CHARGER_RK817
 	help
 	  Say Y to include support for Rockchip RK817 Battery Charger.
 
+config CHARGER_SGM41542
+	tristate "SGM41542 charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the SGM41542 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB3XX Battery Charger"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7ee839dca7f3..c376889db317 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
+obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
new file mode 100644
index 000000000000..7aac4dd65507
--- /dev/null
+++ b/drivers/power/supply/sgm41542_charger.c
@@ -0,0 +1,1074 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Chrager driver for Sgm4154x
+ *
+ * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Xu Shengfei <xsf at rock-chips.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
+#include <linux/types.h>
+
+#define SGM4154X_MANUFACTURER			"SGMICRO"
+#define SGM4154X_NAME				"sgm41542"
+
+#define SGM4154X_CHRG_CTRL_0			0x00
+#define SGM4154X_HIZ_EN				BIT(7)
+#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
+#define SGM4154X_IINDPM_I_MIN_UA		100000
+#define SGM4154X_IINDPM_I_MAX_UA		3800000
+#define SGM4154X_IINDPM_STEP_UA			100000
+#define SGM4154X_IINDPM_DEF_UA			2400000
+
+#define SGM4154X_CHRG_CTRL_1			0x01
+#define SGM4154X_WDT_RST			BIT(6)
+#define SGM4154X_OTG_EN				BIT(5)
+#define SGM4154X_CHRG_EN			BIT(4)
+
+#define SGM4154X_CHRG_CTRL_2			0x02
+#define SGM4154X_BOOST_LIM			BIT(7)
+#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
+#define SGM4154X_ICHRG_I_STEP_UA		60000
+#define SGM4154X_ICHRG_I_MIN_UA			0
+#define SGM4154X_ICHRG_I_MAX_UA			3780000
+#define SGM4154X_ICHRG_I_DEF_UA			2040000
+
+#define SGM4154X_CHRG_CTRL_3			0x03
+#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
+#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_PRECHRG_I_MIN_UA		60000
+#define SGM4154X_PRECHRG_I_MAX_UA		780000
+#define SGM4154X_PRECHRG_I_DEF_UA		180000
+#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
+#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_TERMCHRG_I_MIN_UA		60000
+#define SGM4154X_TERMCHRG_I_MAX_UA		960000
+#define SGM4154X_TERMCHRG_I_DEF_UA		180000
+
+#define SGM4154X_CHRG_CTRL_4			0x04
+#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
+#define SGM4154X_VREG_V_MAX_UV			4624000
+#define SGM4154X_VREG_V_MIN_UV			3856000
+#define SGM4154X_VREG_V_DEF_UV			4208000
+#define SGM4154X_VREG_V_STEP_UV			32000
+#define SGM4154X_VRECHARGE			BIT(0)
+#define SGM4154X_VRECHRG_STEP_MV		100
+#define SGM4154X_VRECHRG_OFFSET_MV		100
+
+#define SGM4154X_CHRG_CTRL_5			0x05
+#define SGM4154X_TERM_EN			BIT(7)
+#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
+#define SGM4154X_WDT_TIMER_40S			BIT(4)
+#define SGM4154X_WDT_TIMER_80S			BIT(5)
+#define SGM4154X_WDT_TIMER_160S			(BIT(4) | BIT(5))
+#define SGM4154X_WDT_TIMER_DISABLE		0
+
+#define SGM4154X_CHRG_CTRL_6			0x06
+#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
+#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
+#define SGM4154X_OVP_10_5V			BIT(7)
+#define SGM4154X_OVP_6_5V			BIT(6)
+#define SGM4154X_OVP_5_5V			0
+#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
+#define SGM4154X_BOOSTV				GENMASK(5, 4)
+#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
+#define SGM4154X_VINDPM_V_MIN_UV		3900000
+#define SGM4154X_VINDPM_V_MAX_UV		12000000
+#define SGM4154X_VINDPM_STEP_UV			100000
+#define SGM4154X_VINDPM_DEF_UV			4500000
+
+#define SGM4154X_CHRG_CTRL_7			0x07
+
+#define SGM4154X_CHRG_STAT		0x08
+#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
+#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
+#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
+#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
+#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
+#define SGM4154X_USB_CDP		BIT(6)
+#define SGM4154X_USB_SDP		BIT(5)
+#define SGM4154X_NOT_CHRGING		0
+#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
+#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
+#define SGM4154X_FAST_CHRG		BIT(4)
+#define SGM4154X_PRECHRG		BIT(3)
+#define SGM4154X_PG_STAT		BIT(2)
+#define SGM4154X_THERM_STAT		BIT(1)
+#define SGM4154X_VSYS_STAT		BIT(0)
+
+#define SGM4154X_CHRG_FAULT		0x09
+#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
+#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
+#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
+#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
+#define SGM4154X_TEMP_WARM		BIT(1)
+#define SGM4154X_TEMP_NORMAL		BIT(0)
+
+#define SGM4154X_CHRG_CTRL_A		0x0a
+#define SGM4154X_VBUS_GOOD		BIT(7)
+#define SGM4154X_VINDPM_INT_MASK	BIT(1)
+#define SGM4154X_IINDPM_INT_MASK	BIT(0)
+
+#define SGM4154X_CHRG_CTRL_B		0x0b
+#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
+#define SGM4154X_PN_MASK		GENMASK(6, 3)
+
+#define SGM4154X_CHRG_CTRL_C		0x0c
+
+#define SGM4154X_CHRG_CTRL_D		0x0d
+#define SGM4154X_JEITA_EN		BIT(0)
+
+#define SGM4154X_INPUT_DET		0x0e
+#define SGM4154X_DPDM_ONGOING		BIT(7)
+
+#define SGM4154X_CHRG_CTRL_F		0x0f
+#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
+
+#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
+
+struct sgm4154x_init_data {
+	int ilim;	/* input current limit */
+	int vlim;	/* minimum system voltage limit */
+	int iterm;	/* termination current */
+	int iprechg;	/* precharge current */
+	int max_ichg;	/* maximum charge current */
+	int max_vreg;	/* maximum charge voltage */
+};
+
+struct sgm4154x_state {
+	bool vsys_stat;
+	bool therm_stat;
+	bool online;
+	u8 chrg_stat;
+	bool chrg_en;
+	bool vbus_gd;
+	u8 chrg_type;
+	u8 health;
+	u8 chrg_fault;
+	u8 ntc_fault;
+};
+
+struct sgm4154x_device {
+	struct i2c_client *client;
+	struct device *dev;
+	struct power_supply *charger;
+	struct regmap *regmap;
+	char model_name[I2C_NAME_SIZE];
+	struct sgm4154x_init_data init_data;
+	struct sgm4154x_state state;
+	struct regulator_dev *otg_rdev;
+	bool watchdog_enable;
+	struct workqueue_struct *sgm_monitor_wq;
+	struct delayed_work sgm_delay_work;
+};
+
+enum SGM4154X_VINDPM_OS {
+	VINDPM_OS_3900MV,
+	VINDPM_OS_5900MV,
+	VINDPM_OS_7500MV,
+	VINDPM_OS_10500MV,
+};
+
+static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_TERMCHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set term current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
+
+	reg_val = reg_val << 4;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_PRECHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set precharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, sgm->init_data.max_ichg);
+	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_2,
+				 SGM4154X_ICHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set icharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge current error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
+
+	return val * SGM4154X_ICHRG_I_STEP_UA;
+}
+
+static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
+{
+	int reg_val;
+	int ret;
+
+	/*
+	 * Note that the value of 0x01111 represents a "special value"
+	 * corresponding to 4352000uV instead of the expected 4336000uV,
+	 * per the datasheet. All other values are as expected. So not
+	 * only do we need to clamp between max and min values, but
+	 * also clamp anything below 4352000uv to 4304000uv to prevent
+	 * overcharging.
+	 */
+	if (chrg_volt < 4352000)
+		chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, 4304000);
+	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
+	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
+	reg_val = reg_val << 3;
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VREG_V_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set charge voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge voltage error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
+
+	/*
+	 * 0x01111 is a special value meaning 4352000uV, all other
+	 * values are as expected based on the offset and step values.
+	 */
+	if (val == 0x0f)
+		return 4352000;
+
+	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
+}
+
+static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
+				       unsigned int vindpm)
+{
+	enum SGM4154X_VINDPM_OS os_val;
+	unsigned int offset;
+	u8 reg_val;
+	int ret;
+
+
+	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
+	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
+		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
+		return -EINVAL;
+	}
+
+	/*
+	 * Supported ranges per the datasheet are as follows:
+	 * 3.9v - 5.4v with a 3.9v offset
+	 * 5.9v - 7.4v with a 5.9v offset
+	 * 7.5v - 9.0v with a 7.5v offset
+	 * 10.5v - 12.0v with a 10.5v offset
+	 * Step size is a constant 100mv
+	 */
+	if (vindpm < 5900000) {
+		vindpm = clamp(vindpm, VINDPM_OS_3900MV, 5400000);
+		os_val = VINDPM_OS_3900MV;
+		offset = 3900000;
+	} else if (vindpm >= 5900000 && vindpm < 7500000) {
+		vindpm = clamp(vindpm, VINDPM_OS_5900MV, 7400000);
+		os_val = VINDPM_OS_5900MV;
+		offset = 5900000;
+	} else if (vindpm >= 7500000 && vindpm < 10500000) {
+		vindpm = clamp(vindpm, VINDPM_OS_7500MV, 9000000);
+		os_val = VINDPM_OS_7500MV;
+		offset = 7500000;
+	} else {
+		vindpm = clamp(vindpm, VINDPM_OS_10500MV, 12000000);
+		os_val = VINDPM_OS_10500MV;
+		offset = 10500000;
+	}
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_F,
+				 SGM4154X_VINDPM_OS_MASK,
+				 os_val);
+	if (ret) {
+		dev_err(sgm->dev, "set vin dpm error!\n");
+		return ret;
+	}
+
+	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VINDPM_V_MASK, reg_val);
+	if (ret)
+		dev_err(sgm->dev, "input voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
+{
+	int reg_val;
+	int ret;
+
+	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Per the datasheet, values between 100000uA and 3100000uA work
+	 * as expected with the register defined as having a step of
+	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
+	 * The register value of 0x1f however corresponds to 3800000uA not
+	 * 3200000uA as one would expect.
+	 */
+	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
+		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
+
+	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
+		iindpm = 3100000;
+
+	if (iindpm == SGM4154X_IINDPM_I_MAX_UA)
+		reg_val = 0x1f;
+	else
+		reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_0,
+				 SGM4154X_IINDPM_I_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set input current limit error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int ilim;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
+	if (ret) {
+		dev_err(sgm->dev, "get input current limit error!\n");
+		return ret;
+	}
+
+	/* Max value is not 3200000uA as expected but is 3800000uA */
+	if (SGM4154X_IINDPM_I_MASK == (ilim & SGM4154X_IINDPM_I_MASK))
+		return SGM4154X_IINDPM_I_MAX_UA;
+
+	ilim = (ilim & SGM4154X_IINDPM_I_MASK) * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
+
+	return ilim;
+}
+
+static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_WDT_RST,
+				 SGM4154X_WDT_RST);
+
+	if (ret)
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, int time)
+{
+	u8 reg_val;
+	int ret;
+
+	if (time == 0)
+		reg_val = SGM4154X_WDT_TIMER_DISABLE;
+	else if (time == 40)
+		reg_val = SGM4154X_WDT_TIMER_40S;
+	else if (time == 80)
+		reg_val = SGM4154X_WDT_TIMER_80S;
+	else
+		reg_val = SGM4154X_WDT_TIMER_160S;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_5,
+				 SGM4154X_WDT_TIMER_MASK,
+				 reg_val);
+
+	if (ret) {
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+		return ret;
+	}
+
+	if (time) {
+		if (!sgm->watchdog_enable)
+			queue_delayed_work(sgm->sgm_monitor_wq,
+					   &sgm->sgm_delay_work,
+					   msecs_to_jiffies(1000 * 5));
+		sgm->watchdog_enable = true;
+	} else {
+		sgm->watchdog_enable = false;
+		sgm4154x_watchdog_timer_reset(sgm);
+	}
+
+	return ret;
+}
+
+static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 SGM4154X_CHRG_EN);
+	if (ret)
+		dev_err(sgm->dev, "enable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 0);
+	if (ret)
+		dev_err(sgm->dev, "disable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VAC_OVP_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set vac ovp error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_recharge_volt(struct sgm4154x_device *sgm, int recharge_volt)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VRECHARGE,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set recharger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_state(struct sgm4154x_device *sgm,
+			      struct sgm4154x_state *state)
+{
+	int reg, ret;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
+		return ret;
+	}
+	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
+	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
+	state->online = !!(reg & SGM4154X_PG_STAT);
+	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
+	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
+		return ret;
+	}
+	state->chrg_fault = reg;
+	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
+	state->health = state->ntc_fault;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
+		return ret;
+	}
+	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
+
+	return ret;
+}
+
+static int sgm4154x_property_is_writeable(struct power_supply *psy,
+					  enum power_supply_property prop)
+{
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int sgm4154x_charger_set_property(struct power_supply *psy,
+					 enum power_supply_property prop,
+					 const union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			ret = sgm4154x_enable_charger(sgm);
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
+		} else {
+			sgm4154x_set_watchdog_timer(sgm, 0);
+			ret = sgm4154x_disable_charger(sgm);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sgm4154x_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm, &state);
+	if (ret) {
+		dev_err(sgm->dev, "get state error!\n");
+		return ret;
+	}
+	sgm->state = state;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		else if (!state.chrg_stat)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		switch (state.chrg_stat) {
+		case SGM4154X_PRECHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_FAST_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		case SGM4154X_TERM_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_NOT_CHRGING:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		}
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = SGM4154X_MANUFACTURER;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SGM4154X_NAME;
+		break;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = state.online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = state.vbus_gd;
+		break;
+	case POWER_SUPPLY_PROP_TYPE:
+		val->intval = POWER_SUPPLY_TYPE_USB;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		val->intval = sgm4154x_get_chrg_volt(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		val->intval = sgm4154x_get_ichrg_curr(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		val->intval = sgm->init_data.vlim;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		val->intval = sgm4154x_get_input_curr_lim(sgm);
+		if (val->intval < 0)
+			return  -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
+{
+	struct sgm4154x_device *sgm4154x = private;
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm4154x, &state);
+	if (ret) {
+		dev_err(sgm4154x->dev, "get state error!\n");
+		return IRQ_NONE;
+	}
+	sgm4154x->state = state;
+	if (state.vbus_gd) {
+		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
+			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
+			if (ret) {
+				dev_err(sgm4154x->dev, "set input current error!\n");
+				return IRQ_NONE;
+			}
+		}
+	}
+	power_supply_changed(sgm4154x->charger);
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property sgm4154x_power_supply_props[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_PRESENT
+};
+
+static char *sgm4154x_charger_supplied_to[] = {
+	"battery-monitor",
+};
+
+static struct power_supply_desc sgm4154x_power_supply_desc = {
+	.name = "sgm4154x-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = sgm4154x_power_supply_props,
+	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
+	.get_property = sgm4154x_charger_get_property,
+	.set_property = sgm4154x_charger_set_property,
+	.property_is_writeable = sgm4154x_property_is_writeable,
+};
+
+static const struct regmap_config sgm4154x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = SGM4154X_CHRG_CTRL_F,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
+				      struct device *dev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = sgm,
+					       .fwnode = dev->fwnode, };
+
+	psy_cfg.supplied_to = sgm4154x_charger_supplied_to;
+	psy_cfg.num_supplicants = ARRAY_SIZE(sgm4154x_charger_supplied_to);
+	psy_cfg.fwnode = dev->fwnode;
+	sgm->charger = devm_power_supply_register(sgm->dev,
+						  &sgm4154x_power_supply_desc,
+						  &psy_cfg);
+	if (IS_ERR(sgm->charger))
+		return PTR_ERR(sgm->charger);
+
+	return 0;
+}
+
+static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
+{
+	struct power_supply_battery_info *bat_info;
+	int ret;
+	u32 val;
+
+	/*
+	 * If unable to read devicetree info, use default/reset
+	 * values from hardware.
+	 */
+	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
+	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
+	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
+	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
+	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
+	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
+
+	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
+	if (!ret) {
+		if (bat_info->constant_charge_current_max_ua)
+			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
+		if (bat_info->constant_charge_voltage_max_uv)
+			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
+		if (bat_info->charge_term_current_ua)
+			sgm->init_data.iterm = bat_info->charge_term_current_ua;
+		if (bat_info->precharge_current_ua)
+			sgm->init_data.iprechg = bat_info->precharge_current_ua;
+
+		power_supply_put_battery_info(sgm->charger, bat_info);
+	} else
+		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-voltage-limit-microvolt",
+				       &val);
+	if (!ret)
+		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
+					    SGM4154X_VINDPM_V_MAX_UV);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-current-limit-microamp",
+				       &val);
+	if (!ret)
+		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
+					    SGM4154X_IINDPM_I_MAX_UA);
+
+	ret = sgm4154x_set_watchdog_timer(sgm, 0);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_vac_ovp(sgm);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_D,
+			   SGM4154X_JEITA_EN,
+			   0);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_IINDPM_INT_MASK,
+			   SGM4154X_IINDPM_INT_MASK);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_VINDPM_INT_MASK,
+			   SGM4154X_VINDPM_INT_MASK);
+
+	/*
+	 * Recharge voltage set to 200 by BSP driver instead of hardware
+	 * default value of 100.
+	 */
+	ret = sgm4154x_set_recharge_volt(sgm, 200);
+
+	return ret;
+}
+
+static const u32 sgm4154x_chg_otg_cur_ua[] = {
+	1200000, 2000000,
+};
+
+static const struct regulator_ops sgm4154x_vbus_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const struct regulator_desc sgm4154x_otg_rdesc = {
+	.of_match = "otg-vbus",
+	.name = "otg-vbus",
+	.regulators_node = of_match_ptr("regulators"),
+	.ops = &sgm4154x_vbus_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4850000,
+	.uV_step = 150000,
+	.n_voltages = 4,
+	.vsel_reg = SGM4154X_CHRG_CTRL_6,
+	.vsel_mask = SGM4154X_BOOSTV,
+	.enable_reg = SGM4154X_CHRG_CTRL_1,
+	.enable_mask = SGM4154X_OTG_EN,
+	.curr_table = sgm4154x_chg_otg_cur_ua,
+	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
+	.csel_reg = SGM4154X_CHRG_CTRL_2,
+	.csel_mask = SGM4154X_BOOST_LIM,
+};
+
+static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
+{
+	struct regulator_config config = {
+		.dev = sgm->dev,
+		.regmap = sgm->regmap,
+		.driver_data = sgm,
+	};
+
+	sgm->otg_rdev = devm_regulator_register(sgm->dev,
+						&sgm4154x_otg_rdesc,
+						&config);
+
+	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
+}
+
+static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
+	if (ret)
+		return ret;
+
+	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
+		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
+
+	return 0;
+}
+
+static void sgm_charger_work(struct work_struct *work)
+{
+	struct sgm4154x_device *sgm =
+		container_of(work,
+			     struct sgm4154x_device,
+			     sgm_delay_work.work);
+
+	sgm4154x_watchdog_timer_reset(sgm);
+	if (sgm->watchdog_enable)
+		queue_delayed_work(sgm->sgm_monitor_wq,
+				   &sgm->sgm_delay_work,
+				   msecs_to_jiffies(1000 * 5));
+}
+
+static int sgm4154x_probe(struct i2c_client *client)
+{
+	const struct i2c_device_id *id = i2c_client_get_device_id(client);
+	struct device *dev = &client->dev;
+	struct sgm4154x_device *sgm;
+	int ret;
+
+	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
+	if (!sgm)
+		return -ENOMEM;
+
+	sgm->client = client;
+	sgm->dev = dev;
+
+	strscpy(sgm->model_name, id->name, I2C_NAME_SIZE);
+
+	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
+	if (IS_ERR(sgm->regmap))
+		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
+				     "Failed to allocate register map\n");
+
+	i2c_set_clientdata(client, sgm);
+
+	ret = sgm4154x_hw_chipid_detect(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to read HW ID\n");
+
+	device_init_wakeup(dev, 1);
+
+	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "%s",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE, "sgm-monitor-wq");
+	if (!sgm->sgm_monitor_wq)
+		return -EINVAL;
+
+	ret = devm_delayed_work_autocancel(dev, &sgm->sgm_delay_work,
+					   sgm_charger_work);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to register delayed work\n");
+
+	ret = sgm4154x_power_supply_init(sgm, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register power supply\n");
+
+	ret = sgm4154x_hw_init(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						sgm4154x_irq_handler_thread,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						"sgm41542-irq", sgm);
+		if (ret)
+			return ret;
+
+		enable_irq_wake(client->irq);
+	}
+
+	ret = sgm4154x_vbus_regulator_register(sgm);
+	if (ret) {
+		disable_irq_wake(client->irq);
+		return dev_err_probe(dev, ret,
+				     "Unable to register VBUS regulator\n");
+	}
+
+	return 0;
+}
+
+static void sgm4154x_charger_shutdown(struct i2c_client *client)
+{
+	struct sgm4154x_device *sgm = i2c_get_clientdata(client);
+
+	sgm4154x_set_prechrg_curr(sgm, SGM4154X_PRECHRG_I_DEF_UA);
+	sgm4154x_disable_charger(sgm);
+}
+
+static void sgm4154x_charger_remove(struct i2c_client *client)
+{
+	disable_irq_wake(client->irq);
+}
+
+static const struct i2c_device_id sgm4154x_i2c_ids[] = {
+	{ "sgm41542" },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
+
+static const struct of_device_id sgm4154x_of_match[] = {
+	{ .compatible = "sgmicro,sgm41542", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
+
+static struct i2c_driver sgm4154x_driver = {
+	.driver = {
+		.name = "sgm4154x-charger",
+		.of_match_table = sgm4154x_of_match,
+	},
+	.probe = sgm4154x_probe,
+	.shutdown = sgm4154x_charger_shutdown,
+	.remove = sgm4154x_charger_remove,
+	.id_table = sgm4154x_i2c_ids,
+};
+
+module_i2c_driver(sgm4154x_driver);
+
+MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
+MODULE_DESCRIPTION("sgm4154x charger driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:07:58 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:07:58 -0500
Subject: [PATCH V5 3/6] dt-bindings: display: panel: Add Anbernic TD4310 panel
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
new file mode 100644
index 000000000000..6f7f92b9c860
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Anbernic TD4310 Based Panels
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+
+description:
+  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
+  (a 1080x1920 5.5 inch panel).
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - anbernic,panel-vita-pro
+      - const: anbernic,td4310
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: Panel power supply
+
+required:
+  - compatible
+  - port
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel at 0 {
+            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+            reg = <0>;
+            backlight = <&backlight>;
+            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+            rotation = <270>;
+            vdd-supply = <&vdd_lcd>;
+
+            port {
+                panel_in: endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:07:59 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:07:59 -0500
Subject: [PATCH V5 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c | 256 ++++++++++++++++++
 3 files changed, 267 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d592f4f4b939..61dd00297ecc 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
 	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
 	  and RG-99 handheld gaming consoles.
 
+config DRM_PANEL_ANBERNIC_TD4310
+	tristate "Anbernic TD4310 LCD panel"
+	depends on GPIOLIB && OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here to enable support for Anbernic designed panels with the
+	  TD4310 panel controller such as the ones used on the Anbernic RG
+	  Vita Pro.
+
 config DRM_PANEL_ARM_VERSATILE
 	tristate "ARM Versatile panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a4291dc3905b..9d8f70c9de3e 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
 obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
new file mode 100644
index 000000000000..84963671e3f9
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Anbernic panels with TD4310 panel controller.
+ *
+ * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/mipi_display.h>
+
+struct anbernic_panel_td4310_info {
+	const struct drm_display_mode *display_mode;
+	u16 width_mm;
+	u16 height_mm;
+	u32 bus_flags;
+	unsigned long mode_flags;
+	u32 format;
+	u32 lanes;
+	u16 prepare_delay;
+	u16 reset_delay;
+	u16 init_delay;
+	u16 enable_delay;
+	u16 disable_delay;
+	u16 unprepare_delay;
+};
+
+struct anbernic_panel_td4310 {
+	struct device *dev;
+	struct mipi_dsi_device *dsi;
+	struct drm_panel panel;
+	const struct anbernic_panel_td4310_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	struct regulator *vdd;
+	enum drm_panel_orientation orientation;
+};
+
+static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
+{
+	return container_of(panel, struct anbernic_panel_td4310, panel);
+}
+
+static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+	int ret;
+
+	ret = regulator_enable(ctx->vdd);
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+	if (ret)
+		goto err_enable;
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	mipi_dsi_msleep(&dsi_ctx, 10);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	if (ret)
+		goto err_reset;
+	if (ctx->panel_info->reset_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	if (ret)
+		goto err_reset;
+
+	if (ctx->panel_info->enable_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+
+	if (dsi_ctx.accum_err) {
+		ret = dsi_ctx.accum_err;
+		goto err_reset;
+	}
+
+	return 0;
+
+err_reset:
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+err_enable:
+	regulator_disable(ctx->vdd);
+	return ret;
+}
+
+static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->unprepare_delay);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->disable_delay);
+
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	regulator_disable(ctx->vdd);
+
+	return 0;
+}
+
+static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
+				    struct drm_connector *connector)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
+
+	connector->display_info.bpc = 8;
+	connector->display_info.width_mm = panel_info->width_mm;
+	connector->display_info.height_mm = panel_info->height_mm;
+	connector->display_info.bus_flags = panel_info->bus_flags;
+
+	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
+}
+
+static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+
+	return ctx->orientation;
+}
+
+static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
+	.prepare = panel_anbernic_td4310_prepare,
+	.unprepare = panel_anbernic_td4310_unprepare,
+	.get_modes = panel_anbernic_td4310_get_mode,
+	.get_orientation = panel_anbernic_td4310_get_orientation,
+};
+
+static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct anbernic_panel_td4310 *ctx;
+	int ret;
+
+	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
+				   &panel_anbernic_td4310_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ctx->dev = dev;
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	if (!ctx->panel_info)
+		return -EINVAL;
+
+	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Cannot get reset gpio\n");
+
+	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+				     "Cannot get enable gpio\n");
+
+	ctx->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(ctx->vdd))
+		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
+				     "Failed to request vdd regulator\n");
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	dsi->lanes = ctx->panel_info->lanes;
+	dsi->format = ctx->panel_info->format;
+	dsi->mode_flags = ctx->panel_info->mode_flags;
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	devm_drm_panel_add(dev, &ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+
+	return 0;
+}
+
+static const struct drm_display_mode anbernic_vitapro_mode = {
+	.clock = 140020,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 50,
+	.hsync_end = 1080 + 50 + 4,
+	.htotal = 1080 + 50 + 4 + 50,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 15,
+	.vsync_end = 1920 + 15 + 4,
+	.vtotal = 1920 + 15 + 4 + 32,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
+	.display_mode = &anbernic_vitapro_mode,
+	.width_mm = 69,
+	.height_mm = 121,
+	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
+		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+	.prepare_delay = 50,
+	.reset_delay = 220,
+	.enable_delay = 120,
+	.disable_delay = 50,
+	.unprepare_delay = 20,
+};
+
+static const struct of_device_id panel_anbernic_td4310_of_match[] = {
+	{
+		.compatible = "anbernic,panel-vita-pro",
+		.data = &anbernic_vitapro_info,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
+
+static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
+	.driver = {
+		.name = "panel-anbernic-td4310",
+		.of_match_table = panel_anbernic_td4310_of_match,
+	},
+	.probe	= panel_anbernic_td4310_probe,
+};
+module_mipi_dsi_driver(anbernic_panel_td4310_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:08:00 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:08:00 -0500
Subject: [PATCH V5 5/6] dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add compatible string for the Anbernic RG Vita-Pro.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b8babe9d3a26 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -66,6 +66,12 @@ properties:
               - anbernic,rg-ds
           - const: rockchip,rk3568
 
+      - description: Anbernic RK3576 Handheld Gaming Console
+        items:
+          - enum:
+              - anbernic,rg-vita-pro
+          - const: rockchip,rk3576
+
       - description: Ariaboard Photonicat
         items:
           - const: ariaboard,photonicat
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun  4 15:08:01 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu,  4 Jun 2026 17:08:01 -0500
Subject: [PATCH V5 6/6] arm64: dts: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260604220802.119107-1-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
Message-ID: <20260604220802.119107-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add device tree for the Anbernic RG Vita-Pro, based on the Rockchip
RK3576. All hardware is currently working except for the accelerometer,
the touchscreen, the battery monitor, and DisplayPort over USB-C. PWM
is also missing currently, and as a result the LEDs and panel backlight
are currently controlled via GPIO but will be changed to PWM once
supported.

The Anbernic RG Vita-Pro includes the following hardware:
 - A 1080x1920 DSI display with touch.
 - 21 buttons.
 - 2 Analog joysticks controlled via userspace.
 - 3 LEDs.
 - 64GB eMMC, 2 SDMMC slots.
 - RTL8852BE WiFi (with Bluetooth via UART)
 - 1 USB 3.0 USB-C port in OTG mode.
 - 3.5mm headphone jack with play button support.
 - 5000mAH battery

The following hardware has incomplete driver support and is not yet
working:
 - An Invensense icm42607p accelerometer.
 - A Cellwise cw221x battery monitor.
 - A Synaptics i2c touchscreen.
 - DisplayPort over USB-C alt-mode.
 - PWM controller.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 2 files changed, 1328 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..7d86676f98e8 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-100ask-dshanpi-a1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-anbernic-rg-vita-pro.dtb
 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
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
new file mode 100644
index 000000000000..344ba1870533
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2026 Chris Morgan <macromorgan at hotmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+
+#include "rk3576.dtsi"
+
+/ {
+	model = "Anbernic RG Vita Pro";
+	chassis-type = "handset";
+	compatible = "anbernic,rg-vita-pro", "rockchip,rk3576";
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	adc_keys_home: adc-keys-home {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 1>;
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <60>;
+
+		button-home {
+			label = "HOME";
+			linux,code = <KEY_HOME>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	adc_keys_play: adc-keys-play {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 3>;
+		keyup-threshold-microvolt = <1300000>;
+		poll-interval = <60>;
+
+		button-play {
+			label = "PLAY";
+			linux,code = <KEY_PLAYPAUSE>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	/*
+	 * Battery values from BSP except for the following:
+	 *
+	 * factory-internal-resistance-micro-ohms - This was set to 80 which
+	 * is likely incorrect and changed to 80000.
+	 *
+	 * charge-full-design-microamp-hours - Was set to 8000000 but the
+	 * physical battery says 5000000.
+	 *
+	 * constant-charge-current-max-microamp - Was set to 10000000 which
+	 * both seems high and exceeds what the charger hardware can do.
+	 * Setting to 3800000 which is the maximum input current the charger
+	 * can handle.
+	 */
+	battery: battery {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <5000000>;
+		charge-term-current-microamp = <300000>;
+		constant-charge-current-max-microamp = <3800000>;
+		constant-charge-voltage-max-microvolt = <4350000>;
+		factory-internal-resistance-micro-ohms = <80000>;
+		precharge-current-microamp = <180000>;
+		precharge-upper-limit-microvolt = <3600000>;
+		voltage-max-design-microvolt = <4350000>;
+		voltage-min-design-microvolt = <3000000>;
+	};
+
+	hp_amp: audio-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&hp_amp_enable_h>;
+		pinctrl-names = "default";
+		sound-name-prefix = "Headphone Amp";
+	};
+
+	/*
+	 * LEDs and Backlights can be controlled as a PWM, but PWM
+	 * driver is not yet available.
+	 */
+	gpio_backlight: backlight {
+		compatible = "gpio-backlight";
+		gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&led_backlight_h>;
+		pinctrl-names = "default";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_amber_h>, <&led_green_h>, <&led_red_h>;
+		pinctrl-names = "default";
+
+		charging-led {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_CHARGING;
+			gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
+		};
+
+		full-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
+		};
+
+		bat-low-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_ALARM;
+			gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio_keys_control: gpio-keys-control {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&gamepad_keys_l>;
+		pinctrl-names = "default";
+
+		button-a {
+			gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
+			label = "EAST";
+			linux,code = <BTN_EAST>;
+		};
+
+		button-b {
+			gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+			label = "SOUTH";
+			linux,code = <BTN_SOUTH>;
+		};
+
+		button-down {
+			gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+			label = "DPAD-DOWN";
+			linux,code = <BTN_DPAD_DOWN>;
+		};
+
+		button-l1 {
+			gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>;
+			label = "TL";
+			linux,code = <BTN_TL>;
+		};
+
+		button-l2 {
+			gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+			label = "TL2";
+			linux,code = <BTN_TL2>;
+		};
+
+		button-left {
+			gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+			label = "DPAD-LEFT";
+			linux,code = <BTN_DPAD_LEFT>;
+		};
+
+		button-menu {
+			gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+			label = "MENU";
+			linux,code = <BTN_MODE>;
+		};
+
+		button-right {
+			gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+			label = "DPAD-RIGHT";
+			linux,code = <BTN_DPAD_RIGHT>;
+		};
+
+		button-r1 {
+			gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+			label = "T2";
+			linux,code = <BTN_TR>;
+		};
+
+		button-r2 {
+			gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+			label = "TR2";
+			linux,code = <BTN_TR2>;
+		};
+
+		button-select {
+			gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>;
+			label = "SELECT";
+			linux,code = <BTN_SELECT>;
+		};
+
+		button-start {
+			gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>;
+			label = "START";
+			linux,code = <BTN_START>;
+		};
+
+		button-thumbl {
+			gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+			label = "THUMBL";
+			linux,code = <BTN_THUMBL>;
+		};
+
+		button-thumbr {
+			gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>;
+			label = "THUMBR";
+			linux,code = <BTN_THUMBR>;
+		};
+
+		button-up {
+			gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+			label = "DPAD-UP";
+			linux,code = <BTN_DPAD_UP>;
+		};
+
+		button-x {
+			gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+			label = "NORTH";
+			linux,code = <BTN_NORTH>;
+		};
+
+		button-y {
+			gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+			label = "WEST";
+			linux,code = <BTN_WEST>;
+		};
+	};
+
+	gpio_keys_volume: gpio-keys-volume {
+		compatible = "gpio-keys";
+		autorepeat;
+		pinctrl-0 = <&vol_keys_l>;
+		pinctrl-names = "default";
+
+		vol-down-key {
+			gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEDOWN";
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+
+		vol-up-key {
+			gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEUP";
+			linux,code = <KEY_VOLUMEUP>;
+		};
+	};
+
+	hdmi-con {
+		compatible = "hdmi-connector";
+		type = "c";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_h>;
+		radio-type = "wlan";
+		shutdown-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+
+	sound: sound {
+		compatible = "simple-audio-card";
+		pinctrl-0 = <&hp_det>;
+		pinctrl-names = "default";
+		simple-audio-card,aux-devs = <&aw87391_pa_l>, <&aw87391_pa_r>,
+					     <&hp_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "rockchip,es8388-codec";
+		simple-audio-card,pin-switches = "Headphones", "Internal Speakers";
+		simple-audio-card,routing =
+			"LINPUT1", "Mic Jack",
+			"LINPUT2", "Mic Jack",
+			"RINPUT1", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone",
+			"Headphones", "Headphone Amp OUTL",
+			"Headphones", "Headphone Amp OUTR",
+			"Headphone Amp INL", "LOUT1",
+			"Headphone Amp INR", "ROUT1",
+			"Internal Speakers", "Left Amp OUT",
+			"Internal Speakers", "Right Amp OUT",
+			"Left Amp IN", "LOUT2",
+			"Right Amp IN", "ROUT2";
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Internal Speakers";
+		status = "okay";
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1100000>;
+		regulator-min-microvolt = <1100000>;
+		regulator-name = "vcc_1v1_nldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <2000000>;
+		regulator-min-microvolt = <2000000>;
+		regulator-name = "vcc_2v0_pldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_3v8_sys: regulator-vcc-3v8-sys {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <3800000>;
+		regulator-min-microvolt = <3800000>;
+		regulator-name = "vcc_3v8_sys";
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_3v3_sd_s0_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc_sdio: regulator-vcc-sdio {
+		compatible = "regulator-gpio";
+		regulator-name = "vcc_sdio";
+		gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_sdio_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <1800000>;
+		states = <1800000 0>, <3300000 1>;
+	};
+
+	vcc_wifi: regulator-vcc-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_wifi";
+		enable-active-high;
+		gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_wifi_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vdd_lcd: regulator-vdd-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_lcd";
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vdd_lcd_h>;
+		pinctrl-names = "default";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&dsi {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	panel: panel at 0 {
+		compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+		reg = <0>;
+		backlight = <&gpio_backlight>;
+		enable-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable>, <&lcd_rst>;
+		reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
+		rotation = <270>;
+		vdd-supply = <&vdd_lcd>;
+
+		port {
+			mipi_in_panel: endpoint {
+				remote-endpoint = <&mipi_out_panel>;
+			};
+		};
+	};
+};
+
+&dsi_in {
+	dsi_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dsi>;
+	};
+};
+
+&dsi_out {
+	mipi_out_panel: endpoint {
+		remote-endpoint = <&mipi_in_panel>;
+	};
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&hdmi_sound {
+	status = "okay";
+};
+
+&hdptxphy {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m1_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	/* synaptics,dsx-i2c touchscreen at 0x70 */
+};
+
+&i2c1 {
+	status = "okay";
+
+	pmic at 23 {
+		compatible = "rockchip,rk806";
+		reg = <0x23>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins
+			     &rk806_dvs1_null
+			     &rk806_dvs2_null
+			     &rk806_dvs3_null>;
+		system-power-controller;
+		vcc1-supply = <&vcc_3v8_sys>;
+		vcc2-supply = <&vcc_3v8_sys>;
+		vcc3-supply = <&vcc_3v8_sys>;
+		vcc4-supply = <&vcc_3v8_sys>;
+		vcc5-supply = <&vcc_3v8_sys>;
+		vcc6-supply = <&vcc_3v8_sys>;
+		vcc7-supply = <&vcc_3v8_sys>;
+		vcc8-supply = <&vcc_3v8_sys>;
+		vcc9-supply = <&vcc_3v8_sys>;
+		vcc10-supply = <&vcc_3v8_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc_3v8_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc_3v8_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_pwrdn: dvs1-pwrdn-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: dvs1-rst-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs1_slp: dvs1-slp-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_dvs: dvs2-dvs-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: dvs2-gpio-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_pwrdn: dvs2-pwrdn-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: dvs2-rst-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_slp: dvs2-slp-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_dvs: dvs3-dvs-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: dvs3-gpio-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_pwrdn: dvs3-pwrdn-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: dvs3-rst-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_slp: dvs3-slp-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		regulators {
+			vdd_cpu_big_s0: dcdc-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_big_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_npu_s0: dcdc-reg2 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_npu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vdd_gpu_s0: dcdc-reg5 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_logic_s0: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <800000>;
+				regulator-name = "vdd_logic_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdd_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo2_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdda_1v2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcca_3v3_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo6_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdda_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_ddr_pll_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v75_hdmi_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda0v75_hdmi_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_0v85_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda_0v75_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	/* inv,icm42607 IMU at 0x68 */
+};
+
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		assigned-clock-rates = <12288000>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		DVDD-supply = <&vcc_3v3_s3>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		pinctrl-0 = <&sai1m0_mclk>;
+		pinctrl-names = "default";
+		PVDD-supply = <&vcc_3v3_s3>;
+		#sound-dai-cells = <0>;
+	};
+
+	aw87391_pa_l: audio-codec at 58 {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x58>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Left Amp";
+	};
+
+	aw87391_pa_r: audio-codec at 5b {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x5b>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Right Amp";
+	};
+};
+
+&i2c6 {
+	pinctrl-0 = <&i2c6m3_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	sgm41542: charger at 3b {
+		compatible = "sgmicro,sgm41542";
+		reg = <0x3b>;
+		input-current-limit-microamp = <3000000>;
+		input-voltage-limit-microvolt = <4500000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-0 = <&charger_irq>;
+		pinctrl-names = "default";
+		monitored-battery = <&battery>;
+		status = "okay";
+
+		regulators {
+			vbus5v0_typec: otg-vbus {
+				regulator-name = "vbus5v0_typec";
+				regulator-max-microvolt = <5000000>;
+				regulator-min-microvolt = <5000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+
+	/* Unused iSmartWare SW2001 encryption device at 0x3c */
+
+	husb311: typec-portc at 4e {
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD1 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&usbc_int>;
+		pinctrl-names = "default";
+		status = "okay";
+		vbus-supply = <&vbus5v0_typec>;
+
+		connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			op-sink-microwatt = <10000000>;
+			power-role = "dual";
+			try-power-role  = "sink";
+
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_FIXED(9000, 2000, PDO_FIXED_USB_COMM)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs_ep: endpoint {
+						remote-endpoint = <&usb_drd0_hs_ep>;
+					};
+				};
+				port at 1 {
+					reg = <1>;
+					usbc0_ss_ep: endpoint {
+						remote-endpoint = <&usb_drd0_ss_ep>;
+					};
+				};
+				port at 2 {
+					reg = <2>;
+					usbc0_dp_ep: endpoint {
+						remote-endpoint = <&usbdp_phy_ep>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hym8563_int>;
+		wakeup-source;
+	};
+
+	/* cellwise,cw221X battery manager at 0x64 */
+};
+
+&mipidcphy {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_perstn>;
+	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_wifi>;
+	status = "okay";
+};
+
+&pinctrl {
+	audio {
+		hp_amp_enable_h: hp-amp-enable {
+			rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_det: hp-det {
+			rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	bluetooth {
+		bt_reset_gpio: bt-reset-pin {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_gpio: bt-wake-pin {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_host_irq: bt-wake-host-irq {
+			rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	charger {
+		charger_irq: charger-irq {
+			rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	display {
+		lcd_enable: lcd-enable {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		lcd_rst: lcd-rst {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	gpio-keys {
+		vol_keys_l: vol-keys_l {
+			rockchip,pins =
+				<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		gamepad_keys_l: gamepad-keys-l {
+			rockchip,pins =
+				<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	gpio-leds {
+		led_amber_h: led-amber-h {
+			rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_backlight_h: led-backlight-h {
+			rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_green_h: led-green-h {
+			rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_red_h: led-red-h {
+			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie0_perstn: pcie0-perstn {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	regulator {
+		vcc_3v3_sd_s0_h: vcc-3v3-sd-s0-h {
+			rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_sdio_h: vcc-sdio-h {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_wifi_h: vcc-wifi-h {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vdd_lcd_h: vdd-lcd-h {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtc {
+		hym8563_int: hym8563-int {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	touch {
+		touch_int: touch-int {
+			rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		usbc_int: usbc-int {
+			rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		usbc0_sbu1: usbc0-sbu1 {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		usbc0_sbu2: usbc0-sbu2 {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	wifi {
+		wifi_en_h: wifi-en-h {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sai1 {
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai6 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
+&sdio {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&sdmmc1m0_bus4>, <&sdmmc1m0_clk>,
+		    <&sdmmc1m0_cmd>, <&sdmmc1m0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vcc_sdio>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	no-sd;
+	no-sdio;
+	non-removable;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>,
+		    <&sdmmc0_cmd>, <&sdmmc0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi1 {
+	num-cs = <1>;
+	pinctrl-0 = <&spi1m2_pins>, <&spi1m2_csn0>;
+	status = "okay";
+
+	/* SPI controlled MCU for joystick and joystick LEDs. */
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_dsi: endpoint at ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi_in_vp1>;
+	};
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m1_xfer>, <&uart6m1_ctsn>, <&uart6m1_rtsn>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "realtek,rtl8822cs-bt";
+		device-wake-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		host-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&bt_reset_gpio>, <&bt_wake_gpio>, <&bt_wake_host_irq>;
+		pinctrl-names = "default";
+	};
+};
+
+&usbdp_phy {
+	mode-switch;
+	orientation-switch;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbc0_sbu1 &usbc0_sbu2>;
+	sbu1-dc-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		usbdp_phy_ep: endpoint {
+			remote-endpoint = <&usbc0_dp_ep>;
+		};
+	};
+};
+
+&usb_drd0_dwc3 {
+	usb-role-switch;
+	dr_mode = "otg";
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_drd0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_drd0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss_ep>;
+			};
+		};
+	};
+};
-- 
2.43.0



From chaoyi.chen at rock-chips.com  Thu Jun  4 18:36:28 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Fri, 5 Jun 2026 09:36:28 +0800
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <20260604135255.62682-1-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
Message-ID: <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>

Hello Midgy,

On 6/4/2026 9:52 PM, Midgy BALON wrote:
> RFC, not for merge. End-to-end inference does not produce correct output
> yet (see Status), so per the v2 discussion this is a request for design
> feedback. It now probes, attaches, and submits cleanly on a stock
> v7.1-rc6 tree; what remains is one hardware-internal issue.
> 
> The RK3568 has a single NVDLA-derived NPU core, the same IP family as the
> RK3588 NPU the driver already supports; the register layout matches. The
> RK3568 differences are a 32-bit NPU AXI/IOMMU (vs 40-bit) and explicit
> PVTPLL/PMU bring-up to power and de-idle the NPU before it is reachable.
> 
> Patches:
>   1-2  rocket: per-SoC data struct, then derive DMA width and core count
>        from match data (refactors, no functional change).
>   3    rocket: RK3568 SoC data + PVTPLL/PMU/NOC bring-up.
>   4    rocket: reset the NPU before detaching the IOMMU on a job timeout
>        (the detach otherwise stalls a wedged AXI master and WARNs).
>   5    rocket: keep the IOMMU domain attached across jobs instead of
>        re-attaching per job (the per-job rk_iommu handshake on the idle
>        NPU MMU is slow and noisy).
>   6    iommu/rockchip: clear AUTO_GATING bit 1 on the RK356x v1 IOMMU so
>        the page-walker keeps its clock (else a TLB-miss walk never
>        completes).
>   7    dt-bindings: add the RK3568 NPU compatible.
>   8-9  arm64 dts: add the NPU and its IOMMU, and enable them on ROCK 3B.
> 
> Dependency. The NPU MMU is rockchip-iommu v1 (32-bit) while the rest of
> the RK3568 uses v2 (40-bit). They cannot coexist until the driver carries
> per-device ops; this series is developed on top of Simon Xue's
> "iommu/rockchip: Drop global rk_ops in favor of per-device ops" [1].
> Without it the NPU IOMMU fails to probe on a full RK3568 boot.
>

Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than
v1, implying it should support 40-bit PAs. Nevertheless, please note that
the upper limit for DTE is 32 bits.

> Power bring-up. The NPU is brought up through the power-domain layer (no
> driver hack): the NPU power-domain keeps its clocks but drops the pm_qos
> phandle (qos_npu sits behind the gated NPU NoC, so genpd's power-off QoS
> save faults reading it), and vdd_npu is marked always-on so the rail is
> up before genpd de-idles the NoC at power-on. The PMU de-idle then ACKs
> without PVTPLL running; PVTPLL is only needed for compute.
>

Can these operations not be completed via the pmdomain driver?
If some operations are controlled by TF-A, are you using open
source TF-A? Thank you.

> Status. On v7.1-rc6 the driver probes, creates /dev/accel/accel0,
> attaches an IOMMU domain, and submits jobs; the program controller
> fetches and broadcasts the command list. Inference output is still wrong,
> and the cause is split across three layers:
>   - kernel (this series): the RK3568 differences appear handled;
>   - mesa/Teflon userspace: still emits RK3588-tuned config, wrong for
>     RK3568 (to be filed separately on mesa-dev);
>   - hardware: with corrected config the NPU's DMA reads the full input
>     and weight tensors (confirmed via its DMA bandwidth counters), but
>     the MAC/output stage never completes, the job times out, and the
>     output stays at the buffer's zero-point. I have not found the missing
>     step; it is not in the command list (replaying the vendor's
>     byte-exact command list behaves the same). Pointers welcome,
>     especially from anyone with RK3568 NPU experience.
> 
> Known residual. On the first IOMMU attach the NPU MMU is idle with paging
> already enabled; the rk_iommu stall/reset handshake does not complete in
> that state and logs one burst of timeouts before the (kept) domain
> settles. It is harmless here because the job times out regardless, but it
> points at an idle-MMU reconfiguration corner the rk_iommu code does not
> handle on this block.
> 
> [1] https://lore.kernel.org/linux-rockchip/20260310105303.128859-1-xxm at rock-chips.com/
> 
> Changes since v2:
>   - Tagged RFC; now tested on a stock v7.1-rc6 tree.
>   - Bring-up moved into the power-domain/DT layer (no initcall hack).
>   - Added the IOMMU detach-on-timeout and attach-once driver fixes.
>   - Split the driver patch (Heiko): soc_data / match-data / RK3568.
>   - Derive DMA width and core count from match data; drop the DT rescans.
>   - Binding describes the hardware; added the missing $ref on rockchip,pmu.
>   - Disclosed the per-device-ops IOMMU dependency.
> 
> Midgy BALON (9):
>   accel: rocket: Introduce per-SoC rocket_soc_data
>   accel: rocket: Derive DMA width and core count from match data
>   accel: rocket: Add RK3568 SoC support
>   accel: rocket: Reset the NPU before detaching the IOMMU on timeout
>   accel: rocket: Keep the IOMMU domain attached across jobs
>   iommu/rockchip: Clear AUTO_GATING bit 1 on the RK356x v1 IOMMU
>   dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
>   arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
>   arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU
> 
>  .../npu/rockchip,rk3588-rknn-core.yaml        | 18 ++++-
>  .../boot/dts/rockchip/rk3568-rock-3b.dts      | 14 +++-
>  arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++
>  drivers/accel/rocket/rocket_core.c            | 22 ++++++-
>  drivers/accel/rocket/rocket_core.h            | 19 ++++++
>  drivers/accel/rocket/rocket_device.c          | 15 ++---
>  drivers/accel/rocket/rocket_device.h          |  3 +-
>  drivers/accel/rocket/rocket_drv.c             | 66 ++++++++++++++++++-
>  drivers/accel/rocket/rocket_job.c             | 35 ++++++++--
>  drivers/iommu/rockchip-iommu.c                | 12 ++++
>  10 files changed, 219 insertions(+), 23 deletions(-)
> 
> 
> base-commit: 52c800fdcf11888ebeb50c3d707f782cc15b66eb

-- 
Best, 
Chaoyi


From chaoyi.chen at rock-chips.com  Thu Jun  4 18:59:24 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Fri, 5 Jun 2026 09:59:24 +0800
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the
 RK356x v1 IOMMU
In-Reply-To: <20260604135255.62682-7-midgy971@gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <20260604135255.62682-7-midgy971@gmail.com>
Message-ID: <e44b506e-e9d2-48e3-acea-ab28b7be9b37@rock-chips.com>

Hello Midgy,

On 6/4/2026 9:52 PM, Midgy BALON wrote:
> On the RK356x v1 IOMMU, RK_MMU_AUTO_GATING resets to 0x3. Bit 1 enables
> auto clock-gating of the page-table walker, so the walker's AXI master
> loses its clock between transactions; a TLB-miss page walk then never
> completes and the IOMMU is left stuck (PAGING_ENABLED, never IDLE).
> 
> Clear bit 1 (keeping bit 0, the slave-port gate) once paging is enabled
> so the walker keeps its clock. This is required for the RK3568 NPU MMU.
> 
> Signed-off-by: Midgy BALON <midgy971 at gmail.com>
> ---
>  drivers/iommu/rockchip-iommu.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 4da80136933c4..e3d8b6e9ca12b 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -953,6 +953,18 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
>  
>  	ret = rk_iommu_enable_paging(iommu);
>  
> +	if (!ret) {
> +		/*
> +		 * RK356x v1 IOMMU: RK_MMU_AUTO_GATING bit 1 enables page-walker
> +		 * auto clock-gating; the walker's AXI master then loses its clock
> +		 * between transactions and a TLB-miss page walk never completes,
> +		 * leaving the IOMMU stuck (PAGING_ENABLED, never IDLE).  Clear
> +		 * bit 1 (keep bit 0, the slave-port gate) once paging is enabled.
> +		 */
> +		for (i = 0; i < iommu->num_mmu; i++)
> +			rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, 0x2);
> +	}
> +
>  out_disable_stall:
>  	rk_iommu_disable_stall(iommu);
>  out_disable_clocks:

As I said, it is v2. Could you please try using the code below
instead and see if it works? Thank you.

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 0013cf196c57..89e3a83a0251 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -930,6 +930,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
        struct iommu_domain *domain = iommu->domain;
        struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
        int ret, i;
+       u32 auto_gate;
 
        ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
        if (ret)
@@ -948,6 +949,10 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
                               rk_ops->mk_dtentries(rk_domain->dt_dma));
                rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
                rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
+
+               auto_gate = rk_iommu_read(iommu->bases[i], RK_MMU_AUTO_GATING);
+               auto_gate |= BIT(31);
+               rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, auto_gate);
        }
 
        ret = rk_iommu_enable_paging(iommu);

-- 
Best, 
Chaoyi


From damon.ding at rock-chips.com  Thu Jun  4 19:23:03 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Fri,  5 Jun 2026 10:23:03 +0800
Subject: [PATCH v11 1/3] arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
In-Reply-To: <20260605022305.3058853-1-damon.ding@rock-chips.com>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
Message-ID: <20260605022305.3058853-2-damon.ding@rock-chips.com>

Add the required HCLK_VO1 bus clock to RK3588 eDP0 node with
corresponding clock-name "hclk". This clock is necessary for the
eDP controller to access video output GRF and work properly.

Previously the clock was enabled implicitly via GRF phandle
reference. Add it explicitly now to align with updated binding.

Fixes: dc79d3d5e7c7 ("arm64: dts: rockchip: Add eDP0 node for RK3588")
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>

---

Changes in v4:
- Modify the commit msg.
---
 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 4fb8888c281c..24a5ccbac08c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1712,8 +1712,8 @@ hdmi0_out: port at 1 {
 	edp0: edp at fdec0000 {
 		compatible = "rockchip,rk3588-edp";
 		reg = <0x0 0xfdec0000 0x0 0x1000>;
-		clocks = <&cru CLK_EDP0_24M>, <&cru PCLK_EDP0>;
-		clock-names = "dp", "pclk";
+		clocks = <&cru CLK_EDP0_24M>, <&cru PCLK_EDP0>, <&cru HCLK_VO1>;
+		clock-names = "dp", "pclk", "hclk";
 		interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH 0>;
 		phys = <&hdptxphy0>;
 		phy-names = "dp";
-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 19:23:02 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Fri,  5 Jun 2026 10:23:02 +0800
Subject: [PATCH v11 0/3] Add eDP support for RK3576
Message-ID: <20260605022305.3058853-1-damon.ding@rock-chips.com>

Picked from:
https://lore.kernel.org/all/20260601065100.1103873-1-damon.ding at rock-chips.com/

Patch 1-2 are to add missing clock "hclk" for RK3588 eDP nodes.
Patch 3 is to add the RK3576 eDP node.

Damon Ding (3):
  arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
  arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
  arm64: dts: rockchip: Add eDP node for RK3576

 arch/arm64/boot/dts/rockchip/rk3576.dtsi      | 28 +++++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  4 +--
 .../arm64/boot/dts/rockchip/rk3588-extra.dtsi |  4 +--
 3 files changed, 32 insertions(+), 4 deletions(-)

---

Changes in v2:
- Split out separate patches to add the "hclk" clock reference.
- Split out separate patches to enable the "hclk" clock.
- Add Reviewed-by tag.

Changes in v3:
- Add a patch to expand descriptions for clocks of the eDP node.
- Add Reviewed-by tag.

Changes in v4:
- Modify commit msg.

Changes in v5:
- Enforce the correct third clock name on a per-compatible basis.
- Modify the commit msg simultaneously.
- Add Acked-by tag.

Changes in v6:
- Expand more detail commit msg about using hclk instead of grf clock.

Changes in v7:
- List all valid clock names at the top level, and constrain the clock
  count for each platform with minItems/maxItems in allOf.

Changes in v8:
- Fix indentation to 10 for enum in clock-names property.

Changes in v9:
- Restore the explicit clock-names for RK3399 and RK3588 eDP dt-bindings.

Changes in v10:
- Use automatic cleanup to fix OF node reference leak reported by
  Sashiko.

Changes in v11:
- Pick and rebase DT related patches.

-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 19:23:04 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Fri,  5 Jun 2026 10:23:04 +0800
Subject: [PATCH v11 2/3] arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
In-Reply-To: <20260605022305.3058853-1-damon.ding@rock-chips.com>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
Message-ID: <20260605022305.3058853-3-damon.ding@rock-chips.com>

Add the required HCLK_VO1 bus clock to RK3588 eDP1 node with
corresponding clock-name "hclk". This clock is necessary for
the eDP controller to access video output GRF and work properly.

Previously the clock was enabled implicitly via GRF phandle
reference. Add it explicitly now to align with updated binding.

Fixes: a481bb0b1ad9 ("arm64: dts: rockchip: Add eDP1 dt node for rk3588")
Signed-off-by: Damon Ding <damon.ding at rock-chips.com>

---

Changes in v4:
- Modify the commit msg.
---
 arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
index a2640014ee04..b251bb129cdb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi
@@ -285,8 +285,8 @@ hdmi1_out: port at 1 {
 	edp1: edp at fded0000 {
 		compatible = "rockchip,rk3588-edp";
 		reg = <0x0 0xfded0000 0x0 0x1000>;
-		clocks = <&cru CLK_EDP1_24M>, <&cru PCLK_EDP1>;
-		clock-names = "dp", "pclk";
+		clocks = <&cru CLK_EDP1_24M>, <&cru PCLK_EDP1>, <&cru HCLK_VO1>;
+		clock-names = "dp", "pclk", "hclk";
 		interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH 0>;
 		phys = <&hdptxphy1>;
 		phy-names = "dp";
-- 
2.34.1



From damon.ding at rock-chips.com  Thu Jun  4 19:23:05 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Fri,  5 Jun 2026 10:23:05 +0800
Subject: [PATCH v11 3/3] arm64: dts: rockchip: Add eDP node for RK3576
In-Reply-To: <20260605022305.3058853-1-damon.ding@rock-chips.com>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
Message-ID: <20260605022305.3058853-4-damon.ding@rock-chips.com>

Add full device tree definition for the integrated eDP controller
on RK3576, following the existing RK3588 hardware layout.

Configure required register range, clocks, interrupt, phy, power
domain, reset and grf properties to fully describe the controller.

Signed-off-by: Damon Ding <damon.ding at rock-chips.com>
Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>

---

Changes in v2:
- Add Reviewed-by tag.

Changes in v4:
- Modify the commit msg.
---
 arch/arm64/boot/dts/rockchip/rk3576.dtsi | 28 ++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 28175d8200d5..733449cb88b1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1496,6 +1496,34 @@ hdmi_out: port at 1 {
 			};
 		};
 
+		edp: edp at 27dc0000 {
+			compatible = "rockchip,rk3576-edp";
+			reg = <0x0 0x27dc0000 0x0 0x1000>;
+			clocks = <&cru CLK_EDP0_24M>, <&cru PCLK_EDP0>, <&cru HCLK_VO0_ROOT>;
+			clock-names = "dp", "pclk", "hclk";
+			interrupts = <GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>;
+			phys = <&hdptxphy>;
+			phy-names = "dp";
+			power-domains = <&power RK3576_PD_VO0>;
+			resets = <&cru SRST_EDP0_24M>, <&cru SRST_P_EDP0>;
+			reset-names = "dp", "apb";
+			rockchip,grf = <&vo0_grf>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				edp_in: port at 0 {
+					reg = <0>;
+				};
+
+				edp_out: port at 1 {
+					reg = <1>;
+				};
+			};
+		};
+
 		dp: dp at 27e40000 {
 			compatible = "rockchip,rk3576-dp";
 			reg = <0x0 0x27e40000 0x0 0x30000>;
-- 
2.34.1



From tzimmermann at suse.de  Thu Jun  4 23:26:17 2026
From: tzimmermann at suse.de (Thomas Zimmermann)
Date: Fri, 5 Jun 2026 08:26:17 +0200
Subject: [PATCH 00/76] drm/bridge: Convert all reset users to create_state
In-Reply-To: <20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc@kernel.org>
References: <20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc@kernel.org>
Message-ID: <dce03a80-3d6b-4792-9868-d6052fa3ea77@suse.de>

Hi

Am 30.05.26 um 15:59 schrieb Maxime Ripard:
[...]
>        drm/bridge: adv7511: Switch to atomic_create_state
>        drm/bridge: analogix_dp: Switch to atomic_create_state
>        drm/bridge: anx7625: Switch to atomic_create_state
>        drm/bridge: chipone-icn6211: Switch to atomic_create_state
>        drm/bridge: display-connector: Switch to atomic_create_state
>        drm/bridge: fsl-ldb: Switch to atomic_create_state
>        drm/bridge: imx8mp-hdmi-pvi: Switch to atomic_create_state
>        drm/bridge: imx8qm-ldb: Switch to atomic_create_state
>        drm/bridge: imx8qxp-ldb: Switch to atomic_create_state
>        drm/bridge: imx8qxp-pixel-combiner: Switch to atomic_create_state
>        drm/bridge: imx8qxp-pixel-link: Switch to atomic_create_state
>        drm/bridge: imx8qxp-pxl2dpi: Switch to atomic_create_state
>        drm/bridge: inno-hdmi: Switch to atomic_create_state
>        drm/bridge: ite-it6263: Switch to atomic_create_state
>        drm/bridge: ite-it6505: Switch to atomic_create_state
>        drm/bridge: ite-it66121: Switch to atomic_create_state
>        drm/bridge: lontium-lt9211: Switch to atomic_create_state
>        drm/bridge: lontium-lt9611: Switch to atomic_create_state
>        drm/bridge: lvds-codec: Switch to atomic_create_state
>        drm/bridge: nwl-dsi: Switch to atomic_create_state
>        drm/bridge: panel: Switch to atomic_create_state
>        drm/bridge: parade-ps8640: Switch to atomic_create_state
>        drm/bridge: samsung-dsim: Switch to atomic_create_state
>        drm/bridge: sii902x: Switch to atomic_create_state
>        drm/bridge: ssd2825: Switch to atomic_create_state
>        drm/bridge: dw-dp: Switch to atomic_create_state
>        drm/bridge: dw-hdmi-qp: Switch to atomic_create_state
>        drm/bridge: dw-hdmi: Switch to atomic_create_state
>        drm/bridge: dw-mipi-dsi: Switch to atomic_create_state
>        drm/bridge: dw-mipi-dsi2: Switch to atomic_create_state
>        drm/bridge: tc358762: Switch to atomic_create_state
>        drm/bridge: tc358767: Switch to atomic_create_state
>        drm/bridge: tc358768: Switch to atomic_create_state
>        drm/bridge: tc358775: Switch to atomic_create_state
>        drm/bridge: ti-dlpc3433: Switch to atomic_create_state
>        drm/bridge: ti-sn65dsi83: Switch to atomic_create_state
>        drm/bridge: ti-sn65dsi86: Switch to atomic_create_state
>        drm/bridge: ti-tdp158: Switch to atomic_create_state
>        drm/bridge: ti-tfp410: Switch to atomic_create_state
>        drm/imx: parallel-display: Switch to atomic_create_state
>        drm/ingenic: Switch to atomic_create_state
>        drm/mediatek: dp: Switch to atomic_create_state
>        drm/mediatek: dpi: Switch to atomic_create_state
>        drm/mediatek: dsi: Switch to atomic_create_state
>        drm/mediatek: hdmi: Switch to atomic_create_state
>        drm/mediatek: hdmi_v2: Switch to atomic_create_state
>        drm/meson: encoder_cvbs: Switch to atomic_create_state
>        drm/meson: encoder_dsi: Switch to atomic_create_state
>        drm/meson: encoder_hdmi: Switch to atomic_create_state
>        drm/msm: dp: Switch to atomic_create_state
>        drm/msm: hdmi: Switch to atomic_create_state
>        drm/omap: hdmi4: Switch to atomic_create_state
>        drm/omap: hdmi5: Switch to atomic_create_state
>        drm/renesas: rcar-du: lvds: Switch to atomic_create_state
>        drm/renesas: rcar-du: mipi_dsi: Switch to atomic_create_state
>        drm/renesas: rz-du: mipi_dsi: Switch to atomic_create_state
>        drm/rockchip: cdn-dp: Switch to atomic_create_state
>        drm/rockchip: rk3066_hdmi: Switch to atomic_create_state
>        drm/rockchip: lvds: Switch to atomic_create_state
>        drm/stm: lvds: Switch to atomic_create_state
>        drm/tests: bridge: Switch to atomic_create_state
>        drm/tidss: encoder: Switch to atomic_create_state
>        drm/tidss: oldi: Switch to atomic_create_state
>        drm/vc4: dsi: Switch to atomic_create_state
>        drm/verisilicon: Switch to atomic_create_state
>        drm/xlnx: zynqmp_dp: Switch to atomic_create_state

You can also add my

Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>

to all these one-liners in the drivers.

Best regards
Thomas


>        drm/atomic-state-helper: Remove drm_atomic_helper_bridge_reset()
>        drm/bridge: cdns-dsi: Use __drm_atomic_helper_bridge_state_init()
>        drm/bridge: cdns-dsi: Switch to atomic_create_state
>        drm/bridge: cdns-mhdp8546: Switch to atomic_create_state
>        drm/bridge: Remove atomic_reset support
>
>   drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  2 +-
>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  2 +-
>   drivers/gpu/drm/bridge/analogix/anx7625.c          |  2 +-
>   drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c     |  9 +++---
>   .../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c    |  8 +++---
>   drivers/gpu/drm/bridge/chipone-icn6211.c           |  2 +-
>   drivers/gpu/drm/bridge/display-connector.c         |  2 +-
>   drivers/gpu/drm/bridge/fsl-ldb.c                   |  2 +-
>   drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c       |  2 +-
>   drivers/gpu/drm/bridge/imx/imx8qm-ldb.c            |  2 +-
>   drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c           |  2 +-
>   .../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c    |  2 +-
>   drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c    |  2 +-
>   drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c       |  2 +-
>   drivers/gpu/drm/bridge/inno-hdmi.c                 |  2 +-
>   drivers/gpu/drm/bridge/ite-it6263.c                |  2 +-
>   drivers/gpu/drm/bridge/ite-it6505.c                |  2 +-
>   drivers/gpu/drm/bridge/ite-it66121.c               |  2 +-
>   drivers/gpu/drm/bridge/lontium-lt9211.c            |  2 +-
>   drivers/gpu/drm/bridge/lontium-lt9611.c            |  2 +-
>   drivers/gpu/drm/bridge/lvds-codec.c                |  2 +-
>   drivers/gpu/drm/bridge/nwl-dsi.c                   |  2 +-
>   drivers/gpu/drm/bridge/panel.c                     |  2 +-
>   drivers/gpu/drm/bridge/parade-ps8640.c             |  2 +-
>   drivers/gpu/drm/bridge/samsung-dsim.c              |  2 +-
>   drivers/gpu/drm/bridge/sii902x.c                   |  2 +-
>   drivers/gpu/drm/bridge/ssd2825.c                   |  2 +-
>   drivers/gpu/drm/bridge/synopsys/dw-dp.c            |  2 +-
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c       |  2 +-
>   drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |  2 +-
>   drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c      |  2 +-
>   drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c     |  2 +-
>   drivers/gpu/drm/bridge/tc358762.c                  |  2 +-
>   drivers/gpu/drm/bridge/tc358767.c                  |  4 +--
>   drivers/gpu/drm/bridge/tc358768.c                  |  2 +-
>   drivers/gpu/drm/bridge/tc358775.c                  |  2 +-
>   drivers/gpu/drm/bridge/ti-dlpc3433.c               |  2 +-
>   drivers/gpu/drm/bridge/ti-sn65dsi83.c              |  2 +-
>   drivers/gpu/drm/bridge/ti-sn65dsi86.c              |  2 +-
>   drivers/gpu/drm/bridge/ti-tdp158.c                 |  2 +-
>   drivers/gpu/drm/bridge/ti-tfp410.c                 |  2 +-
>   drivers/gpu/drm/drm_atomic_state_helper.c          | 33 ++++++++++++----------
>   drivers/gpu/drm/drm_bridge.c                       |  4 +--
>   drivers/gpu/drm/imx/ipuv3/parallel-display.c       |  2 +-
>   drivers/gpu/drm/ingenic/ingenic-drm-drv.c          |  2 +-
>   drivers/gpu/drm/mediatek/mtk_dp.c                  |  2 +-
>   drivers/gpu/drm/mediatek/mtk_dpi.c                 |  2 +-
>   drivers/gpu/drm/mediatek/mtk_dsi.c                 |  2 +-
>   drivers/gpu/drm/mediatek/mtk_hdmi.c                |  2 +-
>   drivers/gpu/drm/mediatek/mtk_hdmi_v2.c             |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_cvbs.c         |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_dsi.c          |  2 +-
>   drivers/gpu/drm/meson/meson_encoder_hdmi.c         |  2 +-
>   drivers/gpu/drm/msm/dp/dp_drm.c                    |  4 +--
>   drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             |  2 +-
>   drivers/gpu/drm/omapdrm/dss/hdmi4.c                |  2 +-
>   drivers/gpu/drm/omapdrm/dss/hdmi5.c                |  2 +-
>   drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c        |  2 +-
>   drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c    |  2 +-
>   drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c     |  2 +-
>   drivers/gpu/drm/rockchip/cdn-dp-core.c             |  2 +-
>   drivers/gpu/drm/rockchip/rk3066_hdmi.c             |  2 +-
>   drivers/gpu/drm/rockchip/rockchip_lvds.c           |  2 +-
>   drivers/gpu/drm/stm/lvds.c                         |  2 +-
>   drivers/gpu/drm/tests/drm_bridge_test.c            |  2 +-
>   drivers/gpu/drm/tidss/tidss_encoder.c              |  2 +-
>   drivers/gpu/drm/tidss/tidss_oldi.c                 |  2 +-
>   drivers/gpu/drm/vc4/vc4_dsi.c                      |  2 +-
>   drivers/gpu/drm/verisilicon/vs_bridge.c            |  4 +--
>   drivers/gpu/drm/xlnx/zynqmp_dp.c                   |  2 +-
>   include/drm/drm_atomic_state_helper.h              |  6 ++--
>   include/drm/drm_bridge.h                           | 33 ++++++++--------------
>   72 files changed, 111 insertions(+), 120 deletions(-)
> ---
> base-commit: 21fcb222f0d1e1c9f5b04c09e9fb3408e13a0264
> change-id: 20260530-drm-no-more-bridge-reset-ca20d5e22740
>
> Best regards,

-- 
--
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 krzk at kernel.org  Fri Jun  5 03:03:19 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Jun 2026 12:03:19 +0200
Subject: [PATCH V10 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
In-Reply-To: <20260604201832.60656-3-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
 <20260604201832.60656-3-macroalpha82@gmail.com>
Message-ID: <20260605-big-auk-of-progress-c99b3a@quoll>

On Thu, Jun 04, 2026 at 03:18:24PM -0500, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add the ICM42607 and ICM42607P inertial measurement unit.
> 
> This device is functionally very similar to the icm42600 series with a
> very different register layout. The driver does not require an
> interrupt for these specific chip revisions.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---
>  .../bindings/iio/imu/invensense,icm42600.yaml  | 18 +++++++++++++++++-
>  1 file changed, 17 insertions(+), 1 deletion(-)

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

Best regards,
Krzysztof



From krzk at kernel.org  Fri Jun  5 03:15:05 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Fri, 5 Jun 2026 12:15:05 +0200
Subject: [PATCH v6 0/3] arm64: dts: rockchip: add Vicharak Axon board
 support
In-Reply-To: <20260601162143.170030-1-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
Message-ID: <20260605-supportive-exuberant-serval-cc42c0@quoll>

On Mon, Jun 01, 2026 at 09:51:39PM +0530, Hrushiraj Gandhi wrote:
> This series adds initial device tree support for the Vicharak Axon
> single-board computer, which is based on the Rockchip RK3588 SoC.
> 
> The Vicharak Axon is a feature-rich SBC targeting developer and embedded
> use cases. It ships with:

Slow down, please. One patchset per 24h.

Best regards,
Krzysztof



From devnull+ricardo.pardini.net at kernel.org  Fri Jun  5 04:49:08 2026
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Fri, 05 Jun 2026 13:49:08 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
Message-ID: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).

The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
compatibles documented in their own bindings (e.g. microchip,lan95xx)
so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
these PCI function nodes can be validated.

Suggested-by: Sebastian Reichel <sebastian.reichel at collabora.com>
Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../devicetree/bindings/net/realtek,r8169.yaml     | 54 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 2 files changed, 55 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/realtek,r8169.yaml b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
new file mode 100644
index 0000000000000..6923211ff4c93
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/realtek,r8169.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Realtek r8169 family PCIe Ethernet Controllers
+
+maintainers:
+  - Heiner Kallweit <hkallweit1 at gmail.com>
+
+description:
+  PCI function node properties for fixed/soldered Realtek Ethernet
+  controllers driven by the r8169 driver.
+
+allOf:
+  - $ref: ethernet-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - pci10ec,8125  # RTL8125 2.5GbE
+      - pci10ec,8126  # RTL8126 5GbE
+      - pci10ec,8127  # RTL8127
+      - pci10ec,8161  # RTL8168 variant
+      - pci10ec,8162  # RTL8168 variant
+      - pci10ec,8168  # RTL8168/8111 GbE
+
+  reg:
+    maxItems: 1
+
+  local-mac-address: true
+  mac-address: true
+  nvmem-cells: true
+  nvmem-cell-names: true
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    pcie {
+        #address-cells = <3>;
+        #size-cells = <2>;
+
+        ethernet at 0,0 {
+            compatible = "pci10ec,8125";
+            reg = <0x10000 0 0 0 0>;
+            local-mac-address = [00 00 00 00 00 00];
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index b539be153f6a4..6341de4fadb6c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -134,6 +134,7 @@ M:	Heiner Kallweit <hkallweit1 at gmail.com>
 M:	nic_swsd at realtek.com
 L:	netdev at vger.kernel.org
 S:	Maintained
+F:	Documentation/devicetree/bindings/net/realtek,r8169.yaml
 F:	drivers/net/ethernet/realtek/r8169*
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER

-- 
2.54.0




From devnull+ricardo.pardini.net at kernel.org  Fri Jun  5 04:49:10 2026
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Fri, 05 Jun 2026 13:49:10 +0200
Subject: [PATCH v3 3/3] arm64: dts: rockchip: describe PCIe RTL8125
 Ethernet on Radxa ROCK 5 family
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
Message-ID: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-3-8a8857b39daf@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

The Radxa ROCK 5B / 5B+ / 5T all carry on-board Realtek RTL8125 NICs.

Describe the fixed function nodes and attach ethernet0/ethernet1
aliases, so that U-Boot's fdt_fixup_ethernet() can inject mac-address
properties from its ethaddr/eth1addr env, for stable MACs across
boots that both U-Boot and the kernel agree on.

The RTL8125 on pcie2x1l2 is shared by all three variants. The ROCK 5T
additionally describes pcie2x1l1 with its second RTL8125.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 .../arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi | 15 +++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts        | 18 ++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi
index bf4a1d2e55ca3..1b48f57638fca 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi
@@ -10,6 +10,7 @@
 
 / {
 	aliases {
+		ethernet0 = &rtl_eth0;
 		mmc0 = &sdhci;
 		mmc1 = &sdmmc;
 		mmc2 = &sdio;
@@ -482,6 +483,20 @@ &pcie2x1l2 {
 	reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
 	vpcie3v3-supply = <&vcc3v3_pcie2x1l2>;
 	status = "okay";
+
+	pcie at 0,0 {
+		reg = <0x400000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+		device_type = "pci";
+		bus-range = <0x40 0x4f>;
+
+		rtl_eth0: ethernet at 0,0 {
+			compatible = "pci10ec,8125";
+			reg = <0x410000 0 0 0 0>;
+		};
+	};
 };
 
 &pcie30phy {
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
index 425036146b6d9..116e3512c4413 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts
@@ -8,6 +8,10 @@ / {
 	model = "Radxa ROCK 5T";
 	compatible = "radxa,rock-5t", "rockchip,rk3588";
 
+	aliases {
+		ethernet1 = &rtl_eth1;
+	};
+
 	analog-sound {
 		compatible = "audio-graph-card";
 		label = "rk3588-es8316";
@@ -76,6 +80,20 @@ &pcie2x1l1 {
 	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
 	vpcie3v3-supply = <&vcc3v3_pcie2x1l1>;
 	status = "okay";
+
+	pcie at 0,0 {
+		reg = <0x300000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+		device_type = "pci";
+		bus-range = <0x30 0x3f>;
+
+		rtl_eth1: ethernet at 0,0 {
+			compatible = "pci10ec,8125";
+			reg = <0x310000 0 0 0 0>;
+		};
+	};
 };
 
 &pcie30phy {

-- 
2.54.0




From devnull+ricardo.pardini.net at kernel.org  Fri Jun  5 04:49:09 2026
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Fri, 05 Jun 2026 13:49:09 +0200
Subject: [PATCH v3 2/3] arm64: dts: rockchip: describe PCIe RTL8125
 Ethernet on NanoPC-T6
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
Message-ID: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-2-8a8857b39daf@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

The FriendlyElec NanoPC-T6 carries two on-board Realtek RTL8125 NICs
behind pcie2x1l0 and pcie2x1l2.

Describe the fixed function nodes and attach ethernet0/ethernet1
aliases, so that U-Boot's fdt_fixup_ethernet() can inject mac-address
properties from its ethaddr/eth1addr env. The on-NIC EEPROMs on this
board are not pre-programmed with a unique MAC, so this gives a
stable MAC across boots that both U-Boot and the kernel agree on.

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
index 84b6b53f016ab..04c4479f08170 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
@@ -20,6 +20,8 @@ / {
 	compatible = "friendlyarm,nanopc-t6", "rockchip,rk3588";
 
 	aliases {
+		ethernet0 = &rtl_eth0;
+		ethernet1 = &rtl_eth1;
 		mmc0 = &sdhci;
 		mmc1 = &sdmmc;
 	};
@@ -635,6 +637,20 @@ &pcie2x1l0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie2_0_rst>;
 	status = "okay";
+
+	pcie at 0,0 {
+		reg = <0x200000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+		device_type = "pci";
+		bus-range = <0x20 0x2f>;
+
+		rtl_eth0: ethernet at 0,0 {
+			compatible = "pci10ec,8125";
+			reg = <0x210000 0 0 0 0>;
+		};
+	};
 };
 
 &pcie2x1l1 {
@@ -651,6 +667,20 @@ &pcie2x1l2 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie2_2_rst>;
 	status = "okay";
+
+	pcie at 0,0 {
+		reg = <0x400000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+		device_type = "pci";
+		bus-range = <0x40 0x4f>;
+
+		rtl_eth1: ethernet at 0,0 {
+			compatible = "pci10ec,8125";
+			reg = <0x410000 0 0 0 0>;
+		};
+	};
 };
 
 &pcie30phy {

-- 
2.54.0




From devnull+ricardo.pardini.net at kernel.org  Fri Jun  5 04:49:07 2026
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Fri, 05 Jun 2026 13:49:07 +0200
Subject: [PATCH v3 0/3] describe RTL8125 PCIe NICs on Rockchip boards (and
 add DT binding)
Message-ID: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>

Several Rockchip rk35xx boards carry on-board Realtek RTL8125 2.5GbE
NICs whose PCI function nodes are not described in the DT. Describing
them allows for stable ethernetN aliases (matching the GMAC alias
convention on these boards) and lets U-Boot's fdt_fixup_ethernet()
inject mac-address properties from its ethaddr/ethNaddr env, so MACs
stay stable across boots and U-Boot and kernel MAC match.

Patch 1 adds a DT binding for Realtek r8169 family PCIe Ethernet
controllers.

Patch 2 describes the on-board RTL8125 function nodes on the
FriendElec NanoPC-T6 (and variants).

Patch 3 is the same, but for the Radxa ROCK 5B / 5B+ / 5T family
done based on lspci output provided by helpful Armbian folks.

---
Changes in v3:
- new patch: add a DT binding for Realtek r8169 family PCIe Ethernet
  controllers, per Sebastian Reichel's review (the "pciVVVV,DDDD" OF
  spelling still needs a binding when used in a board DT).
- new patch for Rock5 series, and include a brief rationale in each.
- retitle the series, since it now covers a few boards and a binding
  rather than just DeviceTree changes for the NanoPC-T6.
- drop the v2 "rename vcc3v3_pcie2x1l0 regulator" patch from this
  series; it will be sent separately as it is not relevant to this.
- Link to v2: https://patch.msgid.link/20260529-rk3588-dts-rtl-eth-describe-dt-alias-v2-0-49700248143f at pardini.net

Changes in v2:
- fix: pcie2x1l0, not pcie2x1l1; indirectly caught by Sashiko's review [1]
- while-at-it: rename regulator vcc3v3_pcie2x1l0 to l1
- Link to v1: https://patch.msgid.link/20260525-rk3588-dts-rtl-eth-describe-dt-alias-v1-1-a6fcda563ac7 at pardini.net

[1] https://sashiko.dev/#/patchset/20260525-rk3588-dts-rtl-eth-describe-dt-alias-v1-1-a6fcda563ac7%40pardini.net

To: Heiner Kallweit <hkallweit1 at gmail.com>
To: nic_swsd at realtek.com
To: Andrew Lunn <andrew+netdev at lunn.ch>
To: "David S. Miller" <davem at davemloft.net>
To: Eric Dumazet <edumazet at google.com>
To: Jakub Kicinski <kuba at kernel.org>
To: Paolo Abeni <pabeni at redhat.com>
To: Rob Herring <robh at kernel.org>
To: Krzysztof Kozlowski <krzk+dt at kernel.org>
To: Conor Dooley <conor+dt at kernel.org>
To: Heiko Stuebner <heiko at sntech.de>
Cc: Sebastian Reichel <sebastian.reichel at collabora.com>
Cc: netdev at vger.kernel.org
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
Signed-off-by: Ricardo Pardini <ricardo at pardini.net>

---
Ricardo Pardini (3):
      dt-bindings: net: add Realtek r8169 family PCIe Ethernet
      arm64: dts: rockchip: describe PCIe RTL8125 Ethernet on NanoPC-T6
      arm64: dts: rockchip: describe PCIe RTL8125 Ethernet on Radxa ROCK 5 family

 .../devicetree/bindings/net/realtek,r8169.yaml     | 54 ++++++++++++++++++++++
 MAINTAINERS                                        |  1 +
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 30 ++++++++++++
 .../boot/dts/rockchip/rk3588-rock-5b-5bp-5t.dtsi   | 15 ++++++
 arch/arm64/boot/dts/rockchip/rk3588-rock-5t.dts    | 18 ++++++++
 5 files changed, 118 insertions(+)
---
base-commit: e7ae89a0c97ce2b68b0983cd01eda67cf373517d
change-id: 20260524-rk3588-dts-rtl-eth-describe-dt-alias-c1ed187b7c50

Best regards,
--  
Ricardo Pardini <ricardo at pardini.net>




From devnull+ricardo.pardini.net at kernel.org  Fri Jun  5 04:54:35 2026
From: devnull+ricardo.pardini.net at kernel.org (Ricardo Pardini via B4 Relay)
Date: Fri, 05 Jun 2026 13:54:35 +0200
Subject: [PATCH] arm64: dts: rockchip: fix regulator names on NanoPC-T6
Message-ID: <20260605-rk3588-dts-rockchip-nanopct6-fix-schematic-names-v1-1-15dd3b23ab1a@pardini.net>

From: Ricardo Pardini <ricardo at pardini.net>

Three fixed-regulator names on the NanoPC-T6 don't match the board
schematic [1].

- vcc3v3_pcie2x1l0 -> vdd_mpcie_3v3
  This GPIO-switched 3v3 regulator is labeled vcc3v3_pcie2x1l0, but
  it is wired to and consumed by &pcie2x1l1. Per the schematic,
  the GPIO PCIE_M2_1_PWREN controls the power net VDD_MPCIE_3.3V;
  rename to match.
- vdd_2v0_pldo_s3 -> vcc_2v0_pldo_s3
  Typo in the regulator-name property of RK806-1 DCDC reg7. The node
  label and the schematic power-net name both already use the vcc_
  form; only the regulator-name string had vdd_.
- vcc3v3_pcie30 -> vcc3v3_pcie_m2_0
  The GPIO-switched 3v3 feeding the M.2 M-Key (NVMe) slot is named
  after the PCIe controller it sits behind rather than the schematic
  power net. The schematic names it VCC3V3_PCIE_M2_0 (produced by an
  MP2143-based buck off VCC_5V0, enabled by PCIE_M2_0_PWREN); rename
  to match.

No functional change.

[1] https://wiki.friendlyelec.com/wiki/images/9/97/NanoPC-T6_2301_SCH.PDF

Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
---
Align three fixed-regulator names on the NanoPC-T6 (and LTS) with
the labels used in the board schematic: the mini-PCIe 3v3 regulator
(whose current name is actively misleading), a vdd_/vcc_ typo on
RK806-1 DCDC reg7, and the M.2 M-Key 3v3 supply (named after the
PCIe controller rather than the schematic power net).

Using actual schematic names was pointed out by Sebastian during
review of an earlier (and mostly unrelated) series [1].

No functional change.

[1] https://lore.kernel.org/linux-rockchip/ah2AYT4XmYR03I7z at venus/
---
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
index 84b6b53f016ab..b44aff39cb32e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dtsi
@@ -201,25 +201,25 @@ vbus5v0_usb: regulator-vbus5v0-usb {
 		vin-supply = <&vcc5v0_sys>;
 	};
 
-	vcc3v3_pcie2x1l0: regulator-vcc3v3-pcie2x1l0 {
+	vdd_mpcie_3v3: regulator-vdd-mpcie-3v3 {
 		compatible = "regulator-fixed";
 		enable-active-high;
 		gpio = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pcie_m2_1_pwren>;
-		regulator-name = "vcc3v3_pcie2x1l0";
+		regulator-name = "vdd_mpcie_3v3";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		vin-supply = <&vcc5v0_sys>;
 	};
 
-	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+	vcc3v3_pcie_m2_0: regulator-vcc3v3-pcie-m2-0 {
 		compatible = "regulator-fixed";
 		enable-active-high;
 		gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&pcie_m2_0_pwren>;
-		regulator-name = "vcc3v3_pcie30";
+		regulator-name = "vcc3v3_pcie_m2_0";
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
 		vin-supply = <&vcc5v0_sys>;
@@ -639,7 +639,7 @@ &pcie2x1l0 {
 
 &pcie2x1l1 {
 	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
-	vpcie3v3-supply = <&vcc3v3_pcie2x1l0>;
+	vpcie3v3-supply = <&vdd_mpcie_3v3>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pcie2_1_rst>;
 	status = "okay";
@@ -659,7 +659,7 @@ &pcie30phy {
 
 &pcie3x4 {
 	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
-	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	vpcie3v3-supply = <&vcc3v3_pcie_m2_0>;
 	status = "okay";
 };
 
@@ -965,7 +965,7 @@ vcc_2v0_pldo_s3: dcdc-reg7 {
 				regulator-min-microvolt = <2000000>;
 				regulator-max-microvolt = <2000000>;
 				regulator-ramp-delay = <12500>;
-				regulator-name = "vdd_2v0_pldo_s3";
+				regulator-name = "vcc_2v0_pldo_s3";
 
 				regulator-state-mem {
 					regulator-on-in-suspend;

---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: 20260603-rk3588-dts-rockchip-nanopct6-fix-schematic-names-a1b8d27f82e7

Best regards,
--  
Ricardo Pardini <ricardo at pardini.net>




From s.pueschel at pengutronix.de  Fri Jun  5 06:32:01 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Fri, 05 Jun 2026 15:32:01 +0200
Subject: [PATCH] media: rockchip: rga: don't change RGB quantization
Message-ID: <20260605-spu-fixrga3quantization-v1-1-1059d984dc6e@pengutronix.de>

Don't change the quantization of an RGB format when converting between
RGB and YUV with the RGA3. As the RGA3 only supports doing conversions
to full range YUV with BT601, it wants to announce it through
try_fmt/s_fmt.

As it is only relevant, when converting between RGB and YUV, it's
guarded by a given condition. But the condition also causes the
RGB format quantization to be adjusted to limited range, which
is incorrect.

Therefore simplify the condition to only apply when the current format
is a YUV format. Also document the reason for checking if the other
format is an RGB format.

Fixes: 24a63d4c9d3c ("media: rockchip: rga: add rga3 support")
Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
This patch is a fix to the upcoming RGA3 support. By mistake it'll also
adjust the RGB quantization instead of only adjusting the quantization
of the YUV formats. Therefore remove the incorrect conditions and
document why we also check the format of the other side.

I've just noticed this flawed condition and didn't check/reproduce it in
a practical scenario.

    v4l2-compliance 1.32.0, 64 bits, 64-bit time_t
    ....
    	Card type        : rga3
    ...
    Total for rockchip-rga device /dev/video0: 48, Succeeded: 48, Failed: 0, Warnings: 0

    v4l2-compliance 1.32.0, 64 bits, 64-bit time_t
    ...
    	Card type        : rga2
    ...
    Total for rockchip-rga device /dev/video1: 48, Succeeded: 48, Failed: 0, Warnings: 0
---
 drivers/media/platform/rockchip/rga/rga3-hw.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
index ca1c268303dd4..c4a71306278ba 100644
--- a/drivers/media/platform/rockchip/rga/rga3-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -450,10 +450,14 @@ static void *rga3_adjust_and_map_format(struct rga_ctx *ctx,
 	other_format = is_output ? &ctx->out.pix : &ctx->in.pix;
 	other_format_info = v4l2_format_info(other_format->pixelformat);
 
-	if ((v4l2_is_format_rgb(format_info) &&
-	     v4l2_is_format_yuv(other_format_info)) ||
-	    (v4l2_is_format_yuv(format_info) &&
-	     v4l2_is_format_rgb(other_format_info))) {
+	/*
+	 * Only apply the quantization restrictions when we need to
+	 * convert between RGB and YUV. Otherwise there is no point
+	 * to limit the quantization for operations like scaling or
+	 * rotations.
+	 */
+	if (v4l2_is_format_yuv(format_info) &&
+	    v4l2_is_format_rgb(other_format_info)) {
 		/*
 		 * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions
 		 * Additionally BT709 and BT2020 only support limited range YUV.

---
base-commit: 6a75e3d4f6428b90f398354212e3a2e0172851d6
change-id: 20260605-spu-fixrga3quantization-061c761a1d80

Best regards,
--  
Sven P?schel <s.pueschel at pengutronix.de>



From hkallweit1 at gmail.com  Fri Jun  5 08:48:04 2026
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Fri, 5 Jun 2026 17:48:04 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
 <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
Message-ID: <b7cc8eba-ff6e-417d-8e74-b3bb24e08a26@gmail.com>

On 05.06.2026 13:49, Ricardo Pardini via B4 Relay wrote:
> From: Ricardo Pardini <ricardo at pardini.net>
> 
> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
> 
> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
> compatibles documented in their own bindings (e.g. microchip,lan95xx)
> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
> these PCI function nodes can be validated.
> 

The of node seems to be created by of_pci_make_dev_node(). But this
function is called for bridges only in pci_bus_add_device().
So where is the node created in your case? Did you test node creation?

> Suggested-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
> ---
>  .../devicetree/bindings/net/realtek,r8169.yaml     | 54 ++++++++++++++++++++++
>  MAINTAINERS                                        |  1 +
>  2 files changed, 55 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/realtek,r8169.yaml b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> new file mode 100644
> index 0000000000000..6923211ff4c93
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/realtek,r8169.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Realtek r8169 family PCIe Ethernet Controllers
> +
> +maintainers:
> +  - Heiner Kallweit <hkallweit1 at gmail.com>
> +
> +description:
> +  PCI function node properties for fixed/soldered Realtek Ethernet
> +  controllers driven by the r8169 driver.
> +
> +allOf:
> +  - $ref: ethernet-controller.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - pci10ec,8125  # RTL8125 2.5GbE
> +      - pci10ec,8126  # RTL8126 5GbE
> +      - pci10ec,8127  # RTL8127
> +      - pci10ec,8161  # RTL8168 variant
> +      - pci10ec,8162  # RTL8168 variant
> +      - pci10ec,8168  # RTL8168/8111 GbE

This list reflects just some of the PCI id's handled by r8169.
Any specific reason for this exact selection?

> +
> +  reg:
> +    maxItems: 1
> +
> +  local-mac-address: true
> +  mac-address: true
> +  nvmem-cells: true
> +  nvmem-cell-names: true
> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pcie {
> +        #address-cells = <3>;
> +        #size-cells = <2>;
> +
> +        ethernet at 0,0 {
> +            compatible = "pci10ec,8125";
> +            reg = <0x10000 0 0 0 0>;
> +            local-mac-address = [00 00 00 00 00 00];
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b539be153f6a4..6341de4fadb6c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -134,6 +134,7 @@ M:	Heiner Kallweit <hkallweit1 at gmail.com>
>  M:	nic_swsd at realtek.com
>  L:	netdev at vger.kernel.org
>  S:	Maintained
> +F:	Documentation/devicetree/bindings/net/realtek,r8169.yaml
>  F:	drivers/net/ethernet/realtek/r8169*
>  
>  8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
> 



From alchark at gmail.com  Fri Jun  5 08:58:59 2026
From: alchark at gmail.com (Alexey Charkov)
Date: Fri, 5 Jun 2026 19:58:59 +0400
Subject: [PATCH RFC v2] drm/rockchip: vop2: Add clock rate mode check
In-Reply-To: <20260409-vop2-clk-rate-check-v2-1-b207cfc427d7@collabora.com>
References: <20260409-vop2-clk-rate-check-v2-1-b207cfc427d7@collabora.com>
Message-ID: <CABjd4Yw_HYpjhrgmonB9FmWV00q=r3yvqnFE4TXEHpM1ZgWOhA@mail.gmail.com>

On Fri, Apr 10, 2026 at 2:37?AM Sebastian Reichel
<sebastian.reichel at collabora.com> wrote:
>
> The display might offer modes, which exceed the maximum clock rate of a
> video output. This usually happens for displays that offer refresh rates
> above 60 Hz. This results in no picture (or a broken one) being displayed
> without manual intervention. Fix this by teaching the driver about the
> maximum achievable clock rates for each video port.
>
> The information about the maximum clock rates for each video channel and
> the tip about multiple pixels being processed per clock were provided by
> Andy Yan and roughly checked against the information available in the
> datasheet (which specifies limits like "2560x1600 at 60Hz with 10-bit"
> instead of a specific pixel rate).
>
> For the video ports supporting a 600 MHz input clock, there is some
> logic to handle up to 4 pixels in parallel when needed resulting in
> the extra multiplier.
>
> Suggested-by: Andy Yan <andy.yan at rock-chips.com>
> Link: https://lore.kernel.org/linux-rockchip/1528d788.186b.19d08ed974c.Coremail.andyshrk at 163.com/
> Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> ---
> I've kept the RFC tag, as I'm not sure about the 4x parallel pixel
> processing. IIUIC all of the video ports with a maximum of 600 MHz
> input clock support it, considering they can go to 4K @ 120Hz,
> which is above 1.2GHz while Andy mentioned a max. support clock rate
> of 600 MHz.
> ---
> Changes in v2:
> - Link to v1: https://lore.kernel.org/r/20260217-vop2-clk-rate-check-v1-1-989b569119ba at collabora.com
> - based on v7.0-rc7
> - rename max_clock_rate into max_pixel_clock_rate to distinguish from
>   input clock
> - update max clock rates to the numbers provided by Andy Yan with
>   extra 4x multiplier for 4K 120Hz VPs
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c |  3 +++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  1 +
>  drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 10 ++++++++++
>  3 files changed, 14 insertions(+)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> index a195f5c819a2..35a0edda5375 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> @@ -1434,6 +1434,9 @@ static enum drm_mode_status vop2_crtc_mode_valid(struct drm_crtc *crtc,
>         if (mode->hdisplay > vp->data->max_output.width)
>                 return MODE_BAD_HVALUE;
>
> +       if (mode->clock > vp->data->max_pixel_clock_rate / 1000)
> +               return MODE_CLOCK_HIGH;
> +
>         return MODE_OK;
>  }
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> index 9124191899ba..fd46913f3346 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> @@ -225,6 +225,7 @@ struct vop2_video_port_data {
>         u16 gamma_lut_len;
>         u16 cubic_lut_len;
>         struct vop_rect max_output;
> +       u32 max_pixel_clock_rate;
>         const u8 pre_scan_max_dly[4];
>         unsigned int offset;
>         /**
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index f3950e8476a7..6ae3d506c476 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -559,18 +559,21 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
>                 .gamma_lut_len = 1024,
>                 .cubic_lut_len = 9 * 9 * 9,
>                 .max_output = { 4096, 2304 },
> +               .max_pixel_clock_rate = 600000000U,
>                 .pre_scan_max_dly = { 69, 53, 53, 42 },
>                 .offset = 0xc00,
>         }, {
>                 .id = 1,
>                 .gamma_lut_len = 1024,
>                 .max_output = { 2048, 1536 },
> +               .max_pixel_clock_rate = 200000000U,
>                 .pre_scan_max_dly = { 40, 40, 40, 40 },
>                 .offset = 0xd00,
>         }, {
>                 .id = 2,
>                 .gamma_lut_len = 1024,
>                 .max_output = { 1920, 1080 },
> +               .max_pixel_clock_rate = 150000000U,
>                 .pre_scan_max_dly = { 40, 40, 40, 40 },
>                 .offset = 0xe00,
>         },
> @@ -775,6 +778,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
>                 .gamma_lut_len = 1024,
>                 .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
>                 .max_output = { 4096, 2304 },
> +               .max_pixel_clock_rate = 600000000U * 4,

Hi Sebastian,

I've tested it on a bunch of different displays with RK3576 while also
giving VP0 an unlimited PLL to work with (and also expanding its rates
table for each of the displays' EDID preferred pixel clocks), and I'm
pretty sure this should be * 2 here, rather than * 4. That would also
align with ".pixel_rate = 2" just below.

In its current form, some of the advanced displays with 240 Hz modes
by default choose modes leading to visual artifacts indicative of
overclocking strain of the graphics pipeline.

The rest look plausible, so with that change please feel free to include:

Tested-by: Alexey Charkov <alchark at flipper.net> # RK3576

Best regards,
Alexey


From andriy.shevchenko at intel.com  Fri Jun  5 09:08:35 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Fri, 5 Jun 2026 19:08:35 +0300
Subject: [PATCH V10 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260604201832.60656-4-macroalpha82@gmail.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
 <20260604201832.60656-4-macroalpha82@gmail.com>
Message-ID: <aiL0g8d0Y_JeAC5c@ashevche-desk.local>

On Thu, Jun 04, 2026 at 03:18:25PM -0500, Chris Morgan wrote:

> Add the core component of a new inv_icm42607 driver. This includes
> a few setup functions and the full register definition in the
> header file.

...

> +#ifndef INV_ICM42607_H_
> +#define INV_ICM42607_H_
> +
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>

I haven't found users for these two.

+ bits.h // BIT() / GENMASK()

> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>


> +#include <linux/regulator/consumer.h>

No users for this one.

+ types.h // for bool

...

> +enum inv_icm42607_sensor_mode {
> +	INV_ICM42607_SENSOR_MODE_OFF,
> +	INV_ICM42607_SENSOR_MODE_STANDBY,
> +	INV_ICM42607_SENSOR_MODE_LOW_POWER,
> +	INV_ICM42607_SENSOR_MODE_LOW_NOISE,

Are those enums map 1:1 to HW bits or bitfields? If so, assign explicitly each
of them.

> +	INV_ICM42607_SENSOR_MODE_NB

Is this a terminator like NUMBER_OF ?

> +};

...

> +/* ODR values */
> +enum inv_icm42607_odr {
> +	INV_ICM42607_ODR_1600HZ = 5,

See above. This one is problematic. No one should rely on Linux/C enums when
it's about HW bits. All HW related stuff has to be explicit.

> +	INV_ICM42607_ODR_800HZ,
> +	INV_ICM42607_ODR_400HZ,
> +	INV_ICM42607_ODR_200HZ,
> +	INV_ICM42607_ODR_100HZ,
> +	INV_ICM42607_ODR_50HZ,
> +	INV_ICM42607_ODR_25HZ,
> +	INV_ICM42607_ODR_12_5HZ,
> +	INV_ICM42607_ODR_6_25HZ_LP,
> +	INV_ICM42607_ODR_3_125HZ_LP,
> +	INV_ICM42607_ODR_1_5625HZ_LP,
> +	INV_ICM42607_ODR_NB
> +};

...

> +struct inv_icm42607_sensor_conf {
> +	int mode;
> +	int fs;
> +	int odr;
> +	int filter;

All of them are supposed to be signed? Why?

> +};

...

> +struct inv_icm42607_hw {
> +	uint8_t whoami;

What's wrong with u8?

> +	const char *name;
> +	const struct inv_icm42607_conf *conf;
> +};

...

> +#include <linux/delay.h>
> +#include <linux/dev_printk.h>
> +#include <linux/interrupt.h>
> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>

IWYU, please.

...

> +/**
> + *  inv_icm42607_setup() - check and setup chip
> + *  @st:	driver internal state
> + *  @bus_setup:	callback for setting up bus specific registers
> + *
> + *  Returns 0 on success, a negative error code otherwise.

If you do kernel-doc, validate it. Return section is missing here.

> + */

...

> +{
> +	const struct device *dev = regmap_get_device(st->map);
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> +	if (ret)
> +		return ret;
> +
> +	if (val != st->hw->whoami)
> +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> +			 val, st->hw->whoami, st->hw->name);

dev_warn_probe() ?

> +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> +	if (ret)
> +		return ret;

> +	fsleep(INV_ICM42607_RESET_TIME_MS * 1000);

USEC_PER_MSEC (needs time.h)

> +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> +				       INV_ICM42607_RESET_TIME_MS * 100,
> +				       INV_ICM42607_RESET_TIME_MS * 10000);

These are weird, as in the first case it's actually 1/10th of _RESET_TIME_MS.
Perhaps you need to reconsider what you use as that constant. Personally I
prefer to see just plain values with the multipliers (to convert to ?s).

> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "reset error, reset done bit not set\n");
> +
> +	/* Sync the regcache again after a reset. */
> +	regcache_mark_dirty(st->map);
> +	ret = regcache_sync(st->map);
> +	if (ret)
> +		return ret;
> +
> +	ret = bus_setup(st);

Hmm... This is bad name with potential of name collision in the future (in case
driver bus code wants to have the same name for the function).

> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> +			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
> +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
> +	if (ret)
> +		return ret;
> +
> +	return inv_icm42607_set_conf(st, st->hw->conf);
> +}

...

> +int inv_icm42607_core_probe(struct regmap *regmap,
> +			    const struct inv_icm42607_hw *hw,
> +			    inv_icm42607_bus_setup bus_setup)
> +{
> +	struct device *dev = regmap_get_device(regmap);
> +	struct inv_icm42607_state *st;
> +	int ret;
> +
> +	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
> +	if (!st)
> +		return -ENOMEM;
> +
> +	ret = devm_mutex_init(dev, &st->lock);
> +	if (ret)
> +		return ret;
> +
> +	st->hw = hw;
> +	st->map = regmap;
> +
> +	ret = iio_read_mount_matrix(dev, &st->orientation);
> +	if (ret)

> +		return dev_err_probe(dev, ret,
> +				     "failed to retrieve mounting matrix %d\n", ret);

Remove duplicate ret printing.

> +
> +	ret = devm_regulator_get_enable(dev, "vdd");
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to get vdd regulator\n");
> +
> +	st->vddio_supply = devm_regulator_get(dev, "vddio");
> +	if (IS_ERR(st->vddio_supply))
> +		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
> +				     "Failed to get vddio regulator\n");
> +
> +	ret = inv_icm42607_enable_vddio_reg(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
> +	if (ret)
> +		return ret;

> +	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
> +	ret = inv_icm42607_setup(st, bus_setup);
> +	if (ret)
> +		return ret;
> +
> +	return 0;

Just

	return inv_icm42607_setup(st, bus_setup);

? Or is it going to be extended in the next changes?

> +}

-- 
With Best Regards,
Andy Shevchenko




From conor at kernel.org  Fri Jun  5 09:26:36 2026
From: conor at kernel.org (Conor Dooley)
Date: Fri, 5 Jun 2026 17:26:36 +0100
Subject: [PATCH V5 3/6] dt-bindings: display: panel: Add Anbernic TD4310
 panel
In-Reply-To: <20260604220802.119107-4-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
 <20260604220802.119107-4-macroalpha82@gmail.com>
Message-ID: <20260605-carless-mouth-92684e2ee74e@spud>

On Thu, Jun 04, 2026 at 05:07:58PM -0500, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
> on the TD4310 controller IC. It measures approximately 5.5 inches
> diagonally and is 1080x1920 in resolution.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---
>  .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
>  1 file changed, 66 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
> new file mode 100644
> index 000000000000..6f7f92b9c860
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
> @@ -0,0 +1,66 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Anbernic TD4310 Based Panels
> +
> +maintainers:
> +  - Chris Morgan <macromorgan at hotmail.com>
> +
> +description:
> +  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
> +  (a 1080x1920 5.5 inch panel).
> +
> +allOf:
> +  - $ref: panel-common.yaml#
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - anbernic,panel-vita-pro
> +      - const: anbernic,td4310
> +
> +  reg:
> +    maxItems: 1
> +
> +  vdd-supply:
> +    description: Panel power supply
> +
> +required:
> +  - compatible
> +  - port
> +  - reg
> +  - reset-gpios
> +  - vdd-supply
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +
> +    dsi {
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +
> +        panel at 0 {
> +            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
> +            reg = <0>;
> +            backlight = <&backlight>;
> +            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
> +            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
> +            rotation = <270>;
> +            vdd-supply = <&vdd_lcd>;
> +
> +            port {
> +                panel_in: endpoint {

Drop the label if you respin.
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable

> +                    remote-endpoint = <&dsi_out>;
> +                };
> +            };
> +        };
> +    };
> +
> +...
> -- 
> 2.43.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-rockchip/attachments/20260605/bc07aa8f/attachment.sig>

From conor at kernel.org  Fri Jun  5 09:39:11 2026
From: conor at kernel.org (Conor Dooley)
Date: Fri, 5 Jun 2026 17:39:11 +0100
Subject: [PATCH V5 1/6] dt-bindings: power: supply: sgm41542: document
 sgm41542
In-Reply-To: <20260604220802.119107-2-macroalpha82@gmail.com>
References: <20260604220802.119107-1-macroalpha82@gmail.com>
 <20260604220802.119107-2-macroalpha82@gmail.com>
Message-ID: <20260605-browsing-unhealthy-9fa48d8b91e9@spud>

On Thu, Jun 04, 2026 at 05:07:56PM -0500, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Document the SG Micro sgm41542 battery charger/boost converter.
> The parameters of input-current-limit-microamp and
> input-voltage-limit-microvolt are defined as such since they are in
> common use among multiple bindings currently.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---
>  .../power/supply/sgmicro,sgm41542.yaml        | 104 ++++++++++++++++++
>  1 file changed, 104 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
> 
> diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
> new file mode 100644
> index 000000000000..a97afea83700
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
> @@ -0,0 +1,104 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: SGM41542 Battery Charger
> +
> +description:
> +  The SGMicro SGM41542 is a single cell battery charger/boost controller.
> +
> +maintainers:
> +  - Chris Morgan <macromorgan at hotmail.com>
> +  - Xu Shengfei <xsf at rock-chips.com>
> +
> +allOf:
> +  - $ref: power-supply.yaml#
> +
> +properties:
> +  compatible:
> +    const: sgmicro,sgm41542
> +
> +  input-current-limit-microamp:
> +    description:
> +      Optional value to clamp the maximum input current limit to for
> +      the device. If omitted, the default value for the hardware will
> +      be used (2400000).
> +    minimum: 100000
> +    maximum: 3800000

Instead of the text,
default: 2400000

> +
> +  input-voltage-limit-microvolt:
> +    description:
> +      Optional value to clamp the maximum input voltage limit to for
> +      the device. If omitted, the default value for the hardware will
> +      be used (4500000).
> +    minimum: 3900000
> +    maximum: 12000000

Same here.
pw-bot: changes-requested

> +
> +  interrupts:
> +    maxItems: 1
> +
> +  monitored-battery:
> +    description: |
> +        A phandle to a monitored battery node. Values for the following
> +        are used by the driver and if not present will result in default
> +        values being applied:

I saw the wording "The charger uses the following battery properties"
elsewhere, and I think that's superior to what's here.

I had a quick check and didn't notice other devices that talked about
defaults here. I feel like it's probably a good idea to state in the
binding what the defaults are, so that if u-boot or whatever grows a
support for this hardware that it uses the same ones.

Cheers,
Conor.

> +        constant-charge-current-max-microamp
> +        constant-charge-voltage-max-microvolt
> +        charge-term-current-microamp
> +        precharge-current-microamp
> +
> +  reg:
> +    maxItems: 1
> +
> +  regulators:
> +    type: object
> +    properties:
> +      otg-vbus:
> +        type: object
> +        description: OTG boost regulator
> +        $ref: /schemas/regulator/regulator.yaml
> +        unevaluatedProperties: false
> +    additionalProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/gpio/gpio.h>
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    battery: battery {
> +      compatible = "simple-battery";
> +      constant-charge-current-max-microamp = <10000000>;
> +      constant-charge-voltage-max-microvolt = <4350000>;
> +      precharge-current-microamp = <180000>;
> +      charge-term-current-microamp = <300000>;
> +    };
> +
> +    i2c {
> +      #address-cells = <1>;
> +      #size-cells = <0>;
> +
> +      charger at 3b {
> +        compatible = "sgmicro,sgm41542";
> +        reg = <0x3b>;
> +        input-current-limit-microamp = <3000000>;
> +        input-voltage-limit-microvolt = <4500000>;
> +        interrupt-parent = <&gpio0>;
> +        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
> +        monitored-battery = <&battery>;
> +
> +        regulators {
> +          otg-vbus {
> +            regulator-max-microvolt = <5000000>;
> +            regulator-min-microvolt = <5000000>;
> +          };
> +        };
> +      };
> +    };
> -- 
> 2.43.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-rockchip/attachments/20260605/bbf755ec/attachment.sig>

From sebastian.reichel at collabora.com  Fri Jun  5 09:42:06 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 5 Jun 2026 18:42:06 +0200
Subject: [PATCH v2 05/12] drm/bridge: synopsys: dw-dp: Add follow-up
 bridge support
In-Reply-To: <177918892313.537125.10814687633426590148.b4-review@b4>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-5-d7e7f6bac77f@collabora.com>
 <177918892313.537125.10814687633426590148.b4-review@b4>
Message-ID: <aiL4lUUa9j6_irAz@venus>

Hello Luca,

On Tue, May 19, 2026 at 01:08:43PM +0200, Luca Ceresoli wrote:
> On Fri, 01 May 2026 00:20:32 +0200, Sebastian Reichel <sebastian.reichel at collabora.com> wrote:
> > diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> > index fc4ddb7792d7..ccc55e40e81c 100644
> > --- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> > +++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
> > @@ -2064,6 +2064,20 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
> >  		goto unregister_aux;
> >  	}
> >  
> > +	next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
> 
> devm_drm_of_get_bridge() looks for either a panel or a bridge. Is it
> possible to have a panel connected here?
> 
> If it isn't, then using of_drm_get_bridge_by_endpoint() which has just been
> merged [0] would be much simpler and cleaner.

Technically this should always be connected to the USBDP PHY
on the Rockchip platforms using this IP (RK3588 & RK3576) and
there are no other upstream platforms using this code so far.

Having said that, we do have some upstream DTs, which directly
connect it to a DP connector instead (as the PHY does not yet
expose a DRM bridge, that's being handled in a different series).
But there is no upstream board connecting it to an eDP panel,
so I will switch over to of_drm_get_bridge_by_endpoint().

Thanks for the info.

Greetings,

-- Sebastian

> 
> [0] https://gitlab.freedesktop.org/drm/misc/kernel/-/commit/03d1078112fddd706b2c1e4a7d98cf18700eb5df
> 
> Luca
> 
> -- 
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
> 
-------------- 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-rockchip/attachments/20260605/48e07a80/attachment-0001.sig>

From alchark at flipper.net  Fri Jun  5 09:57:33 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 5 Jun 2026 20:57:33 +0400
Subject: [PATCH RFC v2] drm/rockchip: vop2: Add clock rate mode check
In-Reply-To: <CABjd4Yw_HYpjhrgmonB9FmWV00q=r3yvqnFE4TXEHpM1ZgWOhA@mail.gmail.com>
References: <20260409-vop2-clk-rate-check-v2-1-b207cfc427d7@collabora.com> <CABjd4Yw_HYpjhrgmonB9FmWV00q=r3yvqnFE4TXEHpM1ZgWOhA@mail.gmail.com>
Message-ID: <CAKTNdwE-qYFiNpn1b9Zy=vjf0QO3JXF_ofp=b5x1-n9Q2WaMCg@mail.gmail.com>

On Fri, Jun 5, 2026 at 7:58?PM Alexey Charkov <alchark at gmail.com> wrote:
>
> On Fri, Apr 10, 2026 at 2:37?AM Sebastian Reichel
> <sebastian.reichel at collabora.com> wrote:
> >
> > The display might offer modes, which exceed the maximum clock rate of a
> > video output. This usually happens for displays that offer refresh rates
> > above 60 Hz. This results in no picture (or a broken one) being displayed
> > without manual intervention. Fix this by teaching the driver about the
> > maximum achievable clock rates for each video port.
> >
> > The information about the maximum clock rates for each video channel and
> > the tip about multiple pixels being processed per clock were provided by
> > Andy Yan and roughly checked against the information available in the
> > datasheet (which specifies limits like "2560x1600 at 60Hz with 10-bit"
> > instead of a specific pixel rate).
> >
> > For the video ports supporting a 600 MHz input clock, there is some
> > logic to handle up to 4 pixels in parallel when needed resulting in
> > the extra multiplier.
> >
> > Suggested-by: Andy Yan <andy.yan at rock-chips.com>
> > Link: https://lore.kernel.org/linux-rockchip/1528d788.186b.19d08ed974c.Coremail.andyshrk at 163.com/
> > Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> > ---
> > I've kept the RFC tag, as I'm not sure about the 4x parallel pixel
> > processing. IIUIC all of the video ports with a maximum of 600 MHz
> > input clock support it, considering they can go to 4K @ 120Hz,
> > which is above 1.2GHz while Andy mentioned a max. support clock rate
> > of 600 MHz.
> > ---
> > Changes in v2:
> > - Link to v1: https://lore.kernel.org/r/20260217-vop2-clk-rate-check-v1-1-989b569119ba at collabora.com
> > - based on v7.0-rc7
> > - rename max_clock_rate into max_pixel_clock_rate to distinguish from
> >   input clock
> > - update max clock rates to the numbers provided by Andy Yan with
> >   extra 4x multiplier for 4K 120Hz VPs
> > ---
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c |  3 +++
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  1 +
> >  drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 10 ++++++++++
> >  3 files changed, 14 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > index a195f5c819a2..35a0edda5375 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> > @@ -1434,6 +1434,9 @@ static enum drm_mode_status vop2_crtc_mode_valid(struct drm_crtc *crtc,
> >         if (mode->hdisplay > vp->data->max_output.width)
> >                 return MODE_BAD_HVALUE;
> >
> > +       if (mode->clock > vp->data->max_pixel_clock_rate / 1000)
> > +               return MODE_CLOCK_HIGH;
> > +
> >         return MODE_OK;
> >  }
> >
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> > index 9124191899ba..fd46913f3346 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
> > @@ -225,6 +225,7 @@ struct vop2_video_port_data {
> >         u16 gamma_lut_len;
> >         u16 cubic_lut_len;
> >         struct vop_rect max_output;
> > +       u32 max_pixel_clock_rate;
> >         const u8 pre_scan_max_dly[4];
> >         unsigned int offset;
> >         /**
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> > index f3950e8476a7..6ae3d506c476 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> > @@ -559,18 +559,21 @@ static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
> >                 .gamma_lut_len = 1024,
> >                 .cubic_lut_len = 9 * 9 * 9,
> >                 .max_output = { 4096, 2304 },
> > +               .max_pixel_clock_rate = 600000000U,
> >                 .pre_scan_max_dly = { 69, 53, 53, 42 },
> >                 .offset = 0xc00,
> >         }, {
> >                 .id = 1,
> >                 .gamma_lut_len = 1024,
> >                 .max_output = { 2048, 1536 },
> > +               .max_pixel_clock_rate = 200000000U,
> >                 .pre_scan_max_dly = { 40, 40, 40, 40 },
> >                 .offset = 0xd00,
> >         }, {
> >                 .id = 2,
> >                 .gamma_lut_len = 1024,
> >                 .max_output = { 1920, 1080 },
> > +               .max_pixel_clock_rate = 150000000U,
> >                 .pre_scan_max_dly = { 40, 40, 40, 40 },
> >                 .offset = 0xe00,
> >         },
> > @@ -775,6 +778,7 @@ static const struct vop2_video_port_data rk3576_vop_video_ports[] = {
> >                 .gamma_lut_len = 1024,
> >                 .cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
> >                 .max_output = { 4096, 2304 },
> > +               .max_pixel_clock_rate = 600000000U * 4,
>
> Hi Sebastian,
>
> I've tested it on a bunch of different displays with RK3576 while also
> giving VP0 an unlimited PLL to work with (and also expanding its rates
> table for each of the displays' EDID preferred pixel clocks), and I'm
> pretty sure this should be * 2 here, rather than * 4. That would also
> align with ".pixel_rate = 2" just below.
>
> In its current form, some of the advanced displays with 240 Hz modes
> by default choose modes leading to visual artifacts indicative of
> overclocking strain of the graphics pipeline.
>
> The rest look plausible, so with that change please feel free to include:
>
> Tested-by: Alexey Charkov <alchark at flipper.net> # RK3576

Sorry, wrong mailbox.

Tested-by: Alexey Charkov <alchark at flipper.net> # RK3576

Best regards,
Alexey


From s.pueschel at pengutronix.de  Fri Jun  5 15:06:46 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:46 +0200
Subject: [PATCH 00/17] media: rockchip: rga: Add multi-core support
Message-ID: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>

Add multi-core support to the RGA (Raster Graphic Accelerator) driver
for Rockchip SoCs. This works by scheduling the given work to multiple
identical RGA cores. Previously other identical cores were discarded
while probing with -ENODEV to avoid exposing multiple video devices for
identical cores and breaking the ABI when adding an in-kernel scheduling.

This series targets the RK3588 SoC, which has one RGA2-Enhance core
and two RGA3 cores (see [1] for an overview of the different RGA cores).
The slimmed down RK3576 SoC also features two RGA2-Pro
(also described as RGA2.5) cores, but is currently not supported by
the driver. Tests are done on a Radxa Rock 5T SBC.

The scheduling is done only on a context level, which causes no
increased performance for a single stream (which uses only one mem2mem
context). Therefore at least N parallel stream are necessary to utilize
N cores. This avoids the more complex buffer handling required to avoid
mixing the frame ordering when one core is slightly faster than the
other (e.g. due to memory transfer timings or different clocks).

While the work is based on Detlev Casanova's multi-core series for the
rkvdec driver [2], it differs in two major aspects:

(1) It doesn't directly call v4l2_m2m_job_finish to mark the current job
as finished in the device_run callback. Detlev used this to trick the
m2m framework to directly schedule the next job. This looked like a
dirty hack and had me running into some of it's pitfalls (e.g. the
difference between the v4l2_m2m_buf_done and the newly introduced
v4l2_m2m_buf_done_manual function).
Instead I've dropped the current curr_ctx member of the v4l2_m2m_dev
struct and added a max_parallel_jobs member to specify the maximum
number of parallel jobs. This allows the driver to set it's maximum
number of parallel jobs with the newly introduced
v4l2_m2m_set_max_parallel_jobs function. The RGA driver uses it to set
it's number of parallel jobs to it's number of available cores. The m2m
framework then schedules the first N jobs on it's job queue to the
device_run callback instead of only one.

(2) Instead of attaching an identical RGA core on probe to the first
probed RGA core instance, use component helpers to add all cores as
components to a virtual platform device. This has the advantage of only
creating the video device after all cores have been probed successfully
and tearing it down if one core is being removed (e.g. by the sysfs),
which otherwise could lead to nasty memory bugs. The implementation is
based on the driver of the etnaviv gpu. As the virtual platform device
doesn't has an iommu, we still allocate all relevant drives on the first
core, which shares it's iommu domain with all other cores.

v4l2-compliance results:
    v4l2-compliance 1.32.0, 64 bits, 64-bit time_t
    ...
    	Card type        : rga2
    ...
    Total for rockchip-rga device /dev/video0: 48, Succeeded: 48, Failed: 0, Warnings: 0
    
    v4l2-compliance 1.32.0, 64 bits, 64-bit time_t
    ...
    	Card type        : rga3
    ...
    Total for rockchip-rga device /dev/video1: 48, Succeeded: 48, Failed: 0, Warnings: 0

The DTS and iommu changes at the end are picked out of other next trees
to provide an easy way to actually test the changes with an RGA3 on a
rk3588 SoC. They'll be dropped when they get into media/next.

Patch 1-3 address review comments from my last RGA3 patch series
Patch 4 additional driver cleanup
Patch 5 implements support for parallel jobs in the m2m framework
Patch 6-8 add multi core preparations to the driver
Patch 9-13 rework the driver to use component helpers
Patch 14 puts all cores into the same iommu domain
Patch 15 enables the multi-core support
patch 16-17 just pick patches required for testing

[1] https://codeberg.org/airockchip/librga/src/branch/main/docs/Rockchip_Developer_Guide_RGA_EN.md#design-index
[2] https://lore.kernel.org/linux-media/20260409-rkvdec-multicore-v1-0-62b316abf0f7 at collabora.com/

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
Simon Xue (1):
      iommu/rockchip: disable fetch dte time limit

Sven P?schel (16):
      media: rockchip: rga: zero cmdbuf in shared code
      media: rockchip: rga: add comment about pixel alignment for YUV formats
      media: rockchip: rga: move early return into if condition in vidioc_enum_fmt
      media: rockchip: rga: removed unused regmap member
      media: v4l2-mem2mem: support running multiple jobs in parallel
      media: rockchip: rga:  move power handling to device_run
      media: rockchip: rga: adjust get_version to return the version
      media: rockchip: rga: add rga_core structure
      media: rockchip: rga: use components to manage multiple cores
      media: rockchip: rga: move rockchip_rga allocation to master probe
      media: rockchip: rga: move video device to the master
      media: rockchip: rga: move core initialization from bind to probe
      media: rockchip: rga: bind all cores to the master
      media: rockchip: rga: put all cores into first core iommu domain
      media: rockchip: rga: schedule jobs to multiple cores
      arm64: dts: rockchip: add rga3 dt nodes to rk3588

 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  44 +++
 drivers/iommu/rockchip-iommu.c                |   8 +
 drivers/media/platform/rockchip/rga/rga-buf.c |  16 +-
 drivers/media/platform/rockchip/rga/rga-hw.c  |  40 +-
 drivers/media/platform/rockchip/rga/rga.c     | 501 +++++++++++++++++++-------
 drivers/media/platform/rockchip/rga/rga.h     |  45 ++-
 drivers/media/platform/rockchip/rga/rga3-hw.c |  32 +-
 drivers/media/v4l2-core/v4l2-mem2mem.c        |  89 +++--
 include/media/v4l2-mem2mem.h                  |   3 +
 9 files changed, 541 insertions(+), 237 deletions(-)
---
base-commit: 6a75e3d4f6428b90f398354212e3a2e0172851d6
change-id: 20260602-spu-rga3multicore-ae8c8caf01e9

Best regards,
--  
Sven P?schel <s.pueschel at pengutronix.de>



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:48 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:48 +0200
Subject: [PATCH 02/17] media: rockchip: rga: add comment about pixel
 alignment for YUV formats
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-2-3ec2b15675f7@pengutronix.de>

Add a comment to clarify the use of fixed step_height values for all YUV
formats. While the commit introducing the change already explains the
reasoning, add an explicit comment to improve the visibility of the
reasoning.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index bd0afd33affe4..efe5541078214 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -414,6 +414,16 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 		.step_height = 1,
 	};
 
+	/*
+	 * Technically 4:2:2 YUV formats don't need a step_height of 2.
+	 * But for the RGA3 this is explicitly documented in  section 5.6.3
+	 * of the RK3588 TRM Part 2.
+	 * And the RGA2 vendor driver also checks that the height (and width)
+	 * is aligned to 2 when a YUV format is used.
+	 *
+	 * Therefore be safe and always align width and height to 2
+	 * when a YUV format is used.
+	 */
 	if (v4l2_is_format_yuv(v4l2_format_info(pix_fmt->pixelformat))) {
 		frmsize.step_width = 2;
 		frmsize.step_height = 2;

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:49 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:49 +0200
Subject: [PATCH 03/17] media: rockchip: rga: move early return into if
 condition in vidioc_enum_fmt
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-3-3ec2b15675f7@pengutronix.de>

Instead of a doing an early return when we don't have a capture device,
merge the condition with the following if condition. This improves
readability, as the condition now explicitly contains a check for a
capture device instead of returning when we don't have a capture device.

Also use the V4L2_TYPE_IS_CAPTURE helper and improve the comment.

The early return if was copied from the vivid drivers
vivid_enum_fmt_vid function.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index efe5541078214..8c03422d669cf 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -372,12 +372,14 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f
 	if (ret != 0)
 		return ret;
 
-	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
-	    f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-		return 0;
-
-	/* allow changing the quantization and xfer func for YUV formats */
-	if (v4l2_is_format_yuv(v4l2_format_info(f->pixelformat)))
+	/*
+	 * Allow changing the quantization and ycbcr_enc func for YUV formats
+	 * on the capture side for RGB -> YUV conversions.
+	 *
+	 * These flags are only relevant for capture devices.
+	 */
+	if (V4L2_TYPE_IS_CAPTURE(f->type) &&
+	    v4l2_is_format_yuv(v4l2_format_info(f->pixelformat)))
 		f->flags |= V4L2_FMT_FLAG_CSC_QUANTIZATION |
 			    V4L2_FMT_FLAG_CSC_YCBCR_ENC;
 

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:57 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:57 +0200
Subject: [PATCH 11/17] media: rockchip: rga: move video device to the
 master
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-11-3ec2b15675f7@pengutronix.de>

Move the video device allocation and registration to the master
component bind function in preparation for binding multiple cores
to the master. Moving it to the master bind function allows to
only register the v4l2 device when all cores have been successfully
bound to the master device. This also causes the video device to be
bound against the master platform device instead of a specific core.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 96 ++++++++++++++++---------------
 1 file changed, 50 insertions(+), 46 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 11912bf5b6906..952377ae467f5 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -743,7 +743,6 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct rockchip_rga *rga = data;
 	struct rga_core *core;
-	struct video_device *vfd;
 	int ret = 0;
 	int irq;
 
@@ -789,33 +788,11 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 		goto err_put_clk;
 	}
 
-	ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
-	if (ret)
-		goto err_put_clk;
-	vfd = video_device_alloc();
-	if (!vfd) {
-		v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
-		ret = -ENOMEM;
-		goto unreg_v4l2_dev;
-	}
-	*vfd = rga_videodev;
-	vfd->lock = &rga->mutex;
-	vfd->v4l2_dev = &rga->v4l2_dev;
-
-	video_set_drvdata(vfd, rga);
-	rga->vfd = vfd;
-
 	platform_set_drvdata(pdev, core);
-	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
-	if (IS_ERR(rga->m2m_dev)) {
-		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
-		ret = PTR_ERR(rga->m2m_dev);
-		goto rel_vdev;
-	}
 
 	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0)
-		goto rel_m2m;
+		goto err_put_clk;
 
 	rga->version = rga->hw->get_version(core);
 
@@ -824,23 +801,8 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 
 	pm_runtime_put(core->dev);
 
-	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
-	if (ret) {
-		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
-		goto rel_m2m;
-	}
-
-	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
-		  vfd->name, video_device_node_name(vfd));
-
 	return 0;
 
-rel_m2m:
-	v4l2_m2m_release(rga->m2m_dev);
-rel_vdev:
-	video_device_release(vfd);
-unreg_v4l2_dev:
-	v4l2_device_unregister(&rga->v4l2_dev);
 err_put_clk:
 	pm_runtime_disable(core->dev);
 
@@ -851,13 +813,6 @@ static void rga_core_unbind(struct device *dev, struct device *master,
 			    void *data)
 {
 	struct rga_core *core = dev_get_drvdata(dev);
-	struct rockchip_rga *rga = core->rga;
-
-	v4l2_info(&rga->v4l2_dev, "Removing\n");
-
-	v4l2_m2m_release(rga->m2m_dev);
-	video_unregister_device(rga->vfd);
-	v4l2_device_unregister(&rga->v4l2_dev);
 
 	pm_runtime_disable(core->dev);
 }
@@ -937,6 +892,7 @@ static struct platform_driver rga_core_pdrv = {
 static int rga_bind(struct device *dev)
 {
 	struct rockchip_rga *rga = dev_get_drvdata(dev);
+	struct video_device *vfd;
 	int ret;
 
 	ret = component_bind_all(dev, rga);
@@ -945,11 +901,59 @@ static int rga_bind(struct device *dev)
 		return ret;
 	}
 
+	ret = v4l2_device_register(dev, &rga->v4l2_dev);
+	if (ret)
+		return ret;
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_v4l2_dev;
+	}
+	*vfd = rga_videodev;
+	vfd->lock = &rga->mutex;
+	vfd->v4l2_dev = &rga->v4l2_dev;
+
+	video_set_drvdata(vfd, rga);
+	rga->vfd = vfd;
+
+	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
+	if (IS_ERR(rga->m2m_dev)) {
+		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
+		ret = PTR_ERR(rga->m2m_dev);
+		goto rel_vdev;
+	}
+
+	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
+	if (ret) {
+		v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
+		goto rel_m2m;
+	}
+
+	v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
 	return 0;
+
+rel_m2m:
+	v4l2_m2m_release(rga->m2m_dev);
+rel_vdev:
+	video_device_release(vfd);
+unreg_v4l2_dev:
+	v4l2_device_unregister(&rga->v4l2_dev);
+	return ret;
 }
 
 static void rga_unbind(struct device *dev)
 {
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
+
+	v4l2_info(&rga->v4l2_dev, "Removing\n");
+
+	v4l2_m2m_release(rga->m2m_dev);
+	video_unregister_device(rga->vfd);
+	v4l2_device_unregister(&rga->v4l2_dev);
+
 	component_unbind_all(dev, NULL);
 }
 

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:58 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:58 +0200
Subject: [PATCH 12/17] media: rockchip: rga: move core initialization from
 bind to probe
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-12-3ec2b15675f7@pengutronix.de>

Move the core initialization from the core binding function to the core
probing function. This better matches the actual sequence, where the
core probe initializes most things and the bind function just binds the
core to the actual rga struct from the master device.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 83 ++++++++++++++++---------------
 1 file changed, 42 insertions(+), 41 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 952377ae467f5..0413b8518dfc8 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -740,21 +740,49 @@ static int rga_parse_dt(struct rga_core *core)
 
 static int rga_core_bind(struct device *dev, struct device *master, void *data)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	struct rockchip_rga *rga = data;
+	struct rga_core *core = dev_get_drvdata(dev);
+	int ret = 0;
+
+	core->rga = rga;
+
+	ret = pm_runtime_resume_and_get(core->dev);
+	if (ret < 0)
+		return ret;
+
+	rga->version = rga->hw->get_version(core);
+
+	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
+		  rga->version.major, rga->version.minor);
+
+	pm_runtime_put(core->dev);
+
+	rga->cores[0] = core;
+
+	return 0;
+}
+
+static const struct component_ops rga_core_ops = {
+	.bind = rga_core_bind,
+};
+
+static int rga_core_probe(struct platform_device *pdev)
+{
 	struct rga_core *core;
+	const struct rga_hw *hw;
 	int ret = 0;
 	int irq;
 
 	if (!pdev->dev.of_node)
 		return -ENODEV;
 
+	hw = of_device_get_match_data(&pdev->dev);
+	if (!hw)
+		return dev_err_probe(&pdev->dev, -ENODEV, "failed to get match data\n");
+
 	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
-	core->rga = rga;
 	core->dev = &pdev->dev;
 
-	rga->cores[0] = core;
-
 	ret = rga_parse_dt(core);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "Unable to parse OF data\n");
@@ -775,7 +803,7 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 	}
 
 	ret = devm_request_irq(core->dev, irq, rga_isr,
-			       rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
+			       hw->has_internal_iommu ? 0 : IRQF_SHARED,
 			       dev_name(core->dev), core);
 	if (ret < 0) {
 		dev_err(core->dev, "failed to request irq\n");
@@ -790,42 +818,6 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 
 	platform_set_drvdata(pdev, core);
 
-	ret = pm_runtime_resume_and_get(core->dev);
-	if (ret < 0)
-		goto err_put_clk;
-
-	rga->version = rga->hw->get_version(core);
-
-	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
-		  rga->version.major, rga->version.minor);
-
-	pm_runtime_put(core->dev);
-
-	return 0;
-
-err_put_clk:
-	pm_runtime_disable(core->dev);
-
-	return ret;
-}
-
-static void rga_core_unbind(struct device *dev, struct device *master,
-			    void *data)
-{
-	struct rga_core *core = dev_get_drvdata(dev);
-
-	pm_runtime_disable(core->dev);
-}
-
-static const struct component_ops rga_core_ops = {
-	.bind = rga_core_bind,
-	.unbind = rga_core_unbind,
-};
-
-static int rga_core_probe(struct platform_device *pdev)
-{
-	int ret = 0;
-
 	ret = component_add(&pdev->dev, &rga_core_ops);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register component: %d", ret);
@@ -833,11 +825,20 @@ static int rga_core_probe(struct platform_device *pdev)
 	}
 
 	return 0;
+
+err_put_clk:
+	pm_runtime_disable(core->dev);
+
+	return ret;
 }
 
 static void rga_core_remove(struct platform_device *pdev)
 {
+	struct rga_core *core = platform_get_drvdata(pdev);
+
 	component_del(&pdev->dev, &rga_core_ops);
+
+	pm_runtime_disable(core->dev);
 }
 
 static int __maybe_unused rga_runtime_suspend(struct device *dev)

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:59 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:59 +0200
Subject: [PATCH 13/17] media: rockchip: rga: bind all cores to the master
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-13-3ec2b15675f7@pengutronix.de>

Bind all core components to the master component. Previously only the
first core has been added to the master device to avoid creating
multiple video devices. As the video device creation has been moved to
the master component, it allows us to bind all cores without creating
additional video devices.

We expect that all cores to report the same version number, as we only
add cores with the same compatible value. This is important, as  we
setup the command buffer before actually scheduling the work to a
specific core. Therefore adjusting command buffers depending on the
version register only works when all cores have the same value.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 22 +++++++++++-----------
 drivers/media/platform/rockchip/rga/rga.h |  1 +
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0413b8518dfc8..6add6c510c127 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -742,6 +742,7 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 {
 	struct rockchip_rga *rga = data;
 	struct rga_core *core = dev_get_drvdata(dev);
+	struct rockchip_rga_version version;
 	int ret = 0;
 
 	core->rga = rga;
@@ -750,14 +751,21 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 	if (ret < 0)
 		return ret;
 
-	rga->version = rga->hw->get_version(core);
+	version = rga->hw->get_version(core);
 
 	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
-		  rga->version.major, rga->version.minor);
+		  version.major, version.minor);
+
+	if (rga->num_cores) {
+		/* we are not the first core, expect that we have the same version */
+		if (rga->version.major != version.major || rga->version.minor != version.minor)
+			v4l2_warn(&rga->v4l2_dev, "Detected multi-core setup with different core versions!\n");
+	} else
+		rga->version = version;
 
 	pm_runtime_put(core->dev);
 
-	rga->cores[0] = core;
+	rga->cores[rga->num_cores++] = core;
 
 	return 0;
 }
@@ -983,14 +991,6 @@ static int rga_probe(struct platform_device *pdev)
 		component_match_add_release(dev, &match, component_release_of,
 					    component_compare_of, core_node);
 		num_cores++;
-
-		/*
-		 * As multi core is not implemented yet,
-		 * break out of the loop to only have one core per rockchip_rga struct.
-		 * Also put the node, which otherwise would've been done by the loop iteration.
-		 */
-		of_node_put(core_node);
-		break;
 	}
 
 	if (!match)
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index fcf1ef7d2029f..6237436b984eb 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -88,6 +88,7 @@ struct rockchip_rga {
 
 	const struct rga_hw *hw;
 
+	u8 num_cores;
 	struct rga_core *cores[];
 };
 

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:50 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:50 +0200
Subject: [PATCH 04/17] media: rockchip: rga: removed unused regmap member
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-4-3ec2b15675f7@pengutronix.de>

The grf member variable is never accessed or written by the RGA driver.
Therefore drop it from the rockchip_rga struct.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 2b4f5694375a4..0e62337f8dd38 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -71,7 +71,6 @@ struct rockchip_rga {
 	struct video_device *vfd;
 
 	struct device *dev;
-	struct regmap *grf;
 	void __iomem *regs;
 	struct clk_bulk_data *clks;
 	int num_clks;

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:07:00 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:07:00 +0200
Subject: [PATCH 14/17] media: rockchip: rga: put all cores into first core
 iommu domain
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-14-3ec2b15675f7@pengutronix.de>

Put all cores into the iommu domain of the first core to allow them to
be used by any core. All buffers accessed by the hardware are allocated
on the first core, as the scheduling to a specific core is done after
the allocation. Therefore put all cores into the same domain to have the
same iommu mapping on all cores.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 6add6c510c127..9cebb461b3fd2 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -10,6 +10,7 @@
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
+#include <linux/iommu.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
@@ -757,6 +758,19 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 		  version.major, version.minor);
 
 	if (rga->num_cores) {
+		/* Attach to the first cores iommu */
+		struct iommu_domain *domain = iommu_get_domain_for_dev(rga->cores[0]->dev);
+
+		if (IS_ERR(domain)) {
+			dev_err(core->dev, "Couldn't get domain of the first core\n");
+			return PTR_ERR(domain);
+		}
+		ret = iommu_attach_device(domain, core->dev);
+		if (ret) {
+			dev_err(core->dev, "Couldn't attach to the domain of the first core\n");
+			return ret;
+		}
+
 		/* we are not the first core, expect that we have the same version */
 		if (rga->version.major != version.major || rga->version.minor != version.minor)
 			v4l2_warn(&rga->v4l2_dev, "Detected multi-core setup with different core versions!\n");

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:55 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:55 +0200
Subject: [PATCH 09/17] media: rockchip: rga: use components to manage
 multiple cores
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-9-3ec2b15675f7@pengutronix.de>

Use component helpers to manage multiple cores and aggregate them into a
central master device. This gives us a dedicated master device and
ensures that all cores (components) are properly set up before creating
the video device.

This commit only sets up a basic component device. Instead of the
rga_disable_multicore function only the first core is added to the
master device. To avoid the secondary core creating an additional video
device the whole core probe implementation is moved to the bind method,
which is only called when the core is bound to a master device.

The implementation is based on the etnaviv gpu driver, which also groups
multiple gpu cores under a single etnaviv master device.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 256 +++++++++++++++++++++++-------
 1 file changed, 202 insertions(+), 54 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 15d095a1d1973..178f45b8da940 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -5,6 +5,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
@@ -737,51 +738,9 @@ static int rga_parse_dt(struct rga_core *core)
 	return 0;
 }
 
-/*
- * Some SoCs, like RK3588 have multiple identical RGA3 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 main core can be used to cluster all cores together.
- */
-static int rga_disable_multicore(struct device *dev)
-{
-	struct device_node *node = NULL;
-	const char *compatible;
-	bool is_main_core;
-	int ret;
-
-	/* Intentionally ignores the fallback strings */
-	ret = of_property_read_string(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_main_core = (dev->of_node == node);
-
-	of_node_put(node);
-
-	if (!is_main_core) {
-		dev_info(dev, "missing multi-core support, ignoring this instance\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int rga_probe(struct platform_device *pdev)
+static int rga_core_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	struct rockchip_rga *rga;
 	struct rga_core *core;
 	struct video_device *vfd;
@@ -791,10 +750,6 @@ 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) + 1 * sizeof(*rga->cores), GFP_KERNEL);
 	if (!rga)
 		return -ENOMEM;
@@ -903,9 +858,10 @@ static int rga_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static void rga_remove(struct platform_device *pdev)
+static void rga_core_unbind(struct device *dev, struct device *master,
+			    void *data)
 {
-	struct rga_core *core = platform_get_drvdata(pdev);
+	struct rga_core *core = dev_get_drvdata(dev);
 	struct rockchip_rga *rga = core->rga;
 
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
@@ -917,6 +873,29 @@ static void rga_remove(struct platform_device *pdev)
 	pm_runtime_disable(core->dev);
 }
 
+static const struct component_ops rga_core_ops = {
+	.bind = rga_core_bind,
+	.unbind = rga_core_unbind,
+};
+
+static int rga_core_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	ret = component_add(&pdev->dev, &rga_core_ops);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register component: %d", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void rga_core_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &rga_core_ops);
+}
+
 static int __maybe_unused rga_runtime_suspend(struct device *dev)
 {
 	struct rga_core *core = dev_get_drvdata(dev);
@@ -933,7 +912,7 @@ static int __maybe_unused rga_runtime_resume(struct device *dev)
 	return clk_bulk_prepare_enable(core->num_clks, core->clks);
 }
 
-static const struct dev_pm_ops rga_pm = {
+static const struct dev_pm_ops rga_core_pm = {
 	SET_RUNTIME_PM_OPS(rga_runtime_suspend,
 			   rga_runtime_resume, NULL)
 };
@@ -956,17 +935,186 @@ static const struct of_device_id rockchip_rga_match[] = {
 
 MODULE_DEVICE_TABLE(of, rockchip_rga_match);
 
+static struct platform_driver rga_core_pdrv = {
+	.probe = rga_core_probe,
+	.remove = rga_core_remove,
+	.driver = {
+		.name = RGA_NAME "-core",
+		.pm = &rga_core_pm,
+		.of_match_table = rockchip_rga_match,
+	},
+};
+
+static int rga_bind(struct device *dev)
+{
+	int ret;
+
+	ret = component_bind_all(dev, NULL);
+	if (ret) {
+		dev_err(dev, "component bind failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void rga_unbind(struct device *dev)
+{
+	component_unbind_all(dev, NULL);
+}
+
+struct component_master_ops rga_master_ops = {
+	.bind = rga_bind,
+	.unbind = rga_unbind,
+};
+
+static int rga_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match_desc = pdev->dev.platform_data;
+	struct device *dev = &pdev->dev;
+	struct component_match *match = NULL;
+	struct device_node *core_node;
+
+	if (!match_desc)
+		return dev_err_probe(dev, -ENODEV, "missing platform data\n");
+
+	for_each_compatible_node(core_node, NULL, match_desc->compatible) {
+		if (!of_device_is_available(core_node))
+			continue;
+
+		of_node_get(core_node);
+		component_match_add_release(dev, &match, component_release_of,
+					    component_compare_of, core_node);
+
+		/*
+		 * As multi core is not implemented yet,
+		 * break out of the loop to only have one core per rockchip_rga struct.
+		 * Also put the node, which otherwise would've been done by the loop iteration.
+		 */
+		of_node_put(core_node);
+		break;
+	}
+
+	if (!match)
+		return dev_err_probe(
+			dev, -ENODEV,
+			"no matching available component devices found\n");
+
+	return component_master_add_with_match(dev, &rga_master_ops, match);
+}
+
+static void rga_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &rga_master_ops);
+}
+
 static struct platform_driver rga_pdrv = {
 	.probe = rga_probe,
 	.remove = rga_remove,
 	.driver = {
 		.name = RGA_NAME,
-		.pm = &rga_pm,
-		.of_match_table = rockchip_rga_match,
 	},
 };
 
-module_platform_driver(rga_pdrv);
+static bool rga_of_has_available_node(const char *compat)
+{
+	struct device_node *node;
+
+	for_each_compatible_node(node, NULL, compat) {
+		if (of_device_is_available(node)) {
+			of_node_put(node);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static int rga_create_platform_device(struct platform_device **ppdev,
+				      const struct of_device_id *match)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	pdev = platform_device_alloc(match->compatible, PLATFORM_DEVID_NONE);
+	if (!pdev)
+		return -ENOMEM;
+
+	ret = platform_device_add_data(pdev, match, sizeof(*match));
+	if (ret)
+		goto free_platform_device;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto free_platform_device;
+
+	ret = device_driver_attach(&rga_pdrv.driver, &pdev->dev);
+	if (ret)
+		goto del_platform_device;
+
+	*ppdev = pdev;
+
+	return 0;
+
+del_platform_device:
+	platform_device_del(pdev);
+free_platform_device:
+	platform_device_put(pdev);
+	return ret;
+}
+
+static struct platform_device *master_pdevs[ARRAY_SIZE(rockchip_rga_match) - 1];
+
+static int __init rga_init(void)
+{
+	int ret;
+	unsigned int i;
+
+	ret = platform_driver_register(&rga_core_pdrv);
+	if (ret != 0)
+		return ret;
+
+	ret = platform_driver_register(&rga_pdrv);
+	if (ret != 0)
+		goto unregister_core_driver;
+
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		if (!rga_of_has_available_node(
+			    rockchip_rga_match[i].compatible))
+			continue;
+
+		ret = rga_create_platform_device(&master_pdevs[i],
+						 &rockchip_rga_match[i]);
+		if (ret)
+			goto unregister_platform_devices;
+	}
+
+	return 0;
+
+unregister_platform_devices:
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		platform_device_unregister(master_pdevs[i]);
+		master_pdevs[i] = NULL;
+	}
+	platform_driver_unregister(&rga_pdrv);
+unregister_core_driver:
+	platform_driver_unregister(&rga_core_pdrv);
+	return ret;
+}
+module_init(rga_init);
+
+static void __exit rga_exit(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(master_pdevs); i++) {
+		platform_device_unregister(master_pdevs[i]);
+		master_pdevs[i] = NULL;
+	}
+	platform_driver_unregister(&rga_pdrv);
+	platform_driver_unregister(&rga_core_pdrv);
+}
+module_exit(rga_exit);
 
 MODULE_AUTHOR("Jacob Chen <jacob-chen at iotwrt.com>");
 MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit");

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:47 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:47 +0200
Subject: [PATCH 01/17] media: rockchip: rga: zero cmdbuf in shared code
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-1-3ec2b15675f7@pengutronix.de>

Zero the command buffer (cmdbuf) in the shared code instead of the
individual RGA2/RGA3 implementations. Besides centralizing the memset
operation this also uses the cmdbuf_size member for the memset size,
which is also used as the size for the actual allocation.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c  | 2 --
 drivers/media/platform/rockchip/rga/rga.c     | 1 +
 drivers/media/platform/rockchip/rga/rga.h     | 3 +++
 drivers/media/platform/rockchip/rga/rga3-hw.c | 2 --
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index be1bc8ddbd03b..4d7b0a03820a1 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -443,8 +443,6 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 
 static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
 {
-	memset(ctx->cmdbuf_virt, 0, RGA_CMDBUF_SIZE);
-
 	rga_cmd_set_mode(ctx);
 	rga_cmd_set_trans_info(ctx);
 }
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index b3cb6bf8eb863..bd0afd33affe4 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -41,6 +41,7 @@ static void device_run(void *prv)
 	spin_lock_irqsave(&rga->ctrl_lock, flags);
 	if (ctx->cmdbuf_dirty) {
 		ctx->cmdbuf_dirty = false;
+		memset(ctx->cmdbuf_virt, 0, rga->hw->cmdbuf_size);
 		rga->hw->setup_cmdbuf(ctx);
 	}
 	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index bd431534d0d39..2b4f5694375a4 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -152,6 +152,9 @@ struct rga_hw {
 	u8 stride_alignment;
 	u8 features;
 
+	/*
+	 * Requires that the cmdbuf is already zeroed.
+	 */
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);
 	void (*start)(struct rockchip_rga *rga,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
index ca1c268303dd4..72741e1faccff 100644
--- a/drivers/media/platform/rockchip/rga/rga3-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -261,8 +261,6 @@ static void rga3_cmd_set_wr_format(struct rga_ctx *ctx)
 
 static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
 {
-	memset(ctx->cmdbuf_virt, 0, RGA3_CMDBUF_SIZE);
-
 	rga3_cmd_set_win0_format(ctx);
 	rga3_cmd_set_trans_info(ctx);
 	rga3_cmd_set_wr_format(ctx);

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:54 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:54 +0200
Subject: [PATCH 08/17] media: rockchip: rga: add rga_core structure
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-8-3ec2b15675f7@pengutronix.de>

Add a rga_core structure to separate the core specific data from the
m2m device. This is done in preparation for multi-core support, where
multiple identical cores are exposed as a single m2m device to the
user-space.

Allocation related calls are explicitly done on the first core, as the
scheduling decisions will be made on demand after the buffers have been
allocated and filled.

In preparation of storing the rockchip_rga struct on a dedicated master
platform device, the rga_core struct is allocated on it's own and only a
pointer is saved in the rockchip_rga struct.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-buf.c |   4 +-
 drivers/media/platform/rockchip/rga/rga-hw.c  |  32 ++++----
 drivers/media/platform/rockchip/rga/rga.c     | 104 ++++++++++++++------------
 drivers/media/platform/rockchip/rga/rga.h     |  39 +++++-----
 drivers/media/platform/rockchip/rga/rga3-hw.c |  24 +++---
 5 files changed, 108 insertions(+), 95 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 3f7c3c68e0cb8..47a8d5a4500a3 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -93,7 +93,7 @@ static int rga_buf_init(struct vb2_buffer *vb)
 	n_desc = DIV_ROUND_UP(size, PAGE_SIZE);
 
 	rbuf->n_desc = n_desc;
-	rbuf->dma_desc = dma_alloc_coherent(rga->dev,
+	rbuf->dma_desc = dma_alloc_coherent(rga->cores[0]->dev,
 					    rbuf->n_desc * sizeof(*rbuf->dma_desc),
 					    &rbuf->dma_desc_pa, GFP_KERNEL);
 	if (!rbuf->dma_desc)
@@ -191,7 +191,7 @@ static void rga_buf_cleanup(struct vb2_buffer *vb)
 	if (!rga_has_internal_iommu(rga))
 		return;
 
-	dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
+	dma_free_coherent(rga->cores[0]->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
 			  rbuf->dma_desc, rbuf->dma_desc_pa);
 }
 
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 190104f3b2954..9a5da4e1716ca 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -417,10 +417,10 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx)
 	dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
 }
 
-static void rga_cmd_set(struct rga_ctx *ctx,
+static void rga_cmd_set(struct rga_core *core,
 			struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
 {
-	struct rockchip_rga *rga = ctx->rga;
+	struct rga_ctx *ctx = core->curr;
 
 	rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
 	/*
@@ -434,10 +434,10 @@ static void rga_cmd_set(struct rga_ctx *ctx,
 	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);
+	rga_write(core, RGA_CMD_BASE, ctx->cmdbuf_phy);
 
 	/* sync CMD buf for RGA */
-	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+	dma_sync_single_for_device(core->rga->cores[0]->dev, ctx->cmdbuf_phy,
 				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 }
 
@@ -447,36 +447,34 @@ static void rga_hw_setup_cmdbuf(struct rga_ctx *ctx)
 	rga_cmd_set_trans_info(ctx);
 }
 
-static void rga_hw_start(struct rockchip_rga *rga,
+static void rga_hw_start(struct rga_core *core,
 			 struct rga_vb_buffer *src,  struct rga_vb_buffer *dst)
 {
-	struct rga_ctx *ctx = rga->curr;
-
-	rga_cmd_set(ctx, src, dst);
+	rga_cmd_set(core, src, dst);
 
-	rga_write(rga, RGA_SYS_CTRL, 0x00);
+	rga_write(core, RGA_SYS_CTRL, 0x00);
 
-	rga_write(rga, RGA_SYS_CTRL, 0x22);
+	rga_write(core, RGA_SYS_CTRL, 0x22);
 
-	rga_write(rga, RGA_INT, 0x600);
+	rga_write(core, RGA_INT, 0x600);
 
-	rga_write(rga, RGA_CMD_CTRL, 0x1);
+	rga_write(core, RGA_CMD_CTRL, 0x1);
 }
 
-static bool rga_handle_irq(struct rockchip_rga *rga)
+static bool rga_handle_irq(struct rga_core *core)
 {
 	int intr;
 
-	intr = rga_read(rga, RGA_INT) & 0xf;
+	intr = rga_read(core, RGA_INT) & 0xf;
 
-	rga_mod(rga, RGA_INT, intr << 4, 0xf << 4);
+	rga_mod(core, RGA_INT, intr << 4, 0xf << 4);
 
 	return intr & RGA_INT_COMMAND_FINISHED;
 }
 
-static struct rockchip_rga_version rga_get_version(struct rockchip_rga *rga)
+static struct rockchip_rga_version rga_get_version(struct rga_core *core)
 {
-	u32 version = rga_read(rga, RGA_VERSION_INFO);
+	u32 version = rga_read(core, RGA_VERSION_INFO);
 
 	return (struct rockchip_rga_version) {
 		.major = (version >> 24) & 0xFF,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index b8edd3596c919..15d095a1d1973 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
 #include <linux/sched.h>
@@ -35,11 +36,12 @@ static void device_run(void *prv)
 {
 	struct rga_ctx *ctx = prv;
 	struct rockchip_rga *rga = ctx->rga;
+	struct rga_core *core = rga->cores[0];
 	struct vb2_v4l2_buffer *src, *dst;
 	unsigned long flags;
 	int ret;
 
-	ret = pm_runtime_resume_and_get(rga->dev);
+	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0) {
 		v4l2_m2m_buf_done_and_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx,
 						 VB2_BUF_STATE_ERROR);
@@ -54,27 +56,28 @@ static void device_run(void *prv)
 	}
 	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
 
-	rga->curr = ctx;
+	core->curr = ctx;
 
 	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	src->sequence = ctx->osequence++;
 
 	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(core, vb_to_rga(src), vb_to_rga(dst));
 }
 
 static irqreturn_t rga_isr(int irq, void *prv)
 {
-	struct rockchip_rga *rga = prv;
+	struct rga_core *core = prv;
+	struct rockchip_rga *rga = core->rga;
 
-	if (rga->hw->handle_irq(rga)) {
+	if (rga->hw->handle_irq(core)) {
 		struct vb2_v4l2_buffer *src, *dst;
-		struct rga_ctx *ctx = rga->curr;
+		struct rga_ctx *ctx = core->curr;
 
 		WARN_ON(!ctx);
 
-		rga->curr = NULL;
+		core->curr = NULL;
 
 		src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
 		dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
@@ -90,7 +93,7 @@ static irqreturn_t rga_isr(int irq, void *prv)
 		v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
 		v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
 
-		pm_runtime_put_autosuspend(rga->dev);
+		pm_runtime_put_autosuspend(core->dev);
 	}
 
 	return IRQ_HANDLED;
@@ -118,7 +121,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	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;
+	src_vq->dev = ctx->rga->cores[0]->dev;
 
 	ret = vb2_queue_init(src_vq);
 	if (ret)
@@ -136,7 +139,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
 	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;
+	dst_vq->dev = ctx->rga->cores[0]->dev;
 
 	return vb2_queue_init(dst_vq);
 }
@@ -275,7 +278,7 @@ static int rga_open(struct file *file)
 		return -ENOMEM;
 
 	/* Create CMD buffer */
-	ctx->cmdbuf_virt = dma_alloc_attrs(rga->dev, rga->hw->cmdbuf_size,
+	ctx->cmdbuf_virt = dma_alloc_attrs(rga->cores[0]->dev, rga->hw->cmdbuf_size,
 					   &ctx->cmdbuf_phy, GFP_KERNEL,
 					   DMA_ATTR_WRITE_COMBINE);
 	if (!ctx->cmdbuf_virt) {
@@ -322,7 +325,7 @@ static int rga_open(struct file *file)
 unlock_mutex:
 	mutex_unlock(&rga->mutex);
 rel_cmdbuf:
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+	dma_free_attrs(rga->cores[0]->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
 		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 rel_ctx:
 	kfree(ctx);
@@ -342,7 +345,7 @@ static int rga_release(struct file *file)
 	v4l2_fh_del(&ctx->fh, file);
 	v4l2_fh_exit(&ctx->fh);
 
-	dma_free_attrs(rga->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
+	dma_free_attrs(rga->cores[0]->dev, rga->hw->cmdbuf_size, ctx->cmdbuf_virt,
 		       ctx->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
 
 	kfree(ctx);
@@ -689,26 +692,26 @@ static const struct video_device rga_videodev = {
 	.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
 };
 
-static int rga_parse_dt(struct rockchip_rga *rga)
+static int rga_parse_dt(struct rga_core *core)
 {
 	struct reset_control *core_rst, *axi_rst, *ahb_rst;
 	int ret;
 
-	core_rst = devm_reset_control_get(rga->dev, "core");
+	core_rst = devm_reset_control_get(core->dev, "core");
 	if (IS_ERR(core_rst)) {
-		dev_err(rga->dev, "failed to get core reset controller\n");
+		dev_err(core->dev, "failed to get core reset controller\n");
 		return PTR_ERR(core_rst);
 	}
 
-	axi_rst = devm_reset_control_get(rga->dev, "axi");
+	axi_rst = devm_reset_control_get(core->dev, "axi");
 	if (IS_ERR(axi_rst)) {
-		dev_err(rga->dev, "failed to get axi reset controller\n");
+		dev_err(core->dev, "failed to get axi reset controller\n");
 		return PTR_ERR(axi_rst);
 	}
 
-	ahb_rst = devm_reset_control_get(rga->dev, "ahb");
+	ahb_rst = devm_reset_control_get(core->dev, "ahb");
 	if (IS_ERR(ahb_rst)) {
-		dev_err(rga->dev, "failed to get ahb reset controller\n");
+		dev_err(core->dev, "failed to get ahb reset controller\n");
 		return PTR_ERR(ahb_rst);
 	}
 
@@ -724,12 +727,12 @@ static int rga_parse_dt(struct rockchip_rga *rga)
 	udelay(1);
 	reset_control_deassert(ahb_rst);
 
-	ret = devm_clk_bulk_get_all(rga->dev, &rga->clks);
+	ret = devm_clk_bulk_get_all(core->dev, &core->clks);
 	if (ret < 0) {
-		dev_err(rga->dev, "failed to get clocks\n");
+		dev_err(core->dev, "failed to get clocks\n");
 		return ret;
 	}
-	rga->num_clks = ret;
+	core->num_clks = ret;
 
 	return 0;
 }
@@ -780,6 +783,7 @@ static int rga_disable_multicore(struct device *dev)
 static int rga_probe(struct platform_device *pdev)
 {
 	struct rockchip_rga *rga;
+	struct rga_core *core;
 	struct video_device *vfd;
 	int ret = 0;
 	int irq;
@@ -791,7 +795,7 @@ static int rga_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL);
+	rga = devm_kzalloc(&pdev->dev, sizeof(*rga) + 1 * sizeof(*rga->cores), GFP_KERNEL);
 	if (!rga)
 		return -ENOMEM;
 
@@ -799,20 +803,25 @@ static int rga_probe(struct platform_device *pdev)
 	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);
 
-	ret = rga_parse_dt(rga);
+	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
+	core->rga = rga;
+	core->dev = &pdev->dev;
+
+	rga->cores[0] = core;
+
+	ret = rga_parse_dt(core);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "Unable to parse OF data\n");
 
-	pm_runtime_set_autosuspend_delay(rga->dev, 50);
-	pm_runtime_enable(rga->dev);
+	pm_runtime_set_autosuspend_delay(core->dev, 50);
+	pm_runtime_enable(core->dev);
 
-	rga->regs = devm_platform_ioremap_resource(pdev, 0);
-	if (IS_ERR(rga->regs)) {
-		ret = PTR_ERR(rga->regs);
+	core->regs = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(core->regs)) {
+		ret = PTR_ERR(core->regs);
 		goto err_put_clk;
 	}
 
@@ -822,17 +831,17 @@ static int rga_probe(struct platform_device *pdev)
 		goto err_put_clk;
 	}
 
-	ret = devm_request_irq(rga->dev, irq, rga_isr,
+	ret = devm_request_irq(core->dev, irq, rga_isr,
 			       rga_has_internal_iommu(rga) ? 0 : IRQF_SHARED,
-			       dev_name(rga->dev), rga);
+			       dev_name(core->dev), core);
 	if (ret < 0) {
-		dev_err(rga->dev, "failed to request irq\n");
+		dev_err(core->dev, "failed to request irq\n");
 		goto err_put_clk;
 	}
 
-	ret = dma_set_mask_and_coherent(rga->dev, DMA_BIT_MASK(32));
+	ret = dma_set_mask_and_coherent(core->dev, DMA_BIT_MASK(32));
 	if (ret) {
-		dev_err(rga->dev, "32-bit DMA not supported");
+		dev_err(core->dev, "32-bit DMA not supported");
 		goto err_put_clk;
 	}
 
@@ -852,7 +861,7 @@ static int rga_probe(struct platform_device *pdev)
 	video_set_drvdata(vfd, rga);
 	rga->vfd = vfd;
 
-	platform_set_drvdata(pdev, rga);
+	platform_set_drvdata(pdev, core);
 	rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops);
 	if (IS_ERR(rga->m2m_dev)) {
 		v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n");
@@ -860,16 +869,16 @@ static int rga_probe(struct platform_device *pdev)
 		goto rel_vdev;
 	}
 
-	ret = pm_runtime_resume_and_get(rga->dev);
+	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0)
 		goto rel_m2m;
 
-	rga->version = rga->hw->get_version(rga);
+	rga->version = rga->hw->get_version(core);
 
 	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
 		  rga->version.major, rga->version.minor);
 
-	pm_runtime_put(rga->dev);
+	pm_runtime_put(core->dev);
 
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
@@ -889,14 +898,15 @@ static int rga_probe(struct platform_device *pdev)
 unreg_v4l2_dev:
 	v4l2_device_unregister(&rga->v4l2_dev);
 err_put_clk:
-	pm_runtime_disable(rga->dev);
+	pm_runtime_disable(core->dev);
 
 	return ret;
 }
 
 static void rga_remove(struct platform_device *pdev)
 {
-	struct rockchip_rga *rga = platform_get_drvdata(pdev);
+	struct rga_core *core = platform_get_drvdata(pdev);
+	struct rockchip_rga *rga = core->rga;
 
 	v4l2_info(&rga->v4l2_dev, "Removing\n");
 
@@ -904,23 +914,23 @@ static void rga_remove(struct platform_device *pdev)
 	video_unregister_device(rga->vfd);
 	v4l2_device_unregister(&rga->v4l2_dev);
 
-	pm_runtime_disable(rga->dev);
+	pm_runtime_disable(core->dev);
 }
 
 static int __maybe_unused rga_runtime_suspend(struct device *dev)
 {
-	struct rockchip_rga *rga = dev_get_drvdata(dev);
+	struct rga_core *core = dev_get_drvdata(dev);
 
-	clk_bulk_disable_unprepare(rga->num_clks, rga->clks);
+	clk_bulk_disable_unprepare(core->num_clks, core->clks);
 
 	return 0;
 }
 
 static int __maybe_unused rga_runtime_resume(struct device *dev)
 {
-	struct rockchip_rga *rga = dev_get_drvdata(dev);
+	struct rga_core *core = dev_get_drvdata(dev);
 
-	return clk_bulk_prepare_enable(rga->num_clks, rga->clks);
+	return clk_bulk_prepare_enable(core->num_clks, core->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 0e854cdf739f4..fcf1ef7d2029f 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -14,7 +14,6 @@
 #include <media/v4l2-device.h>
 
 #define RGA_NAME "rockchip-rga"
-
 #define DEFAULT_WIDTH 100
 #define DEFAULT_HEIGHT 100
 
@@ -36,6 +35,16 @@ struct rockchip_rga_version {
 	u32 minor;
 };
 
+struct rga_core {
+	struct device *dev;
+	void __iomem *regs;
+	struct clk_bulk_data *clks;
+	int num_clks;
+
+	struct rockchip_rga *rga;
+	struct rga_ctx *curr;
+};
+
 struct rga_ctx {
 	struct v4l2_fh fh;
 	struct rockchip_rga *rga;
@@ -70,10 +79,6 @@ struct rockchip_rga {
 	struct v4l2_m2m_dev *m2m_dev;
 	struct video_device *vfd;
 
-	struct device *dev;
-	void __iomem *regs;
-	struct clk_bulk_data *clks;
-	int num_clks;
 	struct rockchip_rga_version version;
 
 	/* vfd lock */
@@ -81,9 +86,9 @@ struct rockchip_rga {
 	/* ctrl parm lock */
 	spinlock_t ctrl_lock;
 
-	struct rga_ctx *curr;
-
 	const struct rga_hw *hw;
+
+	struct rga_core *cores[];
 };
 
 struct rga_addrs {
@@ -119,22 +124,22 @@ int rga_check_scaling(const struct rga_hw *hw, const struct v4l2_rect *crop_in,
 extern const struct vb2_ops rga_qops;
 
 /* RGA Hardware */
-static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
+static inline void rga_write(struct rga_core *core, u32 reg, u32 value)
 {
-	writel(value, rga->regs + reg);
+	writel(value, core->regs + reg);
 };
 
-static inline u32 rga_read(struct rockchip_rga *rga, u32 reg)
+static inline u32 rga_read(struct rga_core *core, u32 reg)
 {
-	return readl(rga->regs + reg);
+	return readl(core->regs + reg);
 };
 
-static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
+static inline void rga_mod(struct rga_core *core, u32 reg, u32 val, u32 mask)
 {
-	u32 temp = rga_read(rga, reg) & ~(mask);
+	u32 temp = rga_read(core, reg) & ~(mask);
 
 	temp |= val & mask;
-	rga_write(rga, reg, temp);
+	rga_write(core, reg, temp);
 };
 
 #define RGA_FEATURE_FLIP	BIT(0)
@@ -155,10 +160,10 @@ struct rga_hw {
 	 * Requires that the cmdbuf is already zeroed.
 	 */
 	void (*setup_cmdbuf)(struct rga_ctx *ctx);
-	void (*start)(struct rockchip_rga *rga,
+	void (*start)(struct rga_core *core,
 		      struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
-	bool (*handle_irq)(struct rockchip_rga *rga);
-	struct rockchip_rga_version (*get_version)(struct rockchip_rga *rga);
+	bool (*handle_irq)(struct rga_core *core);
+	struct rockchip_rga_version (*get_version)(struct rga_core *core);
 	void *(*adjust_and_map_format)(struct rga_ctx *ctx,
 				       struct v4l2_pix_format_mplane *format,
 				       bool is_output);
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
index 3469523a5ecad..f7e4bc8c6ff21 100644
--- a/drivers/media/platform/rockchip/rga/rga3-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -266,42 +266,42 @@ static void rga3_hw_setup_cmdbuf(struct rga_ctx *ctx)
 	rga3_cmd_set_wr_format(ctx);
 }
 
-static void rga3_hw_start(struct rockchip_rga *rga,
+static void rga3_hw_start(struct rga_core *core,
 			  struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
 {
-	struct rga_ctx *ctx = rga->curr;
+	struct rga_ctx *ctx = core->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);
+	rga_write(core, RGA3_CMD_ADDR, ctx->cmdbuf_phy);
 
 	/* sync CMD buf for RGA */
-	dma_sync_single_for_device(rga->dev, ctx->cmdbuf_phy,
+	dma_sync_single_for_device(core->rga->cores[0]->dev, ctx->cmdbuf_phy,
 				   PAGE_SIZE, DMA_BIDIRECTIONAL);
 
 	/* set to master mode and start the conversion */
-	rga_write(rga, RGA3_SYS_CTRL,
+	rga_write(core, 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,
+	rga_write(core, RGA3_INT_EN, FIELD_PREP(RGA3_INT_FRM_DONE, 1));
+	rga_write(core, RGA3_CMD_CTRL,
 		  FIELD_PREP(RGA3_CMD_LINE_START_PULSE, 1));
 }
 
-static bool rga3_handle_irq(struct rockchip_rga *rga)
+static bool rga3_handle_irq(struct rga_core *core)
 {
 	u32 intr;
 
-	intr = rga_read(rga, RGA3_INT_RAW);
+	intr = rga_read(core, RGA3_INT_RAW);
 	/* clear all interrupts */
-	rga_write(rga, RGA3_INT_CLR, intr);
+	rga_write(core, RGA3_INT_CLR, intr);
 
 	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
 }
 
-static struct rockchip_rga_version rga3_get_version(struct rockchip_rga *rga)
+static struct rockchip_rga_version rga3_get_version(struct rga_core *core)
 {
-	u32 version = rga_read(rga, RGA3_VERSION_NUM);
+	u32 version = rga_read(core, RGA3_VERSION_NUM);
 
 	return (struct rockchip_rga_version) {
 		.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version),

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:51 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:51 +0200
Subject: [PATCH 05/17] media: v4l2-mem2mem: support running multiple jobs
 in parallel
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-5-3ec2b15675f7@pengutronix.de>

Add support for running multiple jobs in parallel for SoCs containing
multiple identical devices. An example is the Rockchip RK3588 SoC,
which contains two identical RGA3 devices. Therefore it is desirable to
have the kernel schedule the work across all available devices and only
expose one video device to the userspace.

Previously the curr_ctx member of a v4l2_m2m_dev was used to track the
currently running context. But the currently running context will always
be at the top of the job_queue. As the TRANS_RUNNING flag can be used to
check if the queue head is already running, the curr_ctx member can be
completely dropped

To avoid queueing too many parallel jobs, the
v4l2_m2m_set_max_parallel_jobs method is added. It allows a driver
to set the number of parallel jobs and avoids calling device_run when
the given number of jobs is already running. This is set to 1 by default
to prevent parallel job runs. Drivers with the need and support for
scheduling jobs can adjust this value accordingly.

Note that this change doesn't allow a context to be used multiple times
in parallel. So a single stream won't be able to utilize multiple devices
at once, but N streams can utilize up to N devices. This is caused by the
fact that a context is not added multiple times to the job_list and also
holds the job_flags to distinguish if it's currently running.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/v4l2-core/v4l2-mem2mem.c | 89 ++++++++++++++++++++++------------
 include/media/v4l2-mem2mem.h           |  3 ++
 2 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index a65cbb124cfe0..14ac9c85803d1 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -84,16 +84,15 @@ static const char * const m2m_entity_name[] = {
  *			v4l2_m2m_unregister_media_controller().
  * @intf_devnode:	&struct media_intf devnode pointer with the interface
  *			with controls the M2M device.
- * @curr_ctx:		currently running instance
  * @job_queue:		instances queued to run
  * @job_spinlock:	protects job_queue
  * @job_work:		worker to run queued jobs.
  * @job_queue_flags:	flags of the queue status, %QUEUE_PAUSED.
+ * @max_parallel_jobs:	max job_queue instances number marked as running
  * @m2m_ops:		driver callbacks
  * @kref:		device reference count
  */
 struct v4l2_m2m_dev {
-	struct v4l2_m2m_ctx	*curr_ctx;
 #ifdef CONFIG_MEDIA_CONTROLLER
 	struct media_entity	*source;
 	struct media_pad	source_pad;
@@ -108,6 +107,7 @@ struct v4l2_m2m_dev {
 	spinlock_t		job_spinlock;
 	struct work_struct	job_work;
 	unsigned long		job_queue_flags;
+	u32			max_parallel_jobs;
 
 	const struct v4l2_m2m_ops *m2m_ops;
 
@@ -123,6 +123,12 @@ static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx,
 		return &m2m_ctx->cap_q_ctx;
 }
 
+void v4l2_m2m_set_max_parallel_jobs(struct v4l2_m2m_dev *m2m_dev,
+				    u32 max_parallel_jobs)
+{
+	m2m_dev->max_parallel_jobs = max_parallel_jobs;
+}
+
 struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx,
 				       enum v4l2_buf_type type)
 {
@@ -229,14 +235,22 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove_by_idx);
 void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev)
 {
 	unsigned long flags;
-	void *ret = NULL;
+	struct v4l2_m2m_ctx *first_ctx;
 
 	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-	if (m2m_dev->curr_ctx)
-		ret = m2m_dev->curr_ctx->priv;
+	if (list_empty(&m2m_dev->job_queue)) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		return NULL;
+	}
+
+	first_ctx = list_first_entry(&m2m_dev->job_queue,
+				     struct v4l2_m2m_ctx, queue);
 	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
 
-	return ret;
+	if (first_ctx->job_flags & TRANS_RUNNING)
+		return first_ctx->priv;
+	else
+		return NULL;
 }
 EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
 
@@ -252,13 +266,11 @@ EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
 static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
 {
 	unsigned long flags;
+	struct v4l2_m2m_ctx *ctx;
+	struct v4l2_m2m_ctx *chosen_ctx = NULL;
+	u32 running_jobs = 0;
 
 	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-	if (NULL != m2m_dev->curr_ctx) {
-		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-		dprintk("Another instance is running, won't run now\n");
-		return;
-	}
 
 	if (list_empty(&m2m_dev->job_queue)) {
 		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
@@ -272,13 +284,30 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
 		return;
 	}
 
-	m2m_dev->curr_ctx = list_first_entry(&m2m_dev->job_queue,
-				   struct v4l2_m2m_ctx, queue);
-	m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING;
+	list_for_each_entry(ctx, &m2m_dev->job_queue, queue) {
+		if (!(ctx->job_flags & TRANS_RUNNING)) {
+			chosen_ctx = ctx;
+			break;
+		}
+
+		running_jobs++;
+	}
+	if (running_jobs >= m2m_dev->max_parallel_jobs) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("Maximum number of parallel jobs reached\n");
+		return;
+	}
+	if (!chosen_ctx) {
+		spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+		dprintk("All jobs already running\n");
+		return;
+	}
+
+	chosen_ctx->job_flags |= TRANS_RUNNING;
 	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
 
-	dprintk("Running job on m2m_ctx: %p\n", m2m_dev->curr_ctx);
-	m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv);
+	dprintk("Running job on m2m_ctx: %p\n", chosen_ctx);
+	m2m_dev->m2m_ops->device_run(chosen_ctx->priv);
 }
 
 /*
@@ -469,15 +498,14 @@ static void v4l2_m2m_schedule_next_job(struct v4l2_m2m_dev *m2m_dev,
 static bool _v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
 				 struct v4l2_m2m_ctx *m2m_ctx)
 {
-	if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) {
+	if (!m2m_ctx || !(m2m_ctx->job_flags & TRANS_RUNNING)) {
 		dprintk("Called by an instance not currently running\n");
 		return false;
 	}
 
-	list_del(&m2m_dev->curr_ctx->queue);
-	m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
-	wake_up(&m2m_dev->curr_ctx->finished);
-	m2m_dev->curr_ctx = NULL;
+	list_del(&m2m_ctx->queue);
+	m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+	wake_up(&m2m_ctx->finished);
 	return true;
 }
 
@@ -544,16 +572,19 @@ EXPORT_SYMBOL(v4l2_m2m_buf_done_and_job_finish);
 void v4l2_m2m_suspend(struct v4l2_m2m_dev *m2m_dev)
 {
 	unsigned long flags;
-	struct v4l2_m2m_ctx *curr_ctx;
+	struct v4l2_m2m_ctx *ctx;
+	struct v4l2_m2m_ctx *ctx_safe;
 
 	spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
 	m2m_dev->job_queue_flags |= QUEUE_PAUSED;
-	curr_ctx = m2m_dev->curr_ctx;
 	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
 
-	if (curr_ctx)
-		wait_event(curr_ctx->finished,
-			   !(curr_ctx->job_flags & TRANS_RUNNING));
+	list_for_each_entry_safe(ctx, ctx_safe, &m2m_dev->job_queue, queue) {
+		if (!(ctx->job_flags & TRANS_RUNNING))
+			break;
+
+		wait_event(ctx->finished, !(ctx->job_flags & TRANS_RUNNING));
+	}
 }
 EXPORT_SYMBOL(v4l2_m2m_suspend);
 
@@ -896,10 +927,8 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 	q_ctx->num_rdy = 0;
 	spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
 
-	if (m2m_dev->curr_ctx == m2m_ctx) {
-		m2m_dev->curr_ctx = NULL;
+	if (m2m_ctx->job_flags & TRANS_RUNNING)
 		wake_up(&m2m_ctx->finished);
-	}
 	spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
 
 	return 0;
@@ -1194,12 +1223,12 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
 	if (!m2m_dev)
 		return ERR_PTR(-ENOMEM);
 
-	m2m_dev->curr_ctx = NULL;
 	m2m_dev->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);
+	m2m_dev->max_parallel_jobs = 1;
 
 	return m2m_dev;
 }
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index 31de25d792b98..e6177d0eaf637 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -594,6 +594,9 @@ static inline void v4l2_m2m_set_dst_buffered(struct v4l2_m2m_ctx *m2m_ctx,
 	m2m_ctx->cap_q_ctx.buffered = buffered;
 }
 
+void v4l2_m2m_set_max_parallel_jobs(struct v4l2_m2m_dev *m2m_dev,
+				    u32 max_parallel_jobs);
+
 /**
  * v4l2_m2m_ctx_release() - release m2m context
  *

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:56 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:56 +0200
Subject: [PATCH 10/17] media: rockchip: rga: move rockchip_rga allocation
 to master probe
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-10-3ec2b15675f7@pengutronix.de>

Move the rockchip_rga struct allocation to the master component probe
function in preparation of enabling all cores. This also adjusts the
allocation to use the actual number of cores found in the of tree
instead of being fixed to one core.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 32 ++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 178f45b8da940..11912bf5b6906 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -741,7 +741,7 @@ static int rga_parse_dt(struct rga_core *core)
 static int rga_core_bind(struct device *dev, struct device *master, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
-	struct rockchip_rga *rga;
+	struct rockchip_rga *rga = data;
 	struct rga_core *core;
 	struct video_device *vfd;
 	int ret = 0;
@@ -750,17 +750,6 @@ static int rga_core_bind(struct device *dev, struct device *master, void *data)
 	if (!pdev->dev.of_node)
 		return -ENODEV;
 
-	rga = devm_kzalloc(&pdev->dev, sizeof(*rga) + 1 * sizeof(*rga->cores), GFP_KERNEL);
-	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");
-
-	spin_lock_init(&rga->ctrl_lock);
-	mutex_init(&rga->mutex);
-
 	core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
 	core->rga = rga;
 	core->dev = &pdev->dev;
@@ -947,9 +936,10 @@ static struct platform_driver rga_core_pdrv = {
 
 static int rga_bind(struct device *dev)
 {
+	struct rockchip_rga *rga = dev_get_drvdata(dev);
 	int ret;
 
-	ret = component_bind_all(dev, NULL);
+	ret = component_bind_all(dev, rga);
 	if (ret) {
 		dev_err(dev, "component bind failed\n");
 		return ret;
@@ -974,6 +964,8 @@ static int rga_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct component_match *match = NULL;
 	struct device_node *core_node;
+	struct rockchip_rga *rga;
+	u8 num_cores = 0;
 
 	if (!match_desc)
 		return dev_err_probe(dev, -ENODEV, "missing platform data\n");
@@ -985,6 +977,7 @@ static int rga_probe(struct platform_device *pdev)
 		of_node_get(core_node);
 		component_match_add_release(dev, &match, component_release_of,
 					    component_compare_of, core_node);
+		num_cores++;
 
 		/*
 		 * As multi core is not implemented yet,
@@ -1000,6 +993,19 @@ static int rga_probe(struct platform_device *pdev)
 			dev, -ENODEV,
 			"no matching available component devices found\n");
 
+	rga = devm_kzalloc(dev, sizeof(*rga) + num_cores * sizeof(*rga->cores), GFP_KERNEL);
+	if (!rga)
+		return -ENOMEM;
+
+	rga->hw = match_desc->data;
+	if (!rga->hw)
+		return dev_err_probe(dev, -ENODEV, "failed to get match data\n");
+
+	spin_lock_init(&rga->ctrl_lock);
+	mutex_init(&rga->mutex);
+
+	dev_set_drvdata(dev, rga);
+
 	return component_master_add_with_match(dev, &rga_master_ops, match);
 }
 

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:07:01 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:07:01 +0200
Subject: [PATCH 15/17] media: rockchip: rga: schedule jobs to multiple
 cores
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-15-3ec2b15675f7@pengutronix.de>

Schedule jobs to multiple cores to utilize all RGA cores. To avoid race
conditions when selecting the next free core a dedicated spinlock is added.

Note that this doesn't increase the max frame rate of a single
stream, as a context will wait for the job to finish before starting
the next device_run call.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga.c | 22 +++++++++++++++++++---
 drivers/media/platform/rockchip/rga/rga.h |  1 +
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 9cebb461b3fd2..f00b7f99f2521 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -38,15 +38,31 @@ static void device_run(void *prv)
 {
 	struct rga_ctx *ctx = prv;
 	struct rockchip_rga *rga = ctx->rga;
-	struct rga_core *core = rga->cores[0];
+	struct rga_core *core = NULL;
 	struct vb2_v4l2_buffer *src, *dst;
 	unsigned long flags;
 	int ret;
+	unsigned int i;
+
+	spin_lock_irqsave(&rga->cores_lock, flags);
+	for (i = 0; i < rga->num_cores; i++) {
+		if (!rga->cores[i]->curr) {
+			core = rga->cores[i];
+			core->curr = ctx;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&rga->cores_lock, flags);
+
+	WARN_ONCE(!core, "No free core although max parallel jobs matches the core count!\n");
+	if (!core)
+		return;
 
 	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0) {
 		v4l2_m2m_buf_done_and_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx,
 						 VB2_BUF_STATE_ERROR);
+		core->curr = NULL;
 		return;
 	}
 
@@ -58,8 +74,6 @@ static void device_run(void *prv)
 	}
 	spin_unlock_irqrestore(&rga->ctrl_lock, flags);
 
-	core->curr = ctx;
-
 	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
 	src->sequence = ctx->osequence++;
 
@@ -946,6 +960,7 @@ static int rga_bind(struct device *dev)
 		ret = PTR_ERR(rga->m2m_dev);
 		goto rel_vdev;
 	}
+	v4l2_m2m_set_max_parallel_jobs(rga->m2m_dev, rga->num_cores);
 
 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
 	if (ret) {
@@ -1021,6 +1036,7 @@ static int rga_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, -ENODEV, "failed to get match data\n");
 
 	spin_lock_init(&rga->ctrl_lock);
+	spin_lock_init(&rga->cores_lock);
 	mutex_init(&rga->mutex);
 
 	dev_set_drvdata(dev, rga);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 6237436b984eb..c0dfacdb6f212 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -85,6 +85,7 @@ struct rockchip_rga {
 	struct mutex mutex;
 	/* ctrl parm lock */
 	spinlock_t ctrl_lock;
+	spinlock_t cores_lock;
 
 	const struct rga_hw *hw;
 

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:53 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:53 +0200
Subject: [PATCH 07/17] media: rockchip: rga: adjust get_version to return
 the version
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-7-3ec2b15675f7@pengutronix.de>

Adjust get_version to return the version instead of directly updating it
in the rockchip_rga structure. This is done in preparation for a
multi-core support to check that cores with the same compatible share the
same version.

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
---
 drivers/media/platform/rockchip/rga/rga-hw.c  | 10 +++++++---
 drivers/media/platform/rockchip/rga/rga.c     |  2 +-
 drivers/media/platform/rockchip/rga/rga.h     |  2 +-
 drivers/media/platform/rockchip/rga/rga3-hw.c |  8 +++++---
 4 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index 4d7b0a03820a1..190104f3b2954 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -474,10 +474,14 @@ static bool rga_handle_irq(struct rockchip_rga *rga)
 	return intr & RGA_INT_COMMAND_FINISHED;
 }
 
-static void rga_get_version(struct rockchip_rga *rga)
+static struct rockchip_rga_version 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;
+	u32 version = rga_read(rga, RGA_VERSION_INFO);
+
+	return (struct rockchip_rga_version) {
+		.major = (version >> 24) & 0xFF,
+		.minor = (version >> 20) & 0x0F,
+	};
 }
 
 static struct rga_fmt formats[] = {
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0eff558d7f133..b8edd3596c919 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -864,7 +864,7 @@ static int rga_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto rel_m2m;
 
-	rga->hw->get_version(rga);
+	rga->version = rga->hw->get_version(rga);
 
 	v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n",
 		  rga->version.major, rga->version.minor);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 0e62337f8dd38..0e854cdf739f4 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -158,7 +158,7 @@ struct rga_hw {
 	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);
+	struct rockchip_rga_version (*get_version)(struct rockchip_rga *rga);
 	void *(*adjust_and_map_format)(struct rga_ctx *ctx,
 				       struct v4l2_pix_format_mplane *format,
 				       bool is_output);
diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c
index 72741e1faccff..3469523a5ecad 100644
--- a/drivers/media/platform/rockchip/rga/rga3-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga3-hw.c
@@ -299,12 +299,14 @@ static bool rga3_handle_irq(struct rockchip_rga *rga)
 	return FIELD_GET(RGA3_INT_FRM_DONE, intr);
 }
 
-static void rga3_get_version(struct rockchip_rga *rga)
+static struct rockchip_rga_version 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);
+	return (struct rockchip_rga_version) {
+		.major = FIELD_GET(RGA3_VERSION_NUM_MAJOR, version),
+		.minor = FIELD_GET(RGA3_VERSION_NUM_MINOR, version),
+	};
 }
 
 static struct rga3_fmt rga3_formats[] = {

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:07:03 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:07:03 +0200
Subject: [PATCH 17/17] iommu/rockchip: disable fetch dte time limit
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-17-3ec2b15675f7@pengutronix.de>

From: Simon Xue <xxm at rock-chips.com>

Disable the Bit 31 of the AUTO_GATING iommu register, as it causes
hangups with the RGA3 (Raster Graphics Acceleration 3) peripheral.
The RGA3 register description of the TRM already states that the bit
must be set to 1. The vendor kernel sets the bit unconditionally to
1 to fix VOP (Video Output Processor) screen black issues. This patch
squashes the 2 vendor kernel commits with the following commit messages:

Master fetch data and cpu update page table may work in parallel, may
have the following procedure:

	master                  cpu
	fetch dte               update page tabl
	        |                       |
	(make dte invalid)  <-  zap iotlb entry
	        |                       |
	fetch dte again
	(make dte invalid)  <-  zap iotlb entry
	        |                       |
	fetch dte again
	(make dte invalid)  <-  zap iotlb entry
	        |                       |
	fetch dte again
	(make iommu block)  <-  zap iotlb entry

New iommu version has the above bug, if fetch dte consecutively four
times, then it will be blocked. Fortunately, we can set bit 31 of
register MMU_AUTO_GATING to 1 to make it work as old version which does
not have this issue.

This issue only appears on RV1126 so far, so make a workaround dedicated
to "rockchip,rv1126" machine type.

iommu/rockchip: fix vop blocked and screen black on RK356X and RK3588

RK3568 and RK3588 has the same issue as RV1126/RV1109 that caused by
dte fetch time limit, So we can set BIT(31) of register 0x24 default
to 1 as a workaround.

Signed-off-by: Simon Xue <xxm at rock-chips.com>
Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
Acked-by: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Joerg Roedel <joerg.roedel at amd.com>
---
(cherry picked from commit 8d4346ecd4950ae08cc76a6de327c264e846758c)

picked from the next branch of
https://git.kernel.org/pub/scm/linux/kernel/git/iommu/linux.git
for a convenient usage of the patches.
---
 drivers/iommu/rockchip-iommu.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 0013cf196c573..87ae036d64145 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -76,6 +76,8 @@
 #define SPAGE_ORDER 12
 #define SPAGE_SIZE (1 << SPAGE_ORDER)
 
+#define DISABLE_FETCH_DTE_TIME_LIMIT BIT(31)
+
  /*
   * Support mapping any size that fits in one page table:
   *   4 KiB to 4 MiB
@@ -930,6 +932,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
 	struct iommu_domain *domain = iommu->domain;
 	struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
 	int ret, i;
+	u32 auto_gate;
 
 	ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
 	if (ret)
@@ -948,6 +951,11 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
 			       rk_ops->mk_dtentries(rk_domain->dt_dma));
 		rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
 		rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
+
+		/* Workaround for iommu blocked, BIT(31) default to 1 */
+		auto_gate = rk_iommu_read(iommu->bases[i], RK_MMU_AUTO_GATING);
+		auto_gate |= DISABLE_FETCH_DTE_TIME_LIMIT;
+		rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, auto_gate);
 	}
 
 	ret = rk_iommu_enable_paging(iommu);

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:07:02 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:07:02 +0200
Subject: [PATCH 16/17] arm64: dts: rockchip: add rga3 dt nodes to rk3588
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-16-3ec2b15675f7@pengutronix.de>

Add devicetree nodes for the RGA3 (Raster Graphics Acceleration 3)
peripheral in the RK3588.

The existing rga node refers to the RGA2-Enhanced peripheral. The RK3588
contains one RGA2-Enhanced 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 (RGA2 allows up to 16)

Signed-off-by: Sven P?schel <s.pueschel at pengutronix.de>
Link: https://patch.msgid.link/20260521-spu-rga3-v7-28-3f33e8c7145f at pengutronix.de
Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
(cherry picked from commit 25ee898961a2c661e4cd72bc98f0060f1cd11222)
picked from linux-next to have the necessary RGA3 nodes available.
---
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 44 +++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
index 4fb8888c281c8..a4f44af512375 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi
@@ -1262,6 +1262,50 @@ vpu121_mmu: iommu at fdb50800 {
 		#iommu-cells = <0>;
 	};
 
+	rga3_core0: rga at fdb60000 {
+		compatible = "rockchip,rk3588-rga3";
+		reg = <0x0 0xfdb60000 0x0 0x200>;
+		interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH 0>;
+		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>;
+		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>;
+	};
+
 	rga: rga at fdb80000 {
 		compatible = "rockchip,rk3588-rga", "rockchip,rk3288-rga";
 		reg = <0x0 0xfdb80000 0x0 0x180>;

-- 
2.54.0



From s.pueschel at pengutronix.de  Fri Jun  5 15:06:52 2026
From: s.pueschel at pengutronix.de (=?utf-8?q?Sven_P=C3=BCschel?=)
Date: Sat, 06 Jun 2026 00:06:52 +0200
Subject: [PATCH 06/17] media: rockchip: rga: move power handling to
 device_run
In-Reply-To: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
References: <20260606-spu-rga3multicore-v1-0-3ec2b15675f7@pengutronix.de>
Message-ID: <20260606-spu-rga3multicore-v1-6-3ec2b15675f7@pengutronix.de>

Move the power handling to the device_run function in preparation for
enabling multiple cores. This allows to power the only the necessary cores
instead of powering all available cores.

As the decision on which core the given job is executed will be done in
device_run, we can only power to correct core there.

To avoid unpowering the core in a streaming state switch to autosuspend.
This avoids powering down the core when the next frame is scheduled in
the next 50ms. The timeout maps to a framerate of 20fps, which should be
pretty uncommon in a normal video stream.

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.c     | 11 +++++++++++
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index c0ea6003336bf..3f7c3c68e0cb8 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -242,14 +242,6 @@ static int rga_buf_prepare_streaming(struct vb2_queue *q)
 static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
 {
 	struct rga_ctx *ctx = vb2_get_drv_priv(q);
-	struct rockchip_rga *rga = ctx->rga;
-	int ret;
-
-	ret = pm_runtime_resume_and_get(rga->dev);
-	if (ret < 0) {
-		rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
-		return ret;
-	}
 
 	if (V4L2_TYPE_IS_OUTPUT(q->type))
 		ctx->osequence = 0;
@@ -261,11 +253,7 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
 
 static void rga_buf_stop_streaming(struct vb2_queue *q)
 {
-	struct rga_ctx *ctx = vb2_get_drv_priv(q);
-	struct rockchip_rga *rga = ctx->rga;
-
 	rga_buf_return_buffers(q, VB2_BUF_STATE_ERROR);
-	pm_runtime_put(rga->dev);
 }
 
 const struct vb2_ops rga_qops = {
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 8c03422d669cf..0eff558d7f133 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -37,6 +37,14 @@ static void device_run(void *prv)
 	struct rockchip_rga *rga = ctx->rga;
 	struct vb2_v4l2_buffer *src, *dst;
 	unsigned long flags;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(rga->dev);
+	if (ret < 0) {
+		v4l2_m2m_buf_done_and_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx,
+						 VB2_BUF_STATE_ERROR);
+		return;
+	}
 
 	spin_lock_irqsave(&rga->ctrl_lock, flags);
 	if (ctx->cmdbuf_dirty) {
@@ -81,6 +89,8 @@ static irqreturn_t rga_isr(int irq, void *prv)
 		v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
 		v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
 		v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
+
+		pm_runtime_put_autosuspend(rga->dev);
 	}
 
 	return IRQ_HANDLED;
@@ -797,6 +807,7 @@ static int rga_probe(struct platform_device *pdev)
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret, "Unable to parse OF data\n");
 
+	pm_runtime_set_autosuspend_delay(rga->dev, 50);
 	pm_runtime_enable(rga->dev);
 
 	rga->regs = devm_platform_ioremap_resource(pdev, 0);

-- 
2.54.0



From heiko at sntech.de  Fri Jun  5 15:18:53 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 06 Jun 2026 00:18:53 +0200
Subject: [GIT PULL] Rockchip dts64 changes for 7.2 #2
Message-ID: <21578066.fAMKPKieAE@phil>

Hi soc maintainers,

please find below some more Rockchip DT changes for the merge-window
for 7.2 .

The most interesting addition is of course basic camera support
on RK3588 which enables unfiltered camera capture (i.e. without
postprocessing for whitebalance etc)


Please pull.
Thanks
Heiko


The following changes since commit eb24b60553e0692cbbec2863ca31d2a56bff098d:

  arm64: dts: rockchip: Add watchdog node for RK3528 (2026-05-07 13:27:53 +0200)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v7.2-rockchip-dts64-2

for you to fetch changes up to 8545eda00fdf3d7e17933ce0f706d005b1bad42d:

  arm64: dts: rockchip: Fix vcc_sdio regulator max voltage on Pinebook Pro (2026-06-02 22:47:18 +0200)

----------------------------------------------------------------
We've got basic camera support on RK3588!

New peripherals RK3588 vicap plus camera addition to some boards,
RK3528 USB and USB enablement on some boards, RGA3 support on RK3588.
Missing EL2 virtual timer interrupt added to RK3588.

Some more added peripherals for the Khadas Edge 2L board.

----------------------------------------------------------------
Chen-Yu Tsai (2):
      arm64: dts: rockchip: Fix EEPROM compatible on rk3399-nanopi-r4s-enterprise
      arm64: dts: rockchip: Disable removed devices from rk3399-nanopi-r4s

Chukun Pan (1):
      arm64: dts: rockchip: enable adc button for Radxa E25

Gray Huang (2):
      arm64: dts: rockchip: Enable USB for Khadas Edge 2L
      arm64: dts: rockchip: Add Bluetooth support for Khadas Edge 2L

Hugo Osvaldo Barrera (1):
      arm64: dts: rockchip: Fix vcc_sdio regulator max voltage on Pinebook Pro

Jonas Karlman (5):
      arm64: dts: rockchip: Add USB nodes for RK3528
      arm64: dts: rockchip: Enable USB 2.0 ports on Radxa E20C
      arm64: dts: rockchip: Enable USB ports on Radxa ROCK 2A/2F
      arm64: dts: rockchip: Enable USB 2.0 ports on ArmSoM Sige1
      arm64: dts: rockchip: Enable USB 2.0 ports on NanoPi Zero2

Marc Zyngier (1):
      arm64: dts: rockchip: Add EL2 virtual timer interrupt

Michael Riesch (3):
      arm64: dts: rockchip: add vicap node to rk3588
      arm64: dts: rockchip: add radxa camera 4k on rock 5b+ cam0
      arm64: dts: rockchip: add radxa camera 4k on rock 5b+ cam1

Sven P?schel (1):
      arm64: dts: rockchip: add rga3 dt nodes to rk3588

 arch/arm64/boot/dts/rockchip/Makefile              |   7 ++
 .../dts/rockchip/rk3399-nanopi-r4s-enterprise.dts  |   2 +-
 .../arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi |  68 +++++++++++
 .../boot/dts/rockchip/rk3399-pinebook-pro.dts      |   2 +-
 .../boot/dts/rockchip/rk3528-armsom-sige1.dts      |  25 ++++
 .../boot/dts/rockchip/rk3528-nanopi-zero2.dts      |  29 +++++
 arch/arm64/boot/dts/rockchip/rk3528-radxa-e20c.dts |  60 +++++++++
 arch/arm64/boot/dts/rockchip/rk3528-rock-2.dtsi    |  17 +++
 arch/arm64/boot/dts/rockchip/rk3528-rock-2a.dts    |  11 ++
 arch/arm64/boot/dts/rockchip/rk3528-rock-2f.dts    |  12 ++
 arch/arm64/boot/dts/rockchip/rk3528.dtsi           |  80 ++++++++++++
 arch/arm64/boot/dts/rockchip/rk3568-radxa-e25.dts  |  14 +++
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi      |   3 +-
 .../boot/dts/rockchip/rk3576-khadas-edge-2l.dts    |  82 +++++++++++++
 arch/arm64/boot/dts/rockchip/rk3588-base.dtsi      | 135 +++++++++++++++++++++
 .../rk3588-rock-5b-plus-radxa-cam4k-cam0.dtso      |  99 +++++++++++++++
 .../rk3588-rock-5b-plus-radxa-cam4k-cam1.dtso      |  99 +++++++++++++++
 17 files changed, 742 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus-radxa-cam4k-cam0.dtso
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-rock-5b-plus-radxa-cam4k-cam1.dtso





From ricardo at pardini.net  Fri Jun  5 22:03:59 2026
From: ricardo at pardini.net (Ricardo Pardini)
Date: Sat, 6 Jun 2026 07:03:59 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <b7cc8eba-ff6e-417d-8e74-b3bb24e08a26@gmail.com>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
 <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
 <b7cc8eba-ff6e-417d-8e74-b3bb24e08a26@gmail.com>
Message-ID: <26da1dfa-3408-4654-9046-36ed6d57059c@pardini.net>

On 05/06/2026 17:48, Heiner Kallweit wrote:
> On 05.06.2026 13:49, Ricardo Pardini via B4 Relay wrote:
>> From: Ricardo Pardini <ricardo at pardini.net>
>>
>> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
>> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
>>
>> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
>> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
>> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
>> compatibles documented in their own bindings (e.g. microchip,lan95xx)
>> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
>> these PCI function nodes can be validated.
>>
> 
> The of node seems to be created by of_pci_make_dev_node(). But this
> function is called for bridges only in pci_bus_add_device().
> So where is the node created in your case? Did you test node creation?
> 

Hi Heiner,

Seems to me of_pci_make_dev_node() is not at play here - that's the 
DT-synthesis path. For nodes already present in DT, the of_node is bound 
earlier, during pci_setup_device() -> pci_set_of_node() -> 
of_pci_find_child_device() via the 5-cell reg.

Ref testing: yes; with this series on a NanoPC-T6 I get, for example:
/sys/bus/pci/devices/0004:41:00.0/of_node -> 
/sys/firmware/devicetree/base/pcie at fe190000/pcie at 0,0/ethernet at 0,0 and 
u-boot correctly adds local-mac-address property there which is 
correctly picked up kernel-side:

=> setenv eth1addr 8e:b4:90:66:66:66
=> boot

...

# readlink -f /sys/bus/pci/devices/0004:41:00.0/of_node
/sys/firmware/devicetree/base/pcie at fe190000/pcie at 0,0/ethernet at 0,0

# xxd /sys/bus/pci/devices/0004:41:00.0/of_node/local-mac-address
00000000: 8eb4 9066 6666                           ...fff

# ip link show dev end1 | grep ether
     link/ether 8e:b4:90:66:66:66 brd ff:ff:ff:ff:ff:ff


>> +properties:
>> +  compatible:
>> +    enum:
>> +      - pci10ec,8125  # RTL8125 2.5GbE
>> +      - pci10ec,8126  # RTL8126 5GbE
>> +      - pci10ec,8127  # RTL8127
>> +      - pci10ec,8161  # RTL8168 variant
>> +      - pci10ec,8162  # RTL8168 variant
>> +      - pci10ec,8168  # RTL8168/8111 GbE
> 
> This list reflects just some of the PCI id's handled by r8169.
> Any specific reason for this exact selection?
I went for "chips likely to be soldered down on an SBC", but that was 
indeed speculative.

I guess I should trim to pci10ec,8125, which is all this series 
describes? (further IDs can be added by the patches that introduce 
boards using them)

--
Regards,
Ricardo



From hkallweit1 at gmail.com  Sat Jun  6 13:50:19 2026
From: hkallweit1 at gmail.com (Heiner Kallweit)
Date: Sat, 6 Jun 2026 22:50:19 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <26da1dfa-3408-4654-9046-36ed6d57059c@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
 <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
 <b7cc8eba-ff6e-417d-8e74-b3bb24e08a26@gmail.com>
 <26da1dfa-3408-4654-9046-36ed6d57059c@pardini.net>
Message-ID: <667f64e0-2b3e-41bf-9c97-3562696d3af7@gmail.com>

On 06.06.2026 07:03, Ricardo Pardini wrote:
> On 05/06/2026 17:48, Heiner Kallweit wrote:
>> On 05.06.2026 13:49, Ricardo Pardini via B4 Relay wrote:
>>> From: Ricardo Pardini <ricardo at pardini.net>
>>>
>>> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
>>> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
>>>
>>> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
>>> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
>>> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
>>> compatibles documented in their own bindings (e.g. microchip,lan95xx)
>>> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
>>> these PCI function nodes can be validated.
>>>
>>
>> The of node seems to be created by of_pci_make_dev_node(). But this
>> function is called for bridges only in pci_bus_add_device().
>> So where is the node created in your case? Did you test node creation?
>>
> 
> Hi Heiner,
> 
> Seems to me of_pci_make_dev_node() is not at play here - that's the DT-synthesis path. For nodes already present in DT, the of_node is bound earlier, during pci_setup_device() -> pci_set_of_node() -> of_pci_find_child_device() via the 5-cell reg.
> 
I see, thanks. If the matching is done based on the reg property, then I just wonder
if and where the compatible string is used. Or would the logic also work with a
random compatible string?

> Ref testing: yes; with this series on a NanoPC-T6 I get, for example:
> /sys/bus/pci/devices/0004:41:00.0/of_node -> /sys/firmware/devicetree/base/pcie at fe190000/pcie at 0,0/ethernet at 0,0 and u-boot correctly adds local-mac-address property there which is correctly picked up kernel-side:
> 
> => setenv eth1addr 8e:b4:90:66:66:66
> => boot
> 
> ...
> 
> # readlink -f /sys/bus/pci/devices/0004:41:00.0/of_node
> /sys/firmware/devicetree/base/pcie at fe190000/pcie at 0,0/ethernet at 0,0
> 
> # xxd /sys/bus/pci/devices/0004:41:00.0/of_node/local-mac-address
> 00000000: 8eb4 9066 6666?????????????????????????? ...fff
> 
> # ip link show dev end1 | grep ether
> ??? link/ether 8e:b4:90:66:66:66 brd ff:ff:ff:ff:ff:ff
> 
> 
>>> +properties:
>>> +? compatible:
>>> +??? enum:
>>> +????? - pci10ec,8125? # RTL8125 2.5GbE
>>> +????? - pci10ec,8126? # RTL8126 5GbE
>>> +????? - pci10ec,8127? # RTL8127
>>> +????? - pci10ec,8161? # RTL8168 variant
>>> +????? - pci10ec,8162? # RTL8168 variant
>>> +????? - pci10ec,8168? # RTL8168/8111 GbE
>>
>> This list reflects just some of the PCI id's handled by r8169.
>> Any specific reason for this exact selection?
> I went for "chips likely to be soldered down on an SBC", but that was indeed speculative.
> 
> I guess I should trim to pci10ec,8125, which is all this series describes? (further IDs can be added by the patches that introduce boards using them)
> 
Yes, I'd prefer this approach. Considering that RTL8168 has been supported for
about 20yrs now, your use case seems to be exotic. Otherwise I would have
such a patch much earlier.

> -- 
> Regards,
> Ricardo
> 



From ricardo at pardini.net  Sat Jun  6 18:03:19 2026
From: ricardo at pardini.net (Ricardo Pardini)
Date: Sun, 7 Jun 2026 03:03:19 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <667f64e0-2b3e-41bf-9c97-3562696d3af7@gmail.com>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
 <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
 <b7cc8eba-ff6e-417d-8e74-b3bb24e08a26@gmail.com>
 <26da1dfa-3408-4654-9046-36ed6d57059c@pardini.net>
 <667f64e0-2b3e-41bf-9c97-3562696d3af7@gmail.com>
Message-ID: <04ef65b1-e28f-42fd-b054-d1843205f67d@pardini.net>

On 06/06/2026 22:50, Heiner Kallweit wrote:
> On 06.06.2026 07:03, Ricardo Pardini wrote:
>> On 05/06/2026 17:48, Heiner Kallweit wrote:
>>> On 05.06.2026 13:49, Ricardo Pardini via B4 Relay wrote:
>>>> From: Ricardo Pardini <ricardo at pardini.net>
>>>>
>>>> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
>>>> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
>>>>
>>>> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
>>>> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
>>>> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
>>>> compatibles documented in their own bindings (e.g. microchip,lan95xx)
>>>> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
>>>> these PCI function nodes can be validated.
>>>
>>> The of node seems to be created by of_pci_make_dev_node(). But this
>>> function is called for bridges only in pci_bus_add_device().
>>> So where is the node created in your case? Did you test node creation?
>>
>> Seems to me of_pci_make_dev_node() is not at play here - that's the DT-synthesis path. For nodes already present in DT, the of_node is bound earlier, during pci_setup_device() -> pci_set_of_node() -> of_pci_find_child_device() via the 5-cell reg.
>>
> I see, thanks. If the matching is done based on the reg property, then I just wonder
> if and where the compatible string is used. Or would the logic also work with a
> random compatible string?

Thanks, Heiner. It seems the compatible is not involved in the kernel 
runtime matching at all (and u-boot simply patches DT via the ethernetN 
alias).

I guess DT-wise, specifying compatible (although not strictly required) 
makes sense since DT describes the hardware; "there's an RTL8125 at 
0x410000" sounds better than "there's a PCIe device that needs a MAC 
address at 0x410000", and having the binding opens up usages of 
non-generic properties, although that would be future-looking.

At this stage I've to ask the devicetree folks: should I simply drop the 
compatible from the DT patches (and the whole binding)? dtbs_check 
passes without it, and it also avoids the checkpatch.pl 
vendor-prefix-undocumented warning. There's precedent: at least on some 
Apple Silicon (2022, t600x-j375) and NVIDIA (2019, tegra210-p3450-0000). 
On Rockchip there's quite a few (10?) boards using the same RTL chip we 
might want to describe.

> [...]
>>> This list reflects just some of the PCI id's handled by r8169.
>>> Any specific reason for this exact selection?
>> I went for "chips likely to be soldered down on an SBC", but that was indeed speculative.
>>
>> I guess I should trim to pci10ec,8125, which is all this series describes? (further IDs can be added by the patches that introduce boards using them)
>>
> Yes, I'd prefer this approach. Considering that RTL8168 has been supported for
> about 20yrs now, your use case seems to be exotic. Otherwise I would have
> such a patch much earlier.
The Tegra Jetson Nano has an RTL8111 described in DT for this exact use 
case (without compatible) for about 7 years now -- I just couldn't find 
it until now.

I'll wait for people to chime in, and later send a v4 either dropping 
the binding, or trimming it to only the 8125. Sashiko seems to have nice 
suggestions [1] on the YAML too, in case we decide to keep the binding.

--
Regards,
Ricardo

[1] 
https://sashiko.dev/#/patchset/20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf%40pardini.net



From krzk at kernel.org  Sun Jun  7 01:42:50 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 7 Jun 2026 10:42:50 +0200
Subject: [PATCH v2 2/2] dt-bindings: arm: rockchip: add Vicharak Axon
 board
In-Reply-To: <20260601132529.139172-3-hrushirajg23@gmail.com>
References: <20260601132529.139172-1-hrushirajg23@gmail.com>
 <20260601132529.139172-3-hrushirajg23@gmail.com>
Message-ID: <20260607-favorite-messy-anteater-a56e7b@quoll>

On Mon, Jun 01, 2026 at 06:55:29PM +0530, Hrushiraj Gandhi wrote:
> Add the device tree binding for the Vicharak Axon single-board
> computer based on the Rockchip RK3588 SoC, and add the vicharak
> vendor prefix to the vendor-prefixes list.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
> ---
>  Documentation/devicetree/bindings/arm/rockchip.yaml    | 5 +++++
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  2 files changed, 7 insertions(+)

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

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

Best regards,
Krzysztof



From krzk at kernel.org  Sun Jun  7 01:45:40 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 7 Jun 2026 10:45:40 +0200
Subject: [PATCH v2 1/2] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260601132529.139172-2-hrushirajg23@gmail.com>
References: <20260601132529.139172-1-hrushirajg23@gmail.com>
 <20260601132529.139172-2-hrushirajg23@gmail.com>
Message-ID: <20260607-platypus-of-perfect-pluck-b7ffd0@quoll>

On Mon, Jun 01, 2026 at 06:55:28PM +0530, Hrushiraj Gandhi wrote:
> Add initial support for the Vicharak Axon single-board computer based on
> the Rockchip RK3588 SoC.
> 
> The board supports:
> 
> - eMMC storage
> - microSD card
> - Gigabit Ethernet
> - HDMI output (dual HDMI)
> - HDMI input
> - USB 2.0 host ports
> - PCIe 2.0 slots
> - PCIe 3.0 x4 slot
> - SATA
> - RTC
> - Status LEDs
> 
> The board uses an RK806 PMIC and provides the regulators required by
> the RK3588 SoC.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
> ---
>  arch/arm64/boot/dts/rockchip/Makefile         |    1 +
>  .../dts/rockchip/rk3588-vicharak-axon.dts     | 1038 +++++++++++++++++
>  2 files changed, 1039 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
> 
> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
> index cb55c6b70d0e..fcb115b02eff 100644
> --- a/arch/arm64/boot/dts/rockchip/Makefile
> +++ b/arch/arm64/boot/dts/rockchip/Makefile
> @@ -179,6 +179,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-rock-4d.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3582-radxa-e52c.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-sige7.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-armsom-w3.dtb
> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-genbook.dtb
>  dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
> new file mode 100644
> index 000000000000..fecd13a52e88
> --- /dev/null
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
> @@ -0,0 +1,1038 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +
> +/dts-v1/;
> +
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/linux-event-codes.h>
> +#include <dt-bindings/leds/common.h>
> +#include <dt-bindings/pinctrl/rockchip.h>
> +#include <dt-bindings/soc/rockchip,vop2.h>
> +#include <dt-bindings/usb/pd.h>
> +#include "rk3588.dtsi"
> +
> +/ {
> +	model = "Vicharak Axon";
> +	compatible = "vicharak,axon", "rockchip,rk3588";
> +
> +	aliases {
> +		mmc0 = &sdmmc;
> +		mmc1 = &sdhci;
> +		mmc2 = &sdio;
> +		serial2 = &uart2;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial2:1500000n8";
> +	};
> +
> +	hdmi0-con {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi0_con_in: endpoint {
> +				remote-endpoint = <&hdmi0_out_con>;
> +			};
> +		};
> +	};
> +
> +	hdmi1-con {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi1_con_in: endpoint {
> +				remote-endpoint = <&hdmi1_out_con>;
> +			};
> +		};
> +	};
> +
> +	leds {
> +		compatible = "gpio-leds";
> +		status = "okay";

Which DTSI disabled it?

> +
> +		power_led: power-led {
> +			color = <LED_COLOR_ID_GREEN>;
> +			function = LED_FUNCTION_STATUS;
> +			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
> +			linux,default-trigger = "heartbeat";
> +		};
> +
> +		status_led: status-led {
> +			color = <LED_COLOR_ID_RED>;
> +			function = LED_FUNCTION_STATUS;
> +			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
> +			linux,default-trigger = "none";
> +		};
> +	};
> +
> +	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {

Unused, drop. Don't add useless/non-controllable supplies without
consumers. They bring no benefits, except more review, slower kernel,
more code to maintain.

> +		compatible = "regulator-fixed";
> +		regulator-name = "pcie20_avdd0v85";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <850000>;
> +		regulator-max-microvolt = <850000>;
> +		vin-supply = <&vdd_0v85_s0>;
> +	};
> +
> +	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {

No users

> +		compatible = "regulator-fixed";
> +		regulator-name = "pcie20_avdd1v8";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +		vin-supply = <&avcc_1v8_s0>;
> +	};
> +
> +	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {

Is any of this real?

> +		compatible = "regulator-fixed";
> +		regulator-name = "pcie30_avdd0v75";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <750000>;
> +		regulator-max-microvolt = <750000>;
> +		vin-supply = <&vdd_0v75_s0>;
> +	};
> +
> +	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "pcie30_avdd1v8";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <1800000>;
> +		regulator-max-microvolt = <1800000>;
> +		vin-supply = <&avcc_1v8_s0>;
> +	};
> +
> +	sata_vcc_5v0: regulator-sata-vcc-5v0 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "sata_vcc_5v0";
> +		startup-delay-us = <5000>;
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +		vin-supply = <&vcc12v_dcin>;
> +	};
> +
> +	sdio_pwrseq: sdio-pwrseq {
> +		compatible = "mmc-pwrseq-simple";
> +		clocks = <&hym8563>;
> +		clock-names = "ext_clock";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&sdio_reset_wifi>;
> +		reset-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_LOW>;
> +		status = "okay";
> +	};
> +
> +	vcc0_4v0: vcc4v0_sys: regulator-vcc0-4v0 {

Odd sorting. And still not used!

> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc0_4v0";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <4000000>;
> +		regulator-max-microvolt = <4000000>;
> +		vin-supply = <&vcc12v_dcin>;
> +	};
> +
> +	vcc12v_dcin: regulator-vcc12v-dcin {

Also not used

> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc12v_dcin";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <12000000>;
> +		regulator-max-microvolt = <12000000>;
> +	};
> +
> +	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc3v3_io_expander";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +	};
> +
> +	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc3v3_pcie20_sata30";
> +		regulator-boot-on;
> +		regulator-always-on;
> +		enable-active-high;
> +		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
> +		regulator-max-microvolt = <3300000>;
> +		regulator-min-microvolt = <3300000>;
> +		vin-supply = <&vcc12v_dcin>;
> +	};

...

> +
> +&i2c0 {
> +	pinctrl-0 = <&i2c0m2_xfer>;
> +	pinctrl-names = "default";
> +	status = "okay";
> +
> +	vdd_cpu_big0_s0: regulator at 42 {
> +		compatible = "rockchip,rk8602";
> +		fcs,suspend-voltage-selector = <1>;
> +		reg = <0x42>;
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-max-microvolt = <1050000>;
> +		regulator-min-microvolt = <550000>;
> +		regulator-name = "vdd_cpu_big0_s0";
> +		regulator-ramp-delay = <2300>;
> +		vin-supply = <&vcc5v0_sys>;
> +
> +		regulator-state-mem {
> +			regulator-off-in-suspend;
> +		};
> +	};
> +
> +	vdd_cpu_big1_s0: regulator at 43 {
> +		compatible = "rockchip,rk8603", "rockchip,rk8602";
> +		fcs,suspend-voltage-selector = <1>;
> +		reg = <0x43>;
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-max-microvolt = <1050000>;
> +		regulator-min-microvolt = <550000>;
> +		regulator-name = "vdd_cpu_big1_s0";
> +		regulator-ramp-delay = <2300>;
> +		vin-supply = <&vcc5v0_sys>;
> +
> +		regulator-state-mem {
> +			regulator-off-in-suspend;
> +		};
> +	};
> +
> +	hym8563: rtc at 51 {
> +		compatible = "haoyu,hym8563";
> +		reg = <0x51>;
> +		#clock-cells = <0>;
> +		clock-output-names = "hym8563";
> +		interrupt-parent = <&gpio0>;
> +		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&rtc_int>;
> +		wakeup-source;
> +		status = "okay";


Why is this enabled but regulator above is not? What logic drivers this?


> +	};
> +};
> +
> +&i2c1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c1m2_xfer>;
> +	status = "okay";
> +
> +	vdd_npu_s0: regulator at 42 {
> +		compatible = "rockchip,rk8602";
> +		reg = <0x42>;
> +		fcs,suspend-voltage-selector = <1>;
> +		regulator-name = "vdd_npu_s0";
> +		regulator-boot-on;
> +		regulator-enable-ramp-delay = <500>;
> +		regulator-min-microvolt = <550000>;
> +		regulator-max-microvolt = <950000>;
> +		regulator-ramp-delay = <2300>;
> +		vin-supply = <&vcc5v0_sys>;
> +
> +		regulator-state-mem {
> +			regulator-off-in-suspend;
> +		};
> +	};
> +};
> +
> +&i2c6 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c6m0_xfer>;
> +	status = "okay";
> +
> +	pca9554: gpio at 24 {
> +		compatible = "nxp,pca9554";
> +		#gpio-cells = <2>;
> +		gpio-controller;
> +		reg = <0x24>;
> +		vcc-supply = <&vcc3v3_io_expander>;
> +		status = "okay";

Who disabled it?

Best regards,
Krzysztof



From krzk at kernel.org  Sun Jun  7 02:13:44 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 7 Jun 2026 11:13:44 +0200
Subject: [PATCH v6 1/3] dt-bindings: vendor-prefixes: add vicharak
In-Reply-To: <20260601162143.170030-2-hrushirajg23@gmail.com>
References: <20260601162143.170030-1-hrushirajg23@gmail.com>
 <20260601162143.170030-2-hrushirajg23@gmail.com>
Message-ID: <96c9b1eb-9f8e-430d-9c38-eb4d489d7d24@kernel.org>

On 01/06/2026 18:21, Hrushiraj Gandhi wrote:
> Add the vendor prefix for Vicharak Computers Pvt. Ltd.
> 
> Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 

Drop the patch, it was already sent by someone else.

Best regards,
Krzysztof


From heiko at sntech.de  Sun Jun  7 03:59:00 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 07 Jun 2026 12:59:00 +0200
Subject: [PATCH] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <20260604123224.192543-2-diogompaissilva@gmail.com>
References: <20260604123224.192543-2-diogompaissilva@gmail.com>
Message-ID: <5277524.h16uAIiOU7@phil>

Hi Diego,

Am Donnerstag, 4. Juni 2026, 14:32:25 Mitteleurop?ische Sommerzeit schrieb Diogo Silva:
> Remove the dependency on drm_simple_kms_helper by open-coding the
> drm_simple_encoder_init call.

this description is missing a rationale.

Looking at the drm git history, I guess here you could add a second
paragraph, with something like:

----------- 8< -----------
The helpers have been deprecated for years as they only add an an
intermediate layer between atomic modesetting and the DRM driver.
----------- 8< -----------

Shamelessly stolen from the Todo item ;-)


> Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
> ---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 9 +++++++--

Any reason for only changing the DSI driver?

Looking at [0] a number of the Rockchip drivers use the same pattern:
- drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
- drivers/gpu/drm/rockchip/cdn-dp-core.c
- drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
- drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
- drivers/gpu/drm/rockchip/rk3066_hdmi.c
- drivers/gpu/drm/rockchip/rockchip_lvds.c
- drivers/gpu/drm/rockchip/rockchip_rgb.c

You can just do all Rockchip ones - even in one patch I think :-) .


Thanks
Heiko

[0] https://elixir.bootlin.com/linux/v7.1-rc6/A/ident/drm_simple_encoder_init


>  1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> index 3547d91b25d3..a09b382d208e 100644
> --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> @@ -25,7 +25,6 @@
>  #include <drm/drm_mipi_dsi.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_print.h>
> -#include <drm/drm_simple_kms_helper.h>
>  
>  #include "rockchip_drm_drv.h"
>  
> @@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
>  	clk_disable_unprepare(dsi->grf_clk);
>  }
>  
> +static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
>  static const struct drm_encoder_helper_funcs
>  dw_mipi_dsi_encoder_helper_funcs = {
>  	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
> @@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
>  	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
>  							     dsi->dev->of_node);
>  
> -	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
> +	ret = drm_encoder_init(drm_dev, encoder,
> +				&dw_mipi_dsi_encoder_funcs,
> +				DRM_MODE_ENCODER_DSI, NULL);
>  	if (ret) {
>  		DRM_ERROR("Failed to initialize encoder with drm\n");
>  		return ret;
> 






From diederik at cknow-tech.com  Sun Jun  7 03:58:49 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Sun,  7 Jun 2026 12:58:49 +0200
Subject: [PATCH] ASoC: dt-bindings: everest,es8389: Document audio graph port
Message-ID: <20260607105913.355966-1-diederik@cknow-tech.com>

Provide an endpoint for binding with the other side of the audio link,
which is achieved via the 'port' property.

Signed-off-by: Diederik de Haas <diederik at cknow-tech.com>
---
 Documentation/devicetree/bindings/sound/everest,es8389.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/everest,es8389.yaml b/Documentation/devicetree/bindings/sound/everest,es8389.yaml
index 75ce0bc48904..7db84cf11386 100644
--- a/Documentation/devicetree/bindings/sound/everest,es8389.yaml
+++ b/Documentation/devicetree/bindings/sound/everest,es8389.yaml
@@ -27,6 +27,10 @@ properties:
     items:
       - const: mclk
 
+  port:
+    $ref: audio-graph-port.yaml#
+    unevaluatedProperties: false
+
   "#sound-dai-cells":
     const: 0
 
-- 
2.53.0



From heiko at sntech.de  Sun Jun  7 04:00:15 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 07 Jun 2026 13:00:15 +0200
Subject: [PATCH] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <5277524.h16uAIiOU7@phil>
References: <20260604123224.192543-2-diogompaissilva@gmail.com> <5277524.h16uAIiOU7@phil>
Message-ID: <5449269.L4jQFfv3LO@phil>

Am Sonntag, 7. Juni 2026, 12:59:00 Mitteleurop?ische Sommerzeit schrieb Heiko Stuebner:
> Hi Diego,

sorry for mangling your name, Diogo.


Heiko




From diogompaissilva at gmail.com  Sun Jun  7 04:57:24 2026
From: diogompaissilva at gmail.com (Diogo Silva)
Date: Sun, 7 Jun 2026 13:57:24 +0200
Subject: [PATCH] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <5277524.h16uAIiOU7@phil>
References: <20260604123224.192543-2-diogompaissilva@gmail.com> <5277524.h16uAIiOU7@phil>
Message-ID: <CAJpoHp41+mLPWsu0EpCHkNz_z3=+tGqfh0cDKEaCWxwoYOm_Jw@mail.gmail.com>

Hey Heiko,

> this description is missing a rationale.
>
> Looking at the drm git history, I guess here you could add a second
> paragraph, with something like:
>
> ----------- 8< -----------
> The helpers have been deprecated for years as they only add an an
> intermediate layer between atomic modesetting and the DRM driver.
> ----------- 8< -----------
>
> Shamelessly stolen from the Todo item ;-)

True. I will add the rationale then.

> Any reason for only changing the DSI driver?
>
> Looking at [0] a number of the Rockchip drivers use the same pattern:
> - drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> - drivers/gpu/drm/rockchip/cdn-dp-core.c
> - drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> - drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
> - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> - drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> - drivers/gpu/drm/rockchip/rk3066_hdmi.c
> - drivers/gpu/drm/rockchip/rockchip_lvds.c
> - drivers/gpu/drm/rockchip/rockchip_rgb.c
>
> You can just do all Rockchip ones - even in one patch I think :-) .

Yes, indeed. I wanted to send a tiny patch to check if all my
configurations were ok, but since it looks like they are, I will add the
other rockchip drivers that have the deprecated functions.

Thanks,
Diogo

On Sun, 7 Jun 2026 at 12:59, Heiko Stuebner <heiko at sntech.de> wrote:
>
> Hi Diego,
>
> Am Donnerstag, 4. Juni 2026, 14:32:25 Mitteleurop?ische Sommerzeit schrieb Diogo Silva:
> > Remove the dependency on drm_simple_kms_helper by open-coding the
> > drm_simple_encoder_init call.
>
> this description is missing a rationale.
>
> Looking at the drm git history, I guess here you could add a second
> paragraph, with something like:
>
> ----------- 8< -----------
> The helpers have been deprecated for years as they only add an an
> intermediate layer between atomic modesetting and the DRM driver.
> ----------- 8< -----------
>
> Shamelessly stolen from the Todo item ;-)
>
>
> > Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
> > ---
> >  drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 9 +++++++--
>
> Any reason for only changing the DSI driver?
>
> Looking at [0] a number of the Rockchip drivers use the same pattern:
> - drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> - drivers/gpu/drm/rockchip/cdn-dp-core.c
> - drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> - drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
> - drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> - drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> - drivers/gpu/drm/rockchip/rk3066_hdmi.c
> - drivers/gpu/drm/rockchip/rockchip_lvds.c
> - drivers/gpu/drm/rockchip/rockchip_rgb.c
>
> You can just do all Rockchip ones - even in one patch I think :-) .
>
>
> Thanks
> Heiko
>
> [0] https://elixir.bootlin.com/linux/v7.1-rc6/A/ident/drm_simple_encoder_init
>
>
> >  1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> > index 3547d91b25d3..a09b382d208e 100644
> > --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> > +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
> > @@ -25,7 +25,6 @@
> >  #include <drm/drm_mipi_dsi.h>
> >  #include <drm/drm_of.h>
> >  #include <drm/drm_print.h>
> > -#include <drm/drm_simple_kms_helper.h>
> >
> >  #include "rockchip_drm_drv.h"
> >
> > @@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
> >       clk_disable_unprepare(dsi->grf_clk);
> >  }
> >
> > +static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
> > +     .destroy = drm_encoder_cleanup,
> > +};
> > +
> >  static const struct drm_encoder_helper_funcs
> >  dw_mipi_dsi_encoder_helper_funcs = {
> >       .atomic_check = dw_mipi_dsi_encoder_atomic_check,
> > @@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
> >       encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
> >                                                            dsi->dev->of_node);
> >
> > -     ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
> > +     ret = drm_encoder_init(drm_dev, encoder,
> > +                             &dw_mipi_dsi_encoder_funcs,
> > +                             DRM_MODE_ENCODER_DSI, NULL);
> >       if (ret) {
> >               DRM_ERROR("Failed to initialize encoder with drm\n");
> >               return ret;
> >
>
>
>
>


From diogompaissilva at gmail.com  Sun Jun  7 05:37:40 2026
From: diogompaissilva at gmail.com (Diogo Silva)
Date: Sun,  7 Jun 2026 14:37:40 +0200
Subject: [PATCH v2] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <5277524.h16uAIiOU7@phil>
References: <5277524.h16uAIiOU7@phil>
Message-ID: <20260607123739.393974-2-diogompaissilva@gmail.com>

Simple KMS helper are deprecated since they only add an intermediate
layer between drivers and the atomic modesetting.
This patch removes the dependency on drm_simple_encoder_init from rockchip
DRM drivers by inlining this helper.

Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c  | 9 ++++++---
 drivers/gpu/drm/rockchip/cdn-dp-core.c           | 9 ++++++---
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c  | 9 +++++++--
 drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 ++++++--
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c      | 8 ++++++--
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c   | 8 ++++++--
 drivers/gpu/drm/rockchip/rk3066_hdmi.c           | 8 ++++++--
 drivers/gpu/drm/rockchip/rockchip_lvds.c         | 9 +++++++--
 drivers/gpu/drm/rockchip/rockchip_rgb.c          | 8 ++++++--
 9 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 96bd3dd239d2..ca6701319f2f 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -30,7 +30,6 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -317,6 +316,10 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
 	.mode_fixup = rockchip_dp_drm_encoder_mode_fixup,
 	.mode_set = rockchip_dp_drm_encoder_mode_set,
@@ -369,8 +372,8 @@ static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp)
 							     dev->of_node);
 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder,
-				      DRM_MODE_ENCODER_TMDS);
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret) {
 		DRM_ERROR("failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 177e30445ee8..060ffca1f3d8 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -23,7 +23,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "cdn-dp-core.h"
 #include "cdn-dp-reg.h"
@@ -671,6 +670,10 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs cdn_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
 	.atomic_check = cdn_dp_encoder_atomic_check,
 };
@@ -988,8 +991,8 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 							     dev->of_node);
 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder,
-				      DRM_MODE_ENCODER_TMDS);
+	ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret) {
 		DRM_ERROR("failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 3547d91b25d3..a09b382d208e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -25,7 +25,6 @@
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 	clk_disable_unprepare(dsi->grf_clk);
 }
 
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi_encoder_helper_funcs = {
 	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
@@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dsi->dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+	ret = drm_encoder_init(drm_dev, encoder,
+				&dw_mipi_dsi_encoder_funcs,
+				DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		DRM_ERROR("Failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
index 0aea764e29b2..687afc5590cd 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
@@ -23,7 +23,6 @@
 #include <drm/bridge/dw_mipi_dsi2.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include <uapi/linux/videodev2.h>
 
@@ -275,6 +274,10 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs dw_mipi_dsi2_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi2_encoder_helper_funcs = {
 	.atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
@@ -290,7 +293,8 @@ static int rockchip_dsi2_drm_create_encoder(struct dw_mipi_dsi2_rockchip *dsi2,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dsi2->dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+	ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi2_encoder_funcs,
+			       DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		dev_err(dsi2->dev, "Failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 0dc1eb5d2ae3..906264d65db3 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -16,7 +16,6 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -322,6 +321,10 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
+	.destroy    = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
 	.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
 	.mode_set   = dw_hdmi_rockchip_encoder_mode_set,
@@ -604,7 +607,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
 	}
 
 	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
-	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
 
 	platform_set_drvdata(pdev, hdmi);
 
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index 1a09bcc96c3e..ed665352618f 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -23,7 +23,6 @@
 #include <drm/drm_bridge_connector.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -160,6 +159,10 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
 	return ret;
 }
 
+static const struct drm_encoder_funcs dw_hdmi_qp_rockchip_encoder_funcs = {
+	.destroy	= drm_encoder_cleanup,
+};
+
 static const struct
 drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = {
 	.enable		= dw_hdmi_qp_rockchip_encoder_enable,
@@ -586,7 +589,8 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 		return ret;
 
 	drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs);
-	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+	drm_encoder_init(drm, encoder, &dw_hdmi_qp_rockchip_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
 
 	platform_set_drvdata(pdev, hdmi);
 
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 9066ee2d1dff..a21df6f380f5 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -12,7 +12,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include <linux/clk.h>
 #include <linux/mfd/syscon.h>
@@ -454,6 +453,10 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rk3066_hdmi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
 	.atomic_check   = rk3066_hdmi_encoder_atomic_check,
@@ -696,7 +699,8 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
 		return -EPROBE_DEFER;
 
 	drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
-	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+	drm_encoder_init(drm, encoder, &rk3066_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 75f898a10cbc..c3b30c622873 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -24,7 +24,6 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_lvds.h"
@@ -427,6 +426,10 @@ static void px30_lvds_encoder_disable(struct drm_encoder *encoder)
 	drm_panel_unprepare(lvds->panel);
 }
 
+static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = {
 	.enable = rk3288_lvds_encoder_enable,
@@ -594,7 +597,9 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
+	ret = drm_encoder_init(drm_dev, encoder,
+				      &rockchip_lvds_encoder_funcs,
+				      DRM_MODE_ENCODER_LVDS, NULL);
 	if (ret < 0) {
 		drm_err(drm_dev,
 			"failed to initialize encoder: %d\n", ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index 5c0c6e2cc28d..b5b8322a1260 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -17,7 +17,6 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_rgb.h"
@@ -65,6 +64,10 @@ rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
 	.atomic_check = rockchip_rgb_encoder_atomic_check,
@@ -127,7 +130,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
 	encoder = &rgb->encoder.encoder;
 	encoder->possible_crtcs = drm_crtc_mask(crtc);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_NONE);
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
 	if (ret < 0) {
 		DRM_DEV_ERROR(drm_dev->dev,
 			      "failed to initialize encoder: %d\n", ret);
-- 
2.51.2



From jonas at kwiboo.se  Sun Jun  7 10:01:10 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Sun, 7 Jun 2026 19:01:10 +0200
Subject: [PATCH v2] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <20260607123739.393974-2-diogompaissilva@gmail.com>
References: <5277524.h16uAIiOU7@phil>
 <20260607123739.393974-2-diogompaissilva@gmail.com>
Message-ID: <c8f30973-450e-4995-b6f5-03e7b6afc75b@kwiboo.se>

Hi Diogo,

On 6/7/2026 2:37 PM, Diogo Silva wrote:
> Simple KMS helper are deprecated since they only add an intermediate
> layer between drivers and the atomic modesetting.
> This patch removes the dependency on drm_simple_encoder_init from rockchip
> DRM drivers by inlining this helper.
> 
> Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
> ---
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c  | 9 ++++++---
>  drivers/gpu/drm/rockchip/cdn-dp-core.c           | 9 ++++++---
>  drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c  | 9 +++++++--
>  drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 ++++++--
>  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c      | 8 ++++++--
>  drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c   | 8 ++++++--
>  drivers/gpu/drm/rockchip/rk3066_hdmi.c           | 8 ++++++--
>  drivers/gpu/drm/rockchip/rockchip_lvds.c         | 9 +++++++--
>  drivers/gpu/drm/rockchip/rockchip_rgb.c          | 8 ++++++--
>  9 files changed, 56 insertions(+), 20 deletions(-)

[snip]

> diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> index 0dc1eb5d2ae3..906264d65db3 100644
> --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
> @@ -16,7 +16,6 @@
>  #include <drm/drm_edid.h>
>  #include <drm/drm_of.h>
>  #include <drm/drm_probe_helper.h>
> -#include <drm/drm_simple_kms_helper.h>
>  
>  #include "rockchip_drm_drv.h"
>  
> @@ -322,6 +321,10 @@ dw_hdmi_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
>  	return 0;
>  }
>  
> +static const struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
> +	.destroy    = drm_encoder_cleanup,
> +};
> +
>  static const struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
>  	.mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
>  	.mode_set   = dw_hdmi_rockchip_encoder_mode_set,
> @@ -604,7 +607,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
>  	}
>  
>  	drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
> -	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
> +	drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
> +			 DRM_MODE_ENCODER_TMDS, NULL);

Please base your work on latest drm-misc tree, this has already been
addressed in commit 3de723684be5 ("drm/rockchip: dw_hdmi: Use drmres
helpers for encoder resources") [1].

Also instead of open-code, maybe a change to use drmm_encoder_init() is
more appropriate for some of the other drivers?

[1] https://cgit.freedesktop.org/drm/drm-misc/commit/?id=3de723684be5c13517dea3dba287d06e12678c86

Regards,
Jonas

>  
>  	platform_set_drvdata(pdev, hdmi);
>  

[snip]


From heiko at sntech.de  Sun Jun  7 13:59:31 2026
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 07 Jun 2026 22:59:31 +0200
Subject: [GIT PULL] Rockchip clock changes for 7.2 #1
Message-ID: <4272848.9fHWaBTJ5E@phil>

Hi Mike, Stephen,

please find below a pull-request with a Rockchip clock change for 7.2

Please pull.

Thanks
Heiko


The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v7.2-rockchip-clk1

for you to fetch changes up to 7edfb7fb58ee058298e18fde76a6077ef17d19d8:

  clk: rockchip: allow COMPILE_TEST builds (2026-05-13 12:35:57 +0200)

----------------------------------------------------------------
gate-clocks for i2s outputs on rk3588 and allowing compile-tests
for the whole clock driver.
The sparse warning when the Rockchip clock is compiled on M68K gets
fixed by:
https://lore.kernel.org/lkml/b55e9bd0532c0cad519809c86e0a8400060d75a1.1780559561.git.geert at linux-m68k.org/

----------------------------------------------------------------
Daniele Briguglio (5):
      dt-bindings: clock: rockchip,rk3588-cru: add I2S MCLK output to IO clock IDs
      clk: rockchip: allow grf_type_sys lookup in aux_grf_table
      clk: rockchip: add helper to register auxiliary GRFs
      soc: rockchip: rk3588: add SYS_GRF SOC_CON6 register offset
      clk: rockchip: rk3588: add GATE_GRF clocks for I2S MCLK output to IO

Heiko Stuebner (1):
      Merge branch 'v7.2-shared/socids' into v7.2-clk/next

Rosen Penev (1):
      clk: rockchip: allow COMPILE_TEST builds

 drivers/clk/Makefile                            |  2 +-
 drivers/clk/rockchip/Kconfig                    |  2 +-
 drivers/clk/rockchip/clk-rk3588.c               | 16 ++++++++++++++++
 drivers/clk/rockchip/clk.c                      | 25 +++++++++++++++++++++----
 drivers/clk/rockchip/clk.h                      |  3 +++
 include/dt-bindings/clock/rockchip,rk3588-cru.h |  4 ++++
 include/soc/rockchip/rk3588_grf.h               |  2 ++
 7 files changed, 48 insertions(+), 6 deletions(-)





From midgy971 at gmail.com  Sun Jun  7 14:03:08 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Sun, 7 Jun 2026 23:03:08 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
Message-ID: <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>

Hi Chaoyi,

Thanks a lot for looking at this -- input from Rockchip is exactly what this
series needs.

> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than v1,
> implying it should support 40-bit PAs. Nevertheless, please note that the
> upper limit for DTE is 32 bits.

Understood, and that 32-bit-DTE note is the crux of the trouble I had, so let
me lay out what I see and ask how you'd prefer to solve it.

The mainline node is already v2 (rockchip,rk3568-iommu in rk356x-base.dtsi).
The problem on this 8 GiB board: with the v2 ops the page-table allocations
(gfp_flags == 0) can land above 4 GiB, so the DTE ends up > 32 bits and the
NPU's first translation faults with DMA_READ_ERROR. To work around that I had
switched the NPU MMU to the v1 compatible (rockchip,iommu), whose ops set
GFP_DMA32 and keep the DTE sub-4 GiB. That works in isolation, but because the
driver keeps a single global rk_ops, a v1 NPU MMU then trips
WARN_ON(rk_ops != ops) against the SoC's v2 instances (VOP/VDEC), which is why
I based the series on Simon's per-device-ops work.

So my question: with per-device ops in place, what's the intended way to keep
the NPU MMU on v2 *and* cap its DTE at 32 bits on boards with >4 GiB of RAM?
A v2 ops variant carrying GFP_DMA32 for this device, or is there a register/
config bit that constrains the DTE address? I'd rather follow the Rockchip
intent here than carry the v1 workaround. (Simon, cc'd -- this is right next to
your per-device-ops series.)

> Can these operations not be completed via the pmdomain driver?
> If some operations are controlled by TF-A, are you using open source TF-A?

Most of it is in pmdomain already. Power-on and NoC de-idle are done by the
RK3568 NPU power domain (genpd) at power-on -- the driver no longer pokes the
PMU directly. Two things remain outside it:

 - vdd_npu: I mark it regulator-always-on in DT rather than wiring it as the
   domain's domain-supply, because as a domain-supply it created a device-link
   to the I2C PMIC (rk809) and genpd's power-off QoS-save path then hung
   reading the NPU QoS registers behind the (gated) NoC. If there's a clean way
   to let genpd own vdd_npu without that I2C ordering deadlock I'd much prefer
   that -- pointers welcome.

 - the NPU compute clock (PVTPLL): set from the driver via SCMI, and only
   needed for actual compute, not for bring-up.

One more pmdomain observation from testing, possibly relevant to how the NPU
domain should be modelled: the domain's power-off/on cycle doesn't reliably
re-de-idle the NoC. If the NPU is probed after genpd has already powered the
(unused) domain off, the power-on de-idle fails ("failed to set idle on domain
'npu'") and the NPU IOMMU then takes an external abort on its first MMIO access.
Probing the NPU before the unused-domain power-off, or marking the domain
always-on, both avoid it. Is the NoC de-idle expected to work on a genpd
re-power here, or should this domain effectively stay on?

On TF-A: yes -- bl31 is built from upstream arm-trusted-firmware
(github.com/ARM-software/arm-trusted-firmware, RK3568 platform), providing PSCI
and the SCMI clock service. The only closed blob in the boot chain is Rockchip's
DDR init (rkbin), which is the standard situation for mainline RK356x.

Kind regards,
Midgy

Le ven. 5 juin 2026 ? 03:36, Chaoyi Chen <chaoyi.chen at rock-chips.com> a ?crit :
>
> Hello Midgy,
>
> On 6/4/2026 9:52 PM, Midgy BALON wrote:
> > RFC, not for merge. End-to-end inference does not produce correct output
> > yet (see Status), so per the v2 discussion this is a request for design
> > feedback. It now probes, attaches, and submits cleanly on a stock
> > v7.1-rc6 tree; what remains is one hardware-internal issue.
> >
> > The RK3568 has a single NVDLA-derived NPU core, the same IP family as the
> > RK3588 NPU the driver already supports; the register layout matches. The
> > RK3568 differences are a 32-bit NPU AXI/IOMMU (vs 40-bit) and explicit
> > PVTPLL/PMU bring-up to power and de-idle the NPU before it is reachable.
> >
> > Patches:
> >   1-2  rocket: per-SoC data struct, then derive DMA width and core count
> >        from match data (refactors, no functional change).
> >   3    rocket: RK3568 SoC data + PVTPLL/PMU/NOC bring-up.
> >   4    rocket: reset the NPU before detaching the IOMMU on a job timeout
> >        (the detach otherwise stalls a wedged AXI master and WARNs).
> >   5    rocket: keep the IOMMU domain attached across jobs instead of
> >        re-attaching per job (the per-job rk_iommu handshake on the idle
> >        NPU MMU is slow and noisy).
> >   6    iommu/rockchip: clear AUTO_GATING bit 1 on the RK356x v1 IOMMU so
> >        the page-walker keeps its clock (else a TLB-miss walk never
> >        completes).
> >   7    dt-bindings: add the RK3568 NPU compatible.
> >   8-9  arm64 dts: add the NPU and its IOMMU, and enable them on ROCK 3B.
> >
> > Dependency. The NPU MMU is rockchip-iommu v1 (32-bit) while the rest of
> > the RK3568 uses v2 (40-bit). They cannot coexist until the driver carries
> > per-device ops; this series is developed on top of Simon Xue's
> > "iommu/rockchip: Drop global rk_ops in favor of per-device ops" [1].
> > Without it the NPU IOMMU fails to probe on a full RK3568 boot.
> >
>
> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than
> v1, implying it should support 40-bit PAs. Nevertheless, please note that
> the upper limit for DTE is 32 bits.
>
> > Power bring-up. The NPU is brought up through the power-domain layer (no
> > driver hack): the NPU power-domain keeps its clocks but drops the pm_qos
> > phandle (qos_npu sits behind the gated NPU NoC, so genpd's power-off QoS
> > save faults reading it), and vdd_npu is marked always-on so the rail is
> > up before genpd de-idles the NoC at power-on. The PMU de-idle then ACKs
> > without PVTPLL running; PVTPLL is only needed for compute.
> >
>
> Can these operations not be completed via the pmdomain driver?
> If some operations are controlled by TF-A, are you using open
> source TF-A? Thank you.
>
> > Status. On v7.1-rc6 the driver probes, creates /dev/accel/accel0,
> > attaches an IOMMU domain, and submits jobs; the program controller
> > fetches and broadcasts the command list. Inference output is still wrong,
> > and the cause is split across three layers:
> >   - kernel (this series): the RK3568 differences appear handled;
> >   - mesa/Teflon userspace: still emits RK3588-tuned config, wrong for
> >     RK3568 (to be filed separately on mesa-dev);
> >   - hardware: with corrected config the NPU's DMA reads the full input
> >     and weight tensors (confirmed via its DMA bandwidth counters), but
> >     the MAC/output stage never completes, the job times out, and the
> >     output stays at the buffer's zero-point. I have not found the missing
> >     step; it is not in the command list (replaying the vendor's
> >     byte-exact command list behaves the same). Pointers welcome,
> >     especially from anyone with RK3568 NPU experience.
> >
> > Known residual. On the first IOMMU attach the NPU MMU is idle with paging
> > already enabled; the rk_iommu stall/reset handshake does not complete in
> > that state and logs one burst of timeouts before the (kept) domain
> > settles. It is harmless here because the job times out regardless, but it
> > points at an idle-MMU reconfiguration corner the rk_iommu code does not
> > handle on this block.
> >
> > [1] https://lore.kernel.org/linux-rockchip/20260310105303.128859-1-xxm at rock-chips.com/
> >
> > Changes since v2:
> >   - Tagged RFC; now tested on a stock v7.1-rc6 tree.
> >   - Bring-up moved into the power-domain/DT layer (no initcall hack).
> >   - Added the IOMMU detach-on-timeout and attach-once driver fixes.
> >   - Split the driver patch (Heiko): soc_data / match-data / RK3568.
> >   - Derive DMA width and core count from match data; drop the DT rescans.
> >   - Binding describes the hardware; added the missing $ref on rockchip,pmu.
> >   - Disclosed the per-device-ops IOMMU dependency.
> >
> > Midgy BALON (9):
> >   accel: rocket: Introduce per-SoC rocket_soc_data
> >   accel: rocket: Derive DMA width and core count from match data
> >   accel: rocket: Add RK3568 SoC support
> >   accel: rocket: Reset the NPU before detaching the IOMMU on timeout
> >   accel: rocket: Keep the IOMMU domain attached across jobs
> >   iommu/rockchip: Clear AUTO_GATING bit 1 on the RK356x v1 IOMMU
> >   dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
> >   arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
> >   arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU
> >
> >  .../npu/rockchip,rk3588-rknn-core.yaml        | 18 ++++-
> >  .../boot/dts/rockchip/rk3568-rock-3b.dts      | 14 +++-
> >  arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++
> >  drivers/accel/rocket/rocket_core.c            | 22 ++++++-
> >  drivers/accel/rocket/rocket_core.h            | 19 ++++++
> >  drivers/accel/rocket/rocket_device.c          | 15 ++---
> >  drivers/accel/rocket/rocket_device.h          |  3 +-
> >  drivers/accel/rocket/rocket_drv.c             | 66 ++++++++++++++++++-
> >  drivers/accel/rocket/rocket_job.c             | 35 ++++++++--
> >  drivers/iommu/rockchip-iommu.c                | 12 ++++
> >  10 files changed, 219 insertions(+), 23 deletions(-)
> >
> >
> > base-commit: 52c800fdcf11888ebeb50c3d707f782cc15b66eb
>
> --
> Best,
> Chaoyi


From midgy971 at gmail.com  Sun Jun  7 14:05:03 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Sun, 7 Jun 2026 23:05:03 +0200
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the
 RK356x v1 IOMMU
In-Reply-To: <e44b506e-e9d2-48e3-acea-ab28b7be9b37@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <20260604135255.62682-7-midgy971@gmail.com>
 <e44b506e-e9d2-48e3-acea-ab28b7be9b37@rock-chips.com>
Message-ID: <CA+GS1Y16++cztPxdUGLrPA73ENm4vJGFrjm-jP8r=8OQqcMJGA@mail.gmail.com>

Hi Chaoyi,

> As I said, it is v2. Could you please try using the code below instead and
> see if it works?
> [ auto_gate = read(RK_MMU_AUTO_GATING); auto_gate |= BIT(31); write(...) ]

Thanks -- that's clearly the right shape (read-modify-write, before paging is
enabled, keeping the reset value instead of my clobbering 0x2).

I rebuilt v7.1-rc6 (with the rocket RK3568 series + your per-device-ops work)
using your bit-31 version and tested it on a ROCK 3B: the NPU IOMMU comes up and
services the NPU's DMA cleanly -- the NPU probes, attaches its domain, and runs
repeated conv submissions with no DMA_READ_ERROR and no page-walk stall. No
regression from the write.

To be precise about what I can and can't show: I tested both ways on v7.1-rc6 --
with your bit-31 write, and on the reset value (0x3) -- and the NPU
IOMMU services
the NPU's reads with zero faults in both cases (no DMA_READ_ERROR, no page-walk
stall). So I don't have a failing baseline here that bit-31 visibly
fixes. Is the
AUTO_GATING write needed on current mainline, or only under conditions I'm not
reproducing (a particular traffic pattern / silicon rev)? I'll keep the patch in
your form unless you'd prefer to drop it.

One question so I document it correctly: what does bit 31 of RK_MMU_AUTO_GATING
control on the v2 block -- is it a master "disable internal auto clock-gating"
for the page-table walker (i.e. so a TLB-miss walk's AXI master keeps its clock
to completion)? The RK3568 TRM I have doesn't cover the IOMMU registers, so a
one-line description would let me write an accurate comment.



Kind regards,
Midgy

Le ven. 5 juin 2026 ? 03:59, Chaoyi Chen <chaoyi.chen at rock-chips.com> a ?crit :
>
> Hello Midgy,
>
> On 6/4/2026 9:52 PM, Midgy BALON wrote:
> > On the RK356x v1 IOMMU, RK_MMU_AUTO_GATING resets to 0x3. Bit 1 enables
> > auto clock-gating of the page-table walker, so the walker's AXI master
> > loses its clock between transactions; a TLB-miss page walk then never
> > completes and the IOMMU is left stuck (PAGING_ENABLED, never IDLE).
> >
> > Clear bit 1 (keeping bit 0, the slave-port gate) once paging is enabled
> > so the walker keeps its clock. This is required for the RK3568 NPU MMU.
> >
> > Signed-off-by: Midgy BALON <midgy971 at gmail.com>
> > ---
> >  drivers/iommu/rockchip-iommu.c | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> >
> > diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> > index 4da80136933c4..e3d8b6e9ca12b 100644
> > --- a/drivers/iommu/rockchip-iommu.c
> > +++ b/drivers/iommu/rockchip-iommu.c
> > @@ -953,6 +953,18 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
> >
> >       ret = rk_iommu_enable_paging(iommu);
> >
> > +     if (!ret) {
> > +             /*
> > +              * RK356x v1 IOMMU: RK_MMU_AUTO_GATING bit 1 enables page-walker
> > +              * auto clock-gating; the walker's AXI master then loses its clock
> > +              * between transactions and a TLB-miss page walk never completes,
> > +              * leaving the IOMMU stuck (PAGING_ENABLED, never IDLE).  Clear
> > +              * bit 1 (keep bit 0, the slave-port gate) once paging is enabled.
> > +              */
> > +             for (i = 0; i < iommu->num_mmu; i++)
> > +                     rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, 0x2);
> > +     }
> > +
> >  out_disable_stall:
> >       rk_iommu_disable_stall(iommu);
> >  out_disable_clocks:
>
> As I said, it is v2. Could you please try using the code below
> instead and see if it works? Thank you.
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 0013cf196c57..89e3a83a0251 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -930,6 +930,7 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
>         struct iommu_domain *domain = iommu->domain;
>         struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
>         int ret, i;
> +       u32 auto_gate;
>
>         ret = clk_bulk_enable(iommu->num_clocks, iommu->clocks);
>         if (ret)
> @@ -948,6 +949,10 @@ static int rk_iommu_enable(struct rk_iommu *iommu)
>                                rk_ops->mk_dtentries(rk_domain->dt_dma));
>                 rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
>                 rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
> +
> +               auto_gate = rk_iommu_read(iommu->bases[i], RK_MMU_AUTO_GATING);
> +               auto_gate |= BIT(31);
> +               rk_iommu_write(iommu->bases[i], RK_MMU_AUTO_GATING, auto_gate);
>         }
>
>         ret = rk_iommu_enable_paging(iommu);
>
> --
> Best,
> Chaoyi


From oklopfer37 at gmail.com  Sun Jun  7 15:59:01 2026
From: oklopfer37 at gmail.com (Oren Klopfer)
Date: Sun,  7 Jun 2026 18:59:01 -0400
Subject: [REGRESSION][BISECTED] wireless networking broken on Pinephone Pro
Message-ID: <20260607225901.64019-1-oklopfer37@gmail.com>

Apologies if this is not formatted properly, this is my first submission to the kernel mailing list. WiFi specifications were introduced into the Pinephone Pro device tree in 096bd8c679185f898cae9933c6a68650fa26ea4f, but this causes complete networking failure on some devices. The regression affects all versions v6.18-rc1..v7.1-rc6.

An identical issue was reported for the Pinebook Pro at https://lore.kernel.org/all/aUKOlj-RvTYlrpiS at rock.grzadka/; the regression was reverted in 29d1f56c4f3001b7f547123e0a307c009ac717f8. The errors faced on the Pinephone Pro are exactly the same as were reported for the Pinebook Pro regression.

A previous patch at https://lore.kernel.org/all/20260112-ppp_connectivity-v1-3-284d6e83b212 at gmail.com/ attempted to resolve this issue but never ended up being merged.

Bisection:
096bd8c679185f898cae9933c6a68650fa26ea4f is the first bad commit
commit 096bd8c679185f898cae9933c6a68650fa26ea4f
Author: Peter Robinson <pbrobinson at gmail.com>
Date:   Fri Aug 29 12:38:24 2025 +0100

    arm64: dts: rockchip: Further describe the WiFi for the Pinephone Pro
   
    Update the wake-up pin and associated interupt details for the
    Pinephone Pro WiFi module. Details obtained from the published
    PinephonePro-Schematic-V1.0-20211127.pdf page 19.
   
    Signed-off-by: Peter Robinson <pbrobinson at gmail.com>
    Link: https://lore.kernel.org/r/20250829113826.2029755-1-pbrobinson at gmail.com
    Signed-off-by: Heiko Stuebner <heiko at sntech.de>

 arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

Reverting the commit allows wireless connection to function again. I am not really familiar with the process of submitting a revert patch, but I'd request that this be done on all of 6.18 (LTS), 7.0 (Stable), 7.1 (Mainline). Thanks!

#regzbot introduced: 096bd8c679


From scardracs at disroot.org  Sun Jun  7 16:05:01 2026
From: scardracs at disroot.org (Marco Scardovi)
Date: Mon,  8 Jun 2026 01:05:01 +0200
Subject: [PATCH 0/3] gpio: rockchip: Fix generic IRQ chip leak and modernize resource mapping
Message-ID: <20260607230504.35392-1-scardracs@disroot.org>

Hi all,

This series fixes a generic IRQ chip leak in the gpio-rockchip driver
and performs two small cleanups to use standard platform device helper APIs.

Patch 1 fixes a leak caused by generic IRQ chips not being removed before
IRQ domain teardown.

Patch 2 converts register mapping to use devm_platform_ioremap_resource().

Patch 3 converts interrupt retrieval to use platform_get_irq().

Marco Scardovi (3):
gpio: rockchip: fix generic IRQ chip leak on remove
gpio: rockchip: use devm_platform_ioremap_resource() to map registers
gpio: rockchip: use platform_get_irq() to retrieve interrupt

 drivers/gpio/gpio-rockchip.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

-- 
2.54.0



From scardracs at disroot.org  Sun Jun  7 16:05:02 2026
From: scardracs at disroot.org (Marco Scardovi)
Date: Mon,  8 Jun 2026 01:05:02 +0200
Subject: [PATCH 1/3] gpio: rockchip: fix generic IRQ chip leak on remove
In-Reply-To: <20260607230504.35392-1-scardracs@disroot.org>
References: <20260607230504.35392-1-scardracs@disroot.org>
Message-ID: <20260607230504.35392-2-scardracs@disroot.org>

The driver allocates domain generic chips using
irq_alloc_domain_generic_chips() during probe. However, on driver
remove/teardown, the generic chips are not automatically freed when the
IRQ domain is removed because the domain flags do not include
IRQ_DOMAIN_FLAG_DESTROY_GC.

This causes both the domain generic chips structure and the associated
generic chips to be leaked. Additionally, the generic chips remain on
the global gc_list and may later be visited by generic IRQ chip suspend,
resume, or shutdown callbacks after the GPIO bank has been removed,
potentially resulting in a use-after-free and kernel crash.

Fix the resource leak by explicitly calling
irq_domain_remove_generic_chips() before removing the IRQ domain in
rockchip_gpio_remove().

Fixes: 936ee2675eee ("gpio/rockchip: add driver for rockchip gpio")
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs at disroot.org>
---
 drivers/gpio/gpio-rockchip.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index bc97d5d5d329..9478a58f1caa 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -802,8 +802,10 @@ static void rockchip_gpio_remove(struct platform_device *pdev)
 	struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
 
 	irq_set_chained_handler_and_data(bank->irq, NULL, NULL);
-	if (bank->domain)
+	if (bank->domain) {
+		irq_domain_remove_generic_chips(bank->domain);
 		irq_domain_remove(bank->domain);
+	}
 	gpiochip_remove(&bank->gpio_chip);
 }
 
-- 
2.54.0



From scardracs at disroot.org  Sun Jun  7 16:05:04 2026
From: scardracs at disroot.org (Marco Scardovi)
Date: Mon,  8 Jun 2026 01:05:04 +0200
Subject: [PATCH 3/3] gpio: rockchip: use platform_get_irq() to retrieve interrupt
In-Reply-To: <20260607230504.35392-1-scardracs@disroot.org>
References: <20260607230504.35392-1-scardracs@disroot.org>
Message-ID: <20260607230504.35392-4-scardracs@disroot.org>

The driver currently uses irq_of_parse_and_map() to parse and map the
GPIO bank interrupt from the device tree node. Since the bank device is
represented by a platform_device, use the standard platform_get_irq()
API instead. This integrates cleanly with the platform device framework
and ensures proper error propagation (such as -EPROBE_DEFER).

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs at disroot.org>
---
 drivers/gpio/gpio-rockchip.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 8647d006d103..77b239a9a601 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -654,9 +654,10 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 	if (IS_ERR(bank->reg_base))
 		return PTR_ERR(bank->reg_base);
 
-	bank->irq = irq_of_parse_and_map(bank->of_node, 0);
-	if (!bank->irq)
-		return -EINVAL;
+	ret = platform_get_irq(pdev, 0);
+	if (ret < 0)
+		return ret;
+	bank->irq = ret;
 
 	bank->clk = devm_clk_get_enabled(bank->dev, NULL);
 	if (IS_ERR(bank->clk))
-- 
2.54.0



From scardracs at disroot.org  Sun Jun  7 16:05:03 2026
From: scardracs at disroot.org (Marco Scardovi)
Date: Mon,  8 Jun 2026 01:05:03 +0200
Subject: [PATCH 2/3] gpio: rockchip: use devm_platform_ioremap_resource() to map registers
In-Reply-To: <20260607230504.35392-1-scardracs@disroot.org>
References: <20260607230504.35392-1-scardracs@disroot.org>
Message-ID: <20260607230504.35392-3-scardracs@disroot.org>

Currently, the driver retrieves the memory resource with
of_address_to_resource() and maps it with devm_ioremap_resource().

Since the bank device is a platform_device, simplify and modernize the
code by using devm_platform_ioremap_resource(). This also removes the
need for the local struct resource variable.

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Marco Scardovi <scardracs at disroot.org>
---
 drivers/gpio/gpio-rockchip.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index 9478a58f1caa..8647d006d103 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -647,15 +647,10 @@ static void rockchip_clk_put(void *data)
 
 static int rockchip_get_bank_data(struct rockchip_pin_bank *bank)
 {
-	struct resource res;
+	struct platform_device *pdev = to_platform_device(bank->dev);
 	int id = 0, ret;
 
-	if (of_address_to_resource(bank->of_node, 0, &res)) {
-		dev_err(bank->dev, "cannot find IO resource for bank\n");
-		return -ENOENT;
-	}
-
-	bank->reg_base = devm_ioremap_resource(bank->dev, &res);
+	bank->reg_base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(bank->reg_base))
 		return PTR_ERR(bank->reg_base);
 
-- 
2.54.0



From chaoyi.chen at rock-chips.com  Sun Jun  7 18:40:36 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 8 Jun 2026 09:40:36 +0800
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
Message-ID: <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>

Hi Midgy,

On 6/8/2026 5:03 AM, Midgy Balon wrote:
> Hi Chaoyi,
> 
> Thanks a lot for looking at this -- input from Rockchip is exactly what this
> series needs.
> 
>> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than v1,
>> implying it should support 40-bit PAs. Nevertheless, please note that the
>> upper limit for DTE is 32 bits.
> 
> Understood, and that 32-bit-DTE note is the crux of the trouble I had, so let
> me lay out what I see and ask how you'd prefer to solve it.
> 
> The mainline node is already v2 (rockchip,rk3568-iommu in rk356x-base.dtsi).
> The problem on this 8 GiB board: with the v2 ops the page-table allocations
> (gfp_flags == 0) can land above 4 GiB, so the DTE ends up > 32 bits and the
> NPU's first translation faults with DMA_READ_ERROR. To work around that I had
> switched the NPU MMU to the v1 compatible (rockchip,iommu), whose ops set
> GFP_DMA32 and keep the DTE sub-4 GiB. That works in isolation, but because the
> driver keeps a single global rk_ops, a v1 NPU MMU then trips
> WARN_ON(rk_ops != ops) against the SoC's v2 instances (VOP/VDEC), which is why
> I based the series on Simon's per-device-ops work.
> 
> So my question: with per-device ops in place, what's the intended way to keep
> the NPU MMU on v2 *and* cap its DTE at 32 bits on boards with >4 GiB of RAM?
> A v2 ops variant carrying GFP_DMA32 for this device, or is there a register/
> config bit that constrains the DTE address? I'd rather follow the Rockchip
> intent here than carry the v1 workaround. (Simon, cc'd -- this is right next to
> your per-device-ops series.)
>

If Simon's method works, please use it :)

>> Can these operations not be completed via the pmdomain driver?
>> If some operations are controlled by TF-A, are you using open source TF-A?
> 
> Most of it is in pmdomain already. Power-on and NoC de-idle are done by the
> RK3568 NPU power domain (genpd) at power-on -- the driver no longer pokes the
> PMU directly. Two things remain outside it:
> 
>  - vdd_npu: I mark it regulator-always-on in DT rather than wiring it as the
>    domain's domain-supply, because as a domain-supply it created a device-link
>    to the I2C PMIC (rk809) and genpd's power-off QoS-save path then hung
>    reading the NPU QoS registers behind the (gated) NoC. If there's a clean way
>    to let genpd own vdd_npu without that I2C ordering deadlock I'd much prefer
>    that -- pointers welcome.
>

Please refer to the patch below regarding the RK3588 NPU pmdomain.
In short, you need to set a "need_regulator" for the RK3568 NPU pmdomain.

https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/

>  - the NPU compute clock (PVTPLL): set from the driver via SCMI, and only
>    needed for actual compute, not for bring-up.
> 
> One more pmdomain observation from testing, possibly relevant to how the NPU
> domain should be modelled: the domain's power-off/on cycle doesn't reliably
> re-de-idle the NoC. If the NPU is probed after genpd has already powered the
> (unused) domain off, the power-on de-idle fails ("failed to set idle on domain
> 'npu'") and the NPU IOMMU then takes an external abort on its first MMIO access.
> Probing the NPU before the unused-domain power-off, or marking the domain
> always-on, both avoid it. Is the NoC de-idle expected to work on a genpd
> re-power here, or should this domain effectively stay on?
>

Not quite sure what's going on with PVTPLL and NOC.
Maybe @Finley knows about this?

> On TF-A: yes -- bl31 is built from upstream arm-trusted-firmware
> (github.com/ARM-software/arm-trusted-firmware, RK3568 platform), providing PSCI
> and the SCMI clock service. The only closed blob in the boot chain is Rockchip's
> DDR init (rkbin), which is the standard situation for mainline RK356x.

-- 
Best, 
Chaoyi


From chaoyi.chen at rock-chips.com  Sun Jun  7 18:45:53 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 8 Jun 2026 09:45:53 +0800
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the
 RK356x v1 IOMMU
In-Reply-To: <CA+GS1Y16++cztPxdUGLrPA73ENm4vJGFrjm-jP8r=8OQqcMJGA@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <20260604135255.62682-7-midgy971@gmail.com>
 <e44b506e-e9d2-48e3-acea-ab28b7be9b37@rock-chips.com>
 <CA+GS1Y16++cztPxdUGLrPA73ENm4vJGFrjm-jP8r=8OQqcMJGA@mail.gmail.com>
Message-ID: <0919ffcc-81c3-483a-a3ba-404b455c2040@rock-chips.com>

Hi Midgy,

On 6/8/2026 5:05 AM, Midgy Balon wrote:
> Hi Chaoyi,
> 
>> As I said, it is v2. Could you please try using the code below instead and
>> see if it works?
>> [ auto_gate = read(RK_MMU_AUTO_GATING); auto_gate |= BIT(31); write(...) ]
> 
> Thanks -- that's clearly the right shape (read-modify-write, before paging is
> enabled, keeping the reset value instead of my clobbering 0x2).
> 
> I rebuilt v7.1-rc6 (with the rocket RK3568 series + your per-device-ops work)
> using your bit-31 version and tested it on a ROCK 3B: the NPU IOMMU comes up and
> services the NPU's DMA cleanly -- the NPU probes, attaches its domain, and runs
> repeated conv submissions with no DMA_READ_ERROR and no page-walk stall. No
> regression from the write.
> 
> To be precise about what I can and can't show: I tested both ways on v7.1-rc6 --
> with your bit-31 write, and on the reset value (0x3) -- and the NPU
> IOMMU services
> the NPU's reads with zero faults in both cases (no DMA_READ_ERROR, no page-walk
> stall). So I don't have a failing baseline here that bit-31 visibly
> fixes. Is the
> AUTO_GATING write needed on current mainline, or only under conditions I'm not
> reproducing (a particular traffic pattern / silicon rev)? I'll keep the patch in
> your form unless you'd prefer to drop it.
> 
> One question so I document it correctly: what does bit 31 of RK_MMU_AUTO_GATING
> control on the v2 block -- is it a master "disable internal auto clock-gating"
> for the page-table walker (i.e. so a TLB-miss walk's AXI master keeps its clock
> to completion)? The RK3568 TRM I have doesn't cover the IOMMU registers, so a
> one-line description would let me write an accurate comment.
> 

Glad to hear this works. Please refer to the commit below.

[0]: https://github.com/rockchip-linux/kernel/commit/7f8158fb41b5cc8e738aaeebc3637c50ebd74cae
[1]: https://github.com/rockchip-linux/kernel/commit/6a355e5f9a2069a2309e240791bc3aad63b7324e

-- 
Best, 
Chaoyi


From chaoyi.chen at rock-chips.com  Sun Jun  7 20:40:02 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 8 Jun 2026 11:40:02 +0800
Subject: [RFC PATCH v3 6/9] iommu/rockchip: Clear AUTO_GATING bit 1 on the
 RK356x v1 IOMMU
In-Reply-To: <0919ffcc-81c3-483a-a3ba-404b455c2040@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <20260604135255.62682-7-midgy971@gmail.com>
 <e44b506e-e9d2-48e3-acea-ab28b7be9b37@rock-chips.com>
 <CA+GS1Y16++cztPxdUGLrPA73ENm4vJGFrjm-jP8r=8OQqcMJGA@mail.gmail.com>
 <0919ffcc-81c3-483a-a3ba-404b455c2040@rock-chips.com>
Message-ID: <42f1f39f-ab2b-4473-a82a-7ccefad41fcf@rock-chips.com>

On 6/8/2026 9:45 AM, Chaoyi Chen wrote:
> Hi Midgy,
> 
> On 6/8/2026 5:05 AM, Midgy Balon wrote:
>> Hi Chaoyi,
>>
>>> As I said, it is v2. Could you please try using the code below instead and
>>> see if it works?
>>> [ auto_gate = read(RK_MMU_AUTO_GATING); auto_gate |= BIT(31); write(...) ]
>>
>> Thanks -- that's clearly the right shape (read-modify-write, before paging is
>> enabled, keeping the reset value instead of my clobbering 0x2).
>>
>> I rebuilt v7.1-rc6 (with the rocket RK3568 series + your per-device-ops work)
>> using your bit-31 version and tested it on a ROCK 3B: the NPU IOMMU comes up and
>> services the NPU's DMA cleanly -- the NPU probes, attaches its domain, and runs
>> repeated conv submissions with no DMA_READ_ERROR and no page-walk stall. No
>> regression from the write.
>>
>> To be precise about what I can and can't show: I tested both ways on v7.1-rc6 --
>> with your bit-31 write, and on the reset value (0x3) -- and the NPU
>> IOMMU services
>> the NPU's reads with zero faults in both cases (no DMA_READ_ERROR, no page-walk
>> stall). So I don't have a failing baseline here that bit-31 visibly
>> fixes. Is the
>> AUTO_GATING write needed on current mainline, or only under conditions I'm not
>> reproducing (a particular traffic pattern / silicon rev)? I'll keep the patch in
>> your form unless you'd prefer to drop it.
>>
>> One question so I document it correctly: what does bit 31 of RK_MMU_AUTO_GATING
>> control on the v2 block -- is it a master "disable internal auto clock-gating"
>> for the page-table walker (i.e. so a TLB-miss walk's AXI master keeps its clock
>> to completion)? The RK3568 TRM I have doesn't cover the IOMMU registers, so a
>> one-line description would let me write an accurate comment.
>>
> 
> Glad to hear this works. Please refer to the commit below.
> 
> [0]: https://github.com/rockchip-linux/kernel/commit/7f8158fb41b5cc8e738aaeebc3637c50ebd74cae
> [1]: https://github.com/rockchip-linux/kernel/commit/6a355e5f9a2069a2309e240791bc3aad63b7324e
> 

It looks like RGA needs this patch too, and it has already been merged :).

https://lore.kernel.org/all/20260428-spu-iommudtefix-v2-1-f592f579e508 at pengutronix.de/

-- 
Best, 
Chaoyi


From simon at symple.nz  Sun Jun  7 22:11:11 2026
From: simon at symple.nz (Simon Wright)
Date: Mon, 8 Jun 2026 17:11:11 +1200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5797ac61-dc61-4182-ac60-cc377564ff90@collabora.com>
 <2565c949-a558-415f-8c79-e47812db8341@symple.nz>
 <e3b93bda-fed8-4f21-b3d8-cdf28bfaba1c@collabora.com>
 <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
Message-ID: <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>

Hi Detlev,

Following up on the BL31 lead from my last mail -- we dug further and
found the root cause.

It's an un-primed hardware state after power-up, not BL31 and not a
per-frame register. The Rockchip BSP runs a one-shot priming decode at
every decoder power-on -- rk3576_workaround_run() in
drivers/video/rockchip/mpp/hack/mpp_hack_rk3576.c builds a tiny
self-contained H.264 task and runs it through the decoder at probe and
on every pm_runtime resume. Mainline rkvdec has no equivalent, so the
first decode(s) after each power-up run with indeterminate internal
deblock state.

That makes it a non-deterministic power-up-state race, which is
consistent with everything in the thread: your inability to reproduce
it, the "10% of the time vs every time" split between the two reports,
and the BL31 correlation I sent last time. The odds depend on what the
boot stack leaves in the IP, which would explain why it tracked BL31
version -- but the warmup removes that dependence. (It's also why the
vendor driver is always correct: it does this priming; that's what it
has that mainline doesn't, rather than a hardware difference.)

The fix is to run that warmup at pm_runtime resume -- the minimal
sufficient trigger; running it only at start_streaming left a ~10%
residual. With it on we get 64/64 decodes bit-exact against a
reproduced baseline race, on the same v1.20 Armbian stack that
previously showed the bug; with it off the race returns. So it's
independent of BL31.

A reference implementation -- the DMA priming buffer plus the
link-register kick sequence, ported from the BSP -- is in the repo I
shared (the warmup code itself is in the sibling rkvdec-vdpu383-vp9 /
-av1 repos, src/rkvdec-link.c):

  https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug

I'm not sure of the right mainline form for a vendor-disassembly-
derived priming sequence, so I've left it as a report + reference
rather than a patch -- you're much better placed to decide how, or
whether, it belongs in rkvdec. Happy to test any version on the RK3576
boards here.

(This is a correctness fix only; mainline VDPU383 throughput is a
separate matter and isn't affected by it.)

Regards,
Simon


From hrushirajg23 at gmail.com  Sun Jun  7 23:09:38 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  8 Jun 2026 11:39:38 +0530
Subject: [PATCH v7 0/2] arm64: dts: rockchip: add Vicharak Axon board support
Message-ID: <20260608060940.52549-1-hrushirajg23@gmail.com>

This series adds initial device tree support for the Vicharak Axon
single-board computer, which is based on the Rockchip RK3588 SoC.

The Vicharak Axon is a feature-rich SBC targeting developer and embedded
use cases. It ships with:

  - Rockchip RK3588 (4x Cortex-A76 + 4x Cortex-A55)
  - RK806 PMIC providing all SoC power domains
  - eMMC 5.1 (on-board) and microSD slot
  - Gigabit Ethernet via RGMII (RTL8211F)
  - Dual HDMI 2.1 output and one HDMI 2.0 input (receiver)
  - PCIe 3.0 x4 and two PCIe 2.0 slots
  - SATA 3.0
  - USB 2.0 host ports (EHCI/OHCI)
  - NXP PCA9554 I/O expander for status LEDs
  - Haoyu HYM8563 RTC

Changes since v6:
- Dropped vendor-prefixes patch; the vicharak prefix was already
  submitted upstream by another contributor.
- Added Acked-by from Krzysztof Kozlowski to the binding patch.
- Removed redundant status = okay from newly-defined nodes (leds,
  hym8563, pca9554) as noted by Krzysztof Kozlowski.
- Removed stale mmc2 = &sdio alias (sdio was removed in v4).
- Removed leftover #include <dt-bindings/usb/pd.h> (TypeC removed).
- Removed unused fixed regulators: pcie20_avdd0v85, pcie20_avdd1v8,
  pcie30_avdd0v75, pcie30_avdd1v8, sata_vcc_5v0, vcc0_4v0/vcc4v0_sys.

Changes since v5:
- Enabled i2s5_8ch and i2s6_8ch CPU DAIs to resolve probe deferral
  for hdmi0_sound and hdmi1_sound.

Changes since v4:
- Re-enabled combphy2_psu, required PHY for pcie2x1l1.
- Fixed alphabetical sorting of rk3588-vicharak-axon.dtb in Makefile.

Changes since v3:
- Removed sdio_pwrseq and wireless-wlan pinctrl nodes (Wi-Fi removed).
- Removed unused u2phy0, u2phy0_otg, u2phy1, u2phy1_otg nodes.

Changes since v2:
- Split the dt-bindings patch into separate patches as requested.
- Removed invalid enable-gpios from HDMI nodes.
- Fixed copy-paste error in rk806_dvs1_null pinctrl node.

Changes since v1:
- Renamed rk3588-axon.dts to rk3588-vicharak-axon.dts.
- Added binding patch for board (rockchip.yaml).
- Renamed regulator nodes to the standard regulator-name pattern.
- Removed mem-supply properties from cpu nodes.
- Fixed pcie20_avdd0v85 vin-supply mismatch.
- Removed obsolete regulator-compatible property.
- Removed invalid regulator-init-microvolt property.
- Removed dangling enable-active-high from fixed regulators.
- Cleaned up unneeded i2c3 / es8388 nodes.
- Added missing vpcie3v3-supply properties to PCIe nodes.

Hrushiraj Gandhi (2):
  dt-bindings: arm: rockchip: add Vicharak Axon board
  arm64: dts: rockchip: add Vicharak Axon board

 .../devicetree/bindings/arm/rockchip.yaml     |   5 +
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 926 ++++++++++++++++++
 3 files changed, 932 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

-- 
2.47.3



From hrushirajg23 at gmail.com  Sun Jun  7 23:09:39 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  8 Jun 2026 11:39:39 +0530
Subject: [PATCH v7 1/2] dt-bindings: arm: rockchip: add Vicharak Axon board
In-Reply-To: <20260608060940.52549-1-hrushirajg23@gmail.com>
References: <20260608060940.52549-1-hrushirajg23@gmail.com>
Message-ID: <20260608060940.52549-2-hrushirajg23@gmail.com>

Add the device tree binding for the Vicharak Axon single-board
computer based on the Rockchip RK3588 SoC.

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 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 1a9dde18626d..b023d4cc9842 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1306,6 +1306,11 @@ properties:
           - const: turing,rk1
           - const: rockchip,rk3588
 
+      - description: Vicharak Axon
+        items:
+          - const: vicharak,axon
+          - const: rockchip,rk3588
+
       - description: WolfVision PF5 mainboard
         items:
           - const: wolfvision,rk3568-pf5
-- 
2.47.3



From hrushirajg23 at gmail.com  Sun Jun  7 23:09:40 2026
From: hrushirajg23 at gmail.com (Hrushiraj Gandhi)
Date: Mon,  8 Jun 2026 11:39:40 +0530
Subject: [PATCH v7 2/2] arm64: dts: rockchip: add Vicharak Axon board
In-Reply-To: <20260608060940.52549-1-hrushirajg23@gmail.com>
References: <20260608060940.52549-1-hrushirajg23@gmail.com>
Message-ID: <20260608060940.52549-3-hrushirajg23@gmail.com>

Add initial support for the Vicharak Axon single-board computer based on
the Rockchip RK3588 SoC.

The board supports:

- eMMC storage
- microSD card
- Gigabit Ethernet
- HDMI output (dual HDMI)
- HDMI input
- USB 2.0 host ports
- PCIe 2.0 slots
- PCIe 3.0 x4 slot
- SATA
- RTC
- Status LEDs

The board uses an RK806 PMIC and provides the regulators required by
the RK3588 SoC.

Signed-off-by: Hrushiraj Gandhi <hrushirajg23 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../dts/rockchip/rk3588-vicharak-axon.dts     | 926 ++++++++++++++++++
 2 files changed, 927 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..b10c6d80c5cc 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -211,6 +211,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou-video-demo.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-vicharak-axon.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-v10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-gameforce-ace.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
new file mode 100644
index 000000000000..b4e33922cfba
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-vicharak-axon.dts
@@ -0,0 +1,926 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Vicharak Axon";
+	compatible = "vicharak,axon", "rockchip,rk3588";
+
+	aliases {
+		mmc0 = &sdmmc;
+		mmc1 = &sdhci;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	hdmi1-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi1_con_in: endpoint {
+				remote-endpoint = <&hdmi1_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		power_led: power-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 0 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+
+		status_led: status-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "none";
+		};
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_io_expander: regulator-vcc3v3-io-expander {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_io_expander";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+	};
+
+	vcc3v3_pcie20_sata30: regulator-vcc3v3-pcie20-sata30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie20_sata30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc3v3_pcie30: regulator-vcc3v3-pcie30 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_pcie30";
+		regulator-boot-on;
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_HIGH>;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_usb20_host: regulator-vcc5v0-usb20-host {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_usb20_host";
+		regulator-boot-on;
+		regulator-always-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+};
+
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "output";
+	phy-handle = <&rgmii_phy>;
+	phy-mode = "rgmii-rxid";
+	phy-supply = <&vcc_3v3_s3>;
+	pinctrl-0 = <&gmac1_rgmii_bus
+				&gmac1_rgmii_clk
+				&gmac1_rx_bus2
+				&gmac1_tx_bus2
+				&gmac1_miim>;
+	pinctrl-names = "default";
+	snps,reset-active-low;
+	snps,reset-delays-us = <0 20000 100000>;
+	snps,reset-gpio = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	rx_delay = <0x00>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi1 {
+	status = "okay";
+};
+
+&hdmi1_in {
+	hdmi1_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_hdmi1>;
+	};
+};
+
+&hdmi1_out {
+	hdmi1_out_con: endpoint {
+		remote-endpoint = <&hdmi1_con_in>;
+	};
+};
+
+&hdmi1_sound {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_hpd>;
+	pinctrl-names = "default";
+	hpd-gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&hdptxphy1 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m2_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x42>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		fcs,suspend-voltage-selector = <1>;
+		reg = <0x43>;
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1050000>;
+		regulator-min-microvolt = <550000>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtc_int>;
+		wakeup-source;
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-enable-ramp-delay = <500>;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	pca9554: gpio at 24 {
+		compatible = "nxp,pca9554";
+		#gpio-cells = <2>;
+		gpio-controller;
+		reg = <0x24>;
+		vcc-supply = <&vcc3v3_io_expander>;
+	};
+};
+
+&i2s5_8ch {
+	status = "okay";
+};
+
+&i2s6_8ch {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vcc_1v8_s3>;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
+	disable-wp;
+	max-frequency = <200000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc_3v3_s3>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clock-rates = <200000000>;
+	assigned-clocks = <&cru CLK_SPI2>;
+	num-cs = <1>;
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	pmic at 0 {
+		reg = <0>;
+		compatible = "rockchip,rk806";
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default", "pmic-power-off";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+					<&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		pinctrl-1 = <&rk806_dvs1_pwrdn>;
+		spi-max-frequency = <1000000>;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		rk806_dvs1_null: rk806_dvs1_null {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_slp: rk806_dvs1_slp {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs1_pwrdn: rk806_dvs1_pwrdn {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: rk806_dvs1_rst {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_null: rk806_dvs2_null {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_slp: rk806_dvs2_slp {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_pwrdn: rk806_dvs2_pwrdn {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: rk806_dvs2_rst {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_dvs: rk806_dvs2_dvs {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: rk806_dvs2_gpio {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: rk806_dvs3_null {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_slp: rk806_dvs3_slp {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_pwrdn: rk806_dvs3_pwrdn {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: rk806_dvs3_rst {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_dvs: rk806_dvs3_dvs {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: rk806_dvs3_gpio {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		regulators {
+			vdd_gpu_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <837500>;
+				regulator-max-microvolt = <837500>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&mdio1 {
+	rgmii_phy: phy at 1 {
+		compatible = "ethernet-phy-ieee802.3-c22";
+		reg = <0x1>;
+	};
+};
+
+&pcie2x1l0 {
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	vpcie3v3-supply = <&vcc3v3_pcie20_sata30>;
+	status = "okay";
+};
+
+&pcie2x1l2 {
+	status = "disabled";
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3_reset>;
+	reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_pcie30>;
+	status = "okay";
+};
+
+&pinctrl {
+
+	hdmirx {
+		hdmirx_hpd: hdmirx-5v-detection {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+
+	hym8563 {
+		rtc_int: rtc-int {
+			rockchip,pins =
+				<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	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>;
+		};
+	};
+
+	pcie3 {
+		pcie3_reset: pcie3-reset {
+			rockchip,pins =
+				<4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+};
+
+&saradc {
+	vref-supply = <&avcc_1v8_s0>;
+	status = "okay";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&tsadc {
+	status = "okay";
+};
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_usb20_host>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_hdmi1: endpoint at ROCKCHIP_VOP2_EP_HDMI1 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI1>;
+		remote-endpoint = <&hdmi1_in_vp1>;
+	};
+};
-- 
2.47.3



From kernel at airkyi.com  Mon Jun  8 00:08:03 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:03 +0800
Subject: [PATCH 3/5] phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge
In-Reply-To: <20260608070805.88-1-kernel@airkyi.com>
References: <20260608070805.88-1-kernel@airkyi.com>
Message-ID: <20260608070805.88-4-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>
Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
(no changes since v1)

---
 drivers/phy/rockchip/Kconfig              |  2 ++
 drivers/phy/rockchip/phy-rockchip-typec.c | 13 +++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607..9173d3b4fef4 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -119,6 +119,8 @@ config PHY_ROCKCHIP_SNPS_PCIE3
 config PHY_ROCKCHIP_TYPEC
 	tristate "Rockchip TYPEC PHY Driver"
 	depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
+	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 d9701b6106d5..48070b50416e 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -54,6 +54,7 @@
 
 #include <linux/mfd/syscon.h>
 #include <linux/phy/phy.h>
+#include <drm/bridge/aux-bridge.h>
 
 #define CMN_SSM_BANDGAP			(0x21 << 2)
 #define CMN_SSM_BIAS			(0x22 << 2)
@@ -1162,16 +1163,24 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
 
 	for_each_available_child_of_node(np, child_np) {
 		struct phy *phy;
+		ret = 0;
 
-		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"))
+			ret = drm_aux_bridge_register_from_node(dev, child_np);
+		} else if (of_node_name_eq(child_np, "usb3-port"))
 			phy = devm_phy_create(dev, child_np,
 					      &rockchip_usb3_phy_ops);
 		else
 			continue;
 
+		if (ret) {
+			pm_runtime_disable(dev);
+			of_node_put(child_np);
+			return ret;
+		}
+
 		if (IS_ERR(phy)) {
 			dev_err(dev, "failed to create phy: %pOFn\n",
 				child_np);
-- 
2.54.0



From kernel at airkyi.com  Mon Jun  8 00:08:01 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:01 +0800
Subject: [PATCH 1/5] drm/bridge: Implement generic USB Type-C DP HPD bridge
In-Reply-To: <20260608070805.88-1-kernel@airkyi.com>
References: <20260608070805.88-1-kernel@airkyi.com>
Message-ID: <20260608070805.88-2-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>
Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v2:
- Add copyright text.
- Remove useless goto.

---
 drivers/gpu/drm/bridge/Kconfig                | 10 ++++
 drivers/gpu/drm/bridge/Makefile               |  1 +
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 54 +++++++++++++++++++
 3 files changed, 65 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 c3209b0f4678..d92e93875793 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 beab5b695a6e..c4761526ba0a 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..c09579ff7ab9
--- /dev/null
+++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Chaoyi Chen <chaoyi.chen at rock-chips.com>
+ */
+#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)
+		return NOTIFY_OK;
+
+	/*
+	 * 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));
+
+	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_AUTHOR("Chaoyi Chen <chaoyi.chen at rock-chips.com>");
+MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE");
+MODULE_LICENSE("GPL");
-- 
2.54.0



From kernel at airkyi.com  Mon Jun  8 00:08:02 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:02 +0800
Subject: [PATCH 2/5] drm/bridge: aux: Add drm_aux_bridge_register_from_node()
In-Reply-To: <20260608070805.88-1-kernel@airkyi.com>
References: <20260608070805.88-1-kernel@airkyi.com>
Message-ID: <20260608070805.88-3-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>
Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
Changes in v2:
- Fix incorrect function names in the documentation comments.

---
 drivers/gpu/drm/bridge/aux-bridge.c | 26 +++++++++++++++++++++++---
 include/drm/bridge/aux-bridge.h     |  6 ++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index 1ed21a8713bf..06a1466f49bd 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -33,8 +33,9 @@ static void drm_aux_bridge_unregister_adev(void *_adev)
 }
 
 /**
- * drm_aux_bridge_register - Create a simple bridge device to link the chain
+ * drm_aux_bridge_register_from_node - 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.54.0



From kernel at airkyi.com  Mon Jun  8 00:08:00 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:00 +0800
Subject: [PATCH 0/5] drm/bridge: Implement generic USB Type-C DP HPD bridge
Message-ID: <20260608070805.88-1-kernel@airkyi.com>

From: Chaoyi Chen <chaoyi.chen at rock-chips.com>

This series is split from the v15 "Add Type-C DP support for RK3399 EVB
IND board" series [1]. It focuses on the DRM bridge and Rockchip
platform CDN-DP controller changes.

[1] https://lore.kernel.org/all/20260304094152.92-1-kernel at airkyi.com/

====
1. Generic Type-C DP HPD bridge

Currently, several USB-C controller drivers register their own DP HPD
bridge via aux-hpd-bridge.c, each duplicating the same logic. For
devicetree based platforms, the USB-C controller may vary across boards,
and not every USB-C controller driver implements this feature. Patch 1
implements a generic DP HPD bridge that monitors Type-C bus events and
automatically creates an HPD bridge when a Type-C port device with DP
SVID is registered.

2. Multiple bridge model for CDN-DP

The RK3399 has two USB/DP combo PHY and one CDN-DP controller. Patch 5
introduces a multi-bridge model where each PHY port gets a separate
encoder and bridge, allowing flexible selection of the output PHY port.
This is based on the DRM AUX HPD bridge rather than extcon.

====
Patch 1 adds generic USB Type-C DP HPD bridge (Dmitry, Heikki).
Patch 2 adds new API drm_aux_bridge_register_from_node() (Neil).
Patch 3 adds DRM AUX bridge support for RK3399 USBDP PHY (Neil).
Patch 4 drops CDN-DP's extcon dependency when Type-C is present (Dmitry).
Patch 5 adds multiple bridges to support PHY port selection (Dmitry, Luca).

Changes in v2:
- Link to v1: https://lore.kernel.org/all/20260521032854.103-1-kernel at airkyi.com/
- Add copyright text.
- Remove useless goto.
- Fix incorrect function names in the documentation comments.
- Fix the check logic for dp->active_port (0 is valid).
- Fix the uninitialized prev_port.
- Remove duplicate logic from cdn_dp_switch_port().
- Fix the prototype of cdn_dp_bridge_hpd_notify().
- Properly release connector->fwnode.
- Properly release next_bridge.

Chaoyi Chen (5):
  drm/bridge: Implement generic USB Type-C DP HPD bridge
  drm/bridge: aux: Add drm_aux_bridge_register_from_node()
  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

 drivers/gpu/drm/bridge/Kconfig                |  10 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/aux-bridge.c           |  26 +-
 .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  |  54 +++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c        | 358 ++++++++++++++----
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |  18 +-
 drivers/phy/rockchip/Kconfig                  |   2 +
 drivers/phy/rockchip/phy-rockchip-typec.c     |  13 +-
 include/drm/bridge/aux-bridge.h               |   6 +
 10 files changed, 418 insertions(+), 71 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c

-- 
2.54.0



From kernel at airkyi.com  Mon Jun  8 00:08:05 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:05 +0800
Subject: [PATCH 5/5] drm/rockchip: cdn-dp: Add multiple bridges to support PHY port selection
In-Reply-To: <20260608070805.88-1-kernel@airkyi.com>
References: <20260608070805.88-1-kernel@airkyi.com>
Message-ID: <20260608070805.88-6-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>
Reviewed-by: Luca Ceresoli <luca.ceresoli at bootlin.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
Changes in v2:
- Fix the check logic for dp->active_port (0 is valid).
- Fix the uninitialized prev_port.
- Remove duplicate logic from cdn_dp_switch_port().
- Fix the prototype of cdn_dp_bridge_hpd_notify().
- Properly release connector->fwnode.
- Properly release next_bridge.

---
 drivers/gpu/drm/rockchip/Kconfig       |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 333 ++++++++++++++++++++-----
 drivers/gpu/drm/rockchip/cdn-dp-core.h |  18 +-
 3 files changed, 294 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 1479b8c4ed40..cb97690c5a5d 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -59,6 +59,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 9068118859e2..f2eaad61ba44 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -28,16 +28,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
@@ -192,14 +193,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;
 }
 
@@ -254,12 +268,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 = NULL;
+	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;
 }
 
@@ -268,12 +315,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) {
@@ -551,6 +599,50 @@ 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;
+
+	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->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)
 {
@@ -572,6 +664,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;
 
@@ -581,7 +674,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;
@@ -600,6 +693,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",
@@ -632,6 +728,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);
 }
@@ -639,9 +736,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);
@@ -828,6 +927,17 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge,
 	return ret;
 }
 
+static void cdn_dp_bridge_hpd_notify(struct drm_bridge *bridge,
+				     struct drm_connector *connector,
+				     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,
@@ -838,6 +948,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,
@@ -886,7 +997,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);
 
@@ -945,9 +1057,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,
@@ -967,28 +1082,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);
@@ -1003,26 +1106,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);
@@ -1030,8 +1142,103 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	if (last_bridge) {
+		fwnode_handle_put(connector->fwnode);
+		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;
+		}
+
+		dp->next_bridge_valid = true;
+		dp->next_bridge_list[count] = drm_bridge_get(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)
+		goto out;
+
+	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)) {
+			ret = PTR_ERR(dp_bridge);
+			goto out;
+		}
+		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)
+			goto out;
+	}
+
+	INIT_WORK(&dp->event_work, cdn_dp_pd_event_work);
+
 	for (i = 0; i < dp->ports; i++) {
 		port = dp->port[i];
 
@@ -1045,7 +1252,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		if (ret) {
 			DRM_DEV_ERROR(dev,
 				      "register EXTCON_DISP_DP notifier err\n");
-			return ret;
+			goto out;
 		}
 	}
 
@@ -1054,15 +1261,29 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 	schedule_work(&dp->event_work);
 
 	return 0;
+
+out:
+	for (i = 0; i < MAX_PHY; i++)
+		drm_bridge_put(dp->next_bridge_list[i]);
+
+	return ret;
 }
 
 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)
@@ -1113,10 +1334,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.54.0



From kernel at airkyi.com  Mon Jun  8 00:08:04 2026
From: kernel at airkyi.com (Chaoyi Chen)
Date: Mon,  8 Jun 2026 15:08:04 +0800
Subject: [PATCH 4/5] drm/rockchip: cdn-dp: Support handle lane info without extcon
In-Reply-To: <20260608070805.88-1-kernel@airkyi.com>
References: <20260608070805.88-1-kernel@airkyi.com>
Message-ID: <20260608070805.88-5-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>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
(no changes since v1)

---
 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 177e30445ee8..9068118859e2 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -157,6 +157,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,
@@ -220,7 +223,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))
@@ -386,11 +389,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);
@@ -1029,6 +1035,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,
@@ -1121,14 +1130,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.54.0



From krzk at kernel.org  Mon Jun  8 00:57:58 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Mon, 8 Jun 2026 09:57:58 +0200
Subject: [PATCH v3 1/3] dt-bindings: net: add Realtek r8169 family PCIe
 Ethernet
In-Reply-To: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
References: <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-0-8a8857b39daf@pardini.net>
 <20260605-rk3588-dts-rtl-eth-describe-dt-alias-v3-1-8a8857b39daf@pardini.net>
Message-ID: <20260608-armored-ultra-uakari-ef1d77@quoll>

On Fri, Jun 05, 2026 at 01:49:08PM +0200, Ricardo Pardini wrote:
> Add a binding for fixed/soldered Realtek PCIe Ethernet controllers
> driven by the r8169 driver (RTL8125/8126/8127/8168 and variants).
> 
> The "pciVVVV,DDDD" compatibles are the Open Firmware PCI Bus Binding
> spelling, auto-derived from PCI-SIG vendor/device IDs, but they still
> need a binding when used in a board DT - analogous to "usbVVVV,PPPP"
> compatibles documented in their own bindings (e.g. microchip,lan95xx)
> so board DTs attaching properties (fixed MAC, nvmem cell, ...) to
> these PCI function nodes can be validated.
> 
> Suggested-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> Signed-off-by: Ricardo Pardini <ricardo at pardini.net>
> ---
>  .../devicetree/bindings/net/realtek,r8169.yaml     | 54 ++++++++++++++++++++++
>  MAINTAINERS                                        |  1 +
>  2 files changed, 55 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/realtek,r8169.yaml b/Documentation/devicetree/bindings/net/realtek,r8169.yaml
> new file mode 100644
> index 0000000000000..6923211ff4c93
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/realtek,r8169.yaml

r8169 but no r8169 devices at all. This must match the device name, so
most likely:

realtek,rtl8168.yaml


> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/net/realtek,r8169.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Realtek r8169 family PCIe Ethernet Controllers

rtl8169? 8168? There is no r8169, is there?

> +
> +maintainers:
> +  - Heiner Kallweit <hkallweit1 at gmail.com>
> +
> +description:
> +  PCI function node properties for fixed/soldered Realtek Ethernet
> +  controllers driven by the r8169 driver.

Describe hardware, not drivers.


> +
> +allOf:
> +  - $ref: ethernet-controller.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - pci10ec,8125  # RTL8125 2.5GbE
> +      - pci10ec,8126  # RTL8126 5GbE
> +      - pci10ec,8127  # RTL8127
> +      - pci10ec,8161  # RTL8168 variant
> +      - pci10ec,8162  # RTL8168 variant
> +      - pci10ec,8168  # RTL8168/8111 GbE
> +
> +  reg:
> +    maxItems: 1
> +
> +  local-mac-address: true
> +  mac-address: true
> +  nvmem-cells: true
> +  nvmem-cell-names: true

Drop all above

> +
> +required:
> +  - compatible
> +  - reg
> +
> +additionalProperties: false

uneavaluatedProperties instead

Best regards,
Krzysztof



From midgy971 at gmail.com  Mon Jun  8 01:05:33 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Mon, 8 Jun 2026 10:05:33 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com> <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
Message-ID: <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>

Hello Chaoyi,

Thanks -- this is exactly what I needed.

- v2/DTE: will do. I'll keep building on Simon's per-device-ops series -- with
  that in place the NPU MMU can use the 32-bit-DTE ops (the per-ops GFP_DMA32
  that's already in mainline) without the global rk_ops conflict. I'll
keep it as
  a stated dependency of the v4 cover letter.

- vdd_npu:  I'll switch the RK3568 NPU
  power domain to need_regulator + domain-supply = <&vdd_npu> and drop the
  regulator-always-on workaround. I suspect that's also the right fix for the
  power-off/on de-idle issue I described -- the always-on was really
just papering
  over the domain not being modelled with a regulator. I'll confirm on
the board.

- AUTO_GATING: thanks for the commit references -- I'll keep the bit-31
  read-modify-write form with your Suggested-by and write the comment
from those.
  For the record: on v7.1-rc6 the NPU MMU also completes translations
on the reset
  value (I couldn't reproduce a page-walk stall without the write), so I'll note
  in the commit that it matches the vendor clock-gating handling rather than
  fixing a failure I can reproduce here -- happy to drop it if the iommu
  maintainers would prefer.

- PVTPLL/NoC: I'll follow up with Finley. First I'll check whether the
  need_regulator change resolves the NoC re-power de-idle on its own;
if it still
  I'll bring him the details (the genpd power-on de-idle ack and the
  BUS_IDLE_ST state).

I'll send a v4 with these. Thanks again for the quick, detailed answers.

Kind regards,
Midgy

Le lun. 8 juin 2026 ? 03:40, Chaoyi Chen <chaoyi.chen at rock-chips.com> a ?crit :
>
> Hi Midgy,
>
> On 6/8/2026 5:03 AM, Midgy Balon wrote:
> > Hi Chaoyi,
> >
> > Thanks a lot for looking at this -- input from Rockchip is exactly what this
> > series needs.
> >
> >> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than v1,
> >> implying it should support 40-bit PAs. Nevertheless, please note that the
> >> upper limit for DTE is 32 bits.
> >
> > Understood, and that 32-bit-DTE note is the crux of the trouble I had, so let
> > me lay out what I see and ask how you'd prefer to solve it.
> >
> > The mainline node is already v2 (rockchip,rk3568-iommu in rk356x-base.dtsi).
> > The problem on this 8 GiB board: with the v2 ops the page-table allocations
> > (gfp_flags == 0) can land above 4 GiB, so the DTE ends up > 32 bits and the
> > NPU's first translation faults with DMA_READ_ERROR. To work around that I had
> > switched the NPU MMU to the v1 compatible (rockchip,iommu), whose ops set
> > GFP_DMA32 and keep the DTE sub-4 GiB. That works in isolation, but because the
> > driver keeps a single global rk_ops, a v1 NPU MMU then trips
> > WARN_ON(rk_ops != ops) against the SoC's v2 instances (VOP/VDEC), which is why
> > I based the series on Simon's per-device-ops work.
> >
> > So my question: with per-device ops in place, what's the intended way to keep
> > the NPU MMU on v2 *and* cap its DTE at 32 bits on boards with >4 GiB of RAM?
> > A v2 ops variant carrying GFP_DMA32 for this device, or is there a register/
> > config bit that constrains the DTE address? I'd rather follow the Rockchip
> > intent here than carry the v1 workaround. (Simon, cc'd -- this is right next to
> > your per-device-ops series.)
> >
>
> If Simon's method works, please use it :)
>
> >> Can these operations not be completed via the pmdomain driver?
> >> If some operations are controlled by TF-A, are you using open source TF-A?
> >
> > Most of it is in pmdomain already. Power-on and NoC de-idle are done by the
> > RK3568 NPU power domain (genpd) at power-on -- the driver no longer pokes the
> > PMU directly. Two things remain outside it:
> >
> >  - vdd_npu: I mark it regulator-always-on in DT rather than wiring it as the
> >    domain's domain-supply, because as a domain-supply it created a device-link
> >    to the I2C PMIC (rk809) and genpd's power-off QoS-save path then hung
> >    reading the NPU QoS registers behind the (gated) NoC. If there's a clean way
> >    to let genpd own vdd_npu without that I2C ordering deadlock I'd much prefer
> >    that -- pointers welcome.
> >
>
> Please refer to the patch below regarding the RK3588 NPU pmdomain.
> In short, you need to set a "need_regulator" for the RK3568 NPU pmdomain.
>
> https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/
>
> >  - the NPU compute clock (PVTPLL): set from the driver via SCMI, and only
> >    needed for actual compute, not for bring-up.
> >
> > One more pmdomain observation from testing, possibly relevant to how the NPU
> > domain should be modelled: the domain's power-off/on cycle doesn't reliably
> > re-de-idle the NoC. If the NPU is probed after genpd has already powered the
> > (unused) domain off, the power-on de-idle fails ("failed to set idle on domain
> > 'npu'") and the NPU IOMMU then takes an external abort on its first MMIO access.
> > Probing the NPU before the unused-domain power-off, or marking the domain
> > always-on, both avoid it. Is the NoC de-idle expected to work on a genpd
> > re-power here, or should this domain effectively stay on?
> >
>
> Not quite sure what's going on with PVTPLL and NOC.
> Maybe @Finley knows about this?
>
> > On TF-A: yes -- bl31 is built from upstream arm-trusted-firmware
> > (github.com/ARM-software/arm-trusted-firmware, RK3568 platform), providing PSCI
> > and the SCMI clock service. The only closed blob in the boot chain is Rockchip's
> > DDR init (rkbin), which is the standard situation for mainline RK356x.
>
> --
> Best,
> Chaoyi


From midgy971 at gmail.com  Mon Jun  8 02:14:17 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Mon, 8 Jun 2026 11:14:17 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com> <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
Message-ID: <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>

Hello Chaoyi,

Following up on the need_regulator suggestion -- I implemented and
tested it on the
board, and unfortunately it doesn't avoid the deadlock on RK3568; it
moves it from
boot to the NPU job submit.

What I did: gave the RK3568 NPU power domain a regulator (a DOMAIN_M_R
variant with
need_regulator = true), wired domain-supply = <&vdd_npu>, and dropped the
regulator-always-on workaround.

Boot is now clean and the NPU probes, but there is a warning during boot:

  rockchip-pm-domain ...: Failed to create device link (0x180) with supplier
  0-0020 for .../power-domain at 6

(0-0020 is the rk809 PMIC that supplies vdd_npu.) Then on the first NPU job
submit the board hard-hangs with an RCU stall:

  rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
  rcu:     3-...!: (1 GPs behind) ...
  rcu: rcu_preempt kthread starved for 5115 jiffies! ... RCU_GP_WAIT_FQS(5)
  rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected

My reading: vdd_npu is on the rk809 *I2C* PMIC, so when genpd
enables/disables the
regulator during the NPU's runtime-PM power transition, the I2C
transfer runs in a
context that starves RCU and the box freezes. (I suspect
need_regulator is fine on
the RK3588 NPU because its supply isn't behind an I2C PMIC.) The always-on
workaround avoids this precisely because genpd never touches the I2C
regulator in
that path.

So: for an NPU domain whose supply is an I2C PMIC, is there a
supported way to let
genpd own the regulator without performing the I2C op in the
power-transition path
(a deferred/async regulator enable, or a flag), or should RK3568 keep vdd_npu as
regulator-always-on? For v4 I'll keep always-on unless there's a cleaner path.


Thanks,
Midgy

Le lun. 8 juin 2026 ? 10:05, Midgy Balon <midgy971 at gmail.com> a ?crit :
>
> Hello Chaoyi,
>
> Thanks -- this is exactly what I needed.
>
> - v2/DTE: will do. I'll keep building on Simon's per-device-ops series -- with
>   that in place the NPU MMU can use the 32-bit-DTE ops (the per-ops GFP_DMA32
>   that's already in mainline) without the global rk_ops conflict. I'll
> keep it as
>   a stated dependency of the v4 cover letter.
>
> - vdd_npu:  I'll switch the RK3568 NPU
>   power domain to need_regulator + domain-supply = <&vdd_npu> and drop the
>   regulator-always-on workaround. I suspect that's also the right fix for the
>   power-off/on de-idle issue I described -- the always-on was really
> just papering
>   over the domain not being modelled with a regulator. I'll confirm on
> the board.
>
> - AUTO_GATING: thanks for the commit references -- I'll keep the bit-31
>   read-modify-write form with your Suggested-by and write the comment
> from those.
>   For the record: on v7.1-rc6 the NPU MMU also completes translations
> on the reset
>   value (I couldn't reproduce a page-walk stall without the write), so I'll note
>   in the commit that it matches the vendor clock-gating handling rather than
>   fixing a failure I can reproduce here -- happy to drop it if the iommu
>   maintainers would prefer.
>
> - PVTPLL/NoC: I'll follow up with Finley. First I'll check whether the
>   need_regulator change resolves the NoC re-power de-idle on its own;
> if it still
>   I'll bring him the details (the genpd power-on de-idle ack and the
>   BUS_IDLE_ST state).
>
> I'll send a v4 with these. Thanks again for the quick, detailed answers.
>
> Kind regards,
> Midgy
>
> Le lun. 8 juin 2026 ? 03:40, Chaoyi Chen <chaoyi.chen at rock-chips.com> a ?crit :
> >
> > Hi Midgy,
> >
> > On 6/8/2026 5:03 AM, Midgy Balon wrote:
> > > Hi Chaoyi,
> > >
> > > Thanks a lot for looking at this -- input from Rockchip is exactly what this
> > > series needs.
> > >
> > >> Hmmm. If I understand correctly, the NPU IOMMU should be v2 rather than v1,
> > >> implying it should support 40-bit PAs. Nevertheless, please note that the
> > >> upper limit for DTE is 32 bits.
> > >
> > > Understood, and that 32-bit-DTE note is the crux of the trouble I had, so let
> > > me lay out what I see and ask how you'd prefer to solve it.
> > >
> > > The mainline node is already v2 (rockchip,rk3568-iommu in rk356x-base.dtsi).
> > > The problem on this 8 GiB board: with the v2 ops the page-table allocations
> > > (gfp_flags == 0) can land above 4 GiB, so the DTE ends up > 32 bits and the
> > > NPU's first translation faults with DMA_READ_ERROR. To work around that I had
> > > switched the NPU MMU to the v1 compatible (rockchip,iommu), whose ops set
> > > GFP_DMA32 and keep the DTE sub-4 GiB. That works in isolation, but because the
> > > driver keeps a single global rk_ops, a v1 NPU MMU then trips
> > > WARN_ON(rk_ops != ops) against the SoC's v2 instances (VOP/VDEC), which is why
> > > I based the series on Simon's per-device-ops work.
> > >
> > > So my question: with per-device ops in place, what's the intended way to keep
> > > the NPU MMU on v2 *and* cap its DTE at 32 bits on boards with >4 GiB of RAM?
> > > A v2 ops variant carrying GFP_DMA32 for this device, or is there a register/
> > > config bit that constrains the DTE address? I'd rather follow the Rockchip
> > > intent here than carry the v1 workaround. (Simon, cc'd -- this is right next to
> > > your per-device-ops series.)
> > >
> >
> > If Simon's method works, please use it :)
> >
> > >> Can these operations not be completed via the pmdomain driver?
> > >> If some operations are controlled by TF-A, are you using open source TF-A?
> > >
> > > Most of it is in pmdomain already. Power-on and NoC de-idle are done by the
> > > RK3568 NPU power domain (genpd) at power-on -- the driver no longer pokes the
> > > PMU directly. Two things remain outside it:
> > >
> > >  - vdd_npu: I mark it regulator-always-on in DT rather than wiring it as the
> > >    domain's domain-supply, because as a domain-supply it created a device-link
> > >    to the I2C PMIC (rk809) and genpd's power-off QoS-save path then hung
> > >    reading the NPU QoS registers behind the (gated) NoC. If there's a clean way
> > >    to let genpd own vdd_npu without that I2C ordering deadlock I'd much prefer
> > >    that -- pointers welcome.
> > >
> >
> > Please refer to the patch below regarding the RK3588 NPU pmdomain.
> > In short, you need to set a "need_regulator" for the RK3568 NPU pmdomain.
> >
> > https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/
> >
> > >  - the NPU compute clock (PVTPLL): set from the driver via SCMI, and only
> > >    needed for actual compute, not for bring-up.
> > >
> > > One more pmdomain observation from testing, possibly relevant to how the NPU
> > > domain should be modelled: the domain's power-off/on cycle doesn't reliably
> > > re-de-idle the NoC. If the NPU is probed after genpd has already powered the
> > > (unused) domain off, the power-on de-idle fails ("failed to set idle on domain
> > > 'npu'") and the NPU IOMMU then takes an external abort on its first MMIO access.
> > > Probing the NPU before the unused-domain power-off, or marking the domain
> > > always-on, both avoid it. Is the NoC de-idle expected to work on a genpd
> > > re-power here, or should this domain effectively stay on?
> > >
> >
> > Not quite sure what's going on with PVTPLL and NOC.
> > Maybe @Finley knows about this?
> >
> > > On TF-A: yes -- bl31 is built from upstream arm-trusted-firmware
> > > (github.com/ARM-software/arm-trusted-firmware, RK3568 platform), providing PSCI
> > > and the SCMI clock service. The only closed blob in the boot chain is Rockchip's
> > > DDR init (rkbin), which is the standard situation for mainline RK356x.
> >
> > --
> > Best,
> > Chaoyi


From mripard at kernel.org  Mon Jun  8 02:17:54 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 8 Jun 2026 11:17:54 +0200
Subject: [PATCH 2/2] drm/rockchip: dw_hdmi_qp: expose "overscan" property
In-Reply-To: <CAKTNdwE5uAOc9V+L1J7_QJfW45D-K-vTnpHuktxD2=x9e_4jOQ@mail.gmail.com>
References: <20260602-hdmi-overscan-v1-0-31f71b817c80@flipper.net>
 <20260602-hdmi-overscan-v1-2-31f71b817c80@flipper.net>
 <20260603-glittering-vigilant-beluga-0c6bf6@houat>
 <CAKTNdwE5uAOc9V+L1J7_QJfW45D-K-vTnpHuktxD2=x9e_4jOQ@mail.gmail.com>
Message-ID: <20260608-judicious-maroon-toucanet-a8f610@houat>

Hi Alexey,

On Wed, Jun 03, 2026 at 12:15:04PM +0400, Alexey Charkov wrote:
> On Wed, Jun 3, 2026 at 11:55?AM Maxime Ripard <mripard at kernel.org> wrote:
> >
> > On Tue, Jun 02, 2026 at 09:00:40PM +0400, Alexey Charkov wrote:
> > > Expose the "overscan" connector property as recognized by KWin and the
> > > likes to compensate for TV overscan cropping.
> > >
> > > The CRTC will use the margin values derived from this overscan percentage
> > > in its post-composition scaler to add appropriate blank margins on all
> > > sides of the output image so that the TV doesn't eat up visible content.
> > >
> > > Signed-off-by: Alexey Charkov <alchark at flipper.net>
> > > ---
> > >  drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 16 ++++++++++++++++
> > >  1 file changed, 16 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > > index f35484715c2d..fae44d11dbef 100644
> > > --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > > +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
> > > @@ -137,10 +137,18 @@ dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
> > >                                        struct drm_connector_state *conn_state)
> > >  {
> > >       struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
> > > +     const struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
> > >       struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> > >       union phy_configure_opts phy_cfg = {};
> > > +     unsigned int overscan;
> > >       int ret;
> > >
> > > +     overscan = min(conn_state->tv.overscan, 100u);
> > > +     s->tv_margins.left   = adj_mode->hdisplay * overscan / 200;
> > > +     s->tv_margins.right  = s->tv_margins.left;
> > > +     s->tv_margins.top    = adj_mode->vdisplay * overscan / 200;
> > > +     s->tv_margins.bottom = s->tv_margins.top;
> > > +
> > >       if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
> > >           s->output_bpc == conn_state->hdmi.output_bpc)
> > >               return 0;
> > > @@ -603,6 +611,14 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
> > >               return dev_err_probe(hdmi->dev, PTR_ERR(connector),
> > >                                    "Failed to init bridge connector\n");
> > >
> > > +     ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
> > > +     if (ret)
> > > +             return dev_err_probe(dev, ret,
> > > +                                  "Failed to create TV connector properties\n");
> > > +
> > > +     drm_object_attach_property(&connector->base,
> > > +                                drm->mode_config.tv_overscan_property, 0);
> > > +
> >
> > As the name suggests, it's a legacy property only ever used for TV. You
> > should be using drm_mode_create_tv_margin_properties()
> 
> Hi Maxime, I tried that one before going for the current solution but
> realized that the userspace tooling I care about (KWin in particular)
> doesn't recognize those properties, but it does recognize "overscan".
> Maybe there's a compat helper somewhere that I missed, which would
> translate between the two?
> 
> It is for TVs. Turns out that having a proper right-sized digital
> input interface doesn't prevent them from doing weird stuff with the
> image data, i.e. overscanning and cropping it right where one would
> expect to see the system tray and panel.

When I said "TV", I meant old-school analog TV, not modern HDMI ones :)

I guess it's a Kwin issue then. To my knowledge, there's 0 HDMI driver
implementing the legacy tv properties, when VC4 implements the margin
ones for HDMI.

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-rockchip/attachments/20260608/b6705715/attachment.sig>

From chaoyi.chen at rock-chips.com  Mon Jun  8 02:38:32 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Mon, 8 Jun 2026 17:38:32 +0800
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
 <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
Message-ID: <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>

Hi Midgy,

On 6/8/2026 5:14 PM, Midgy Balon wrote:
> Hello Chaoyi,
> 
> Following up on the need_regulator suggestion -- I implemented and
> tested it on the
> board, and unfortunately it doesn't avoid the deadlock on RK3568; it
> moves it from
> boot to the NPU job submit.
> 
> What I did: gave the RK3568 NPU power domain a regulator (a DOMAIN_M_R
> variant with
> need_regulator = true), wired domain-supply = <&vdd_npu>, and dropped the
> regulator-always-on workaround.
> 
> Boot is now clean and the NPU probes, but there is a warning during boot:
> 
>   rockchip-pm-domain ...: Failed to create device link (0x180) with supplier
>   0-0020 for .../power-domain at 6
> 
> (0-0020 is the rk809 PMIC that supplies vdd_npu.) Then on the first NPU job
> submit the board hard-hangs with an RCU stall:
> 
>   rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
>   rcu:     3-...!: (1 GPs behind) ...
>   rcu: rcu_preempt kthread starved for 5115 jiffies! ... RCU_GP_WAIT_FQS(5)
>   rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected
> 
> My reading: vdd_npu is on the rk809 *I2C* PMIC, so when genpd
> enables/disables the
> regulator during the NPU's runtime-PM power transition, the I2C
> transfer runs in a
> context that starves RCU and the box freezes. (I suspect
> need_regulator is fine on
> the RK3588 NPU because its supply isn't behind an I2C PMIC.) The always-on
> workaround avoids this precisely because genpd never touches the I2C
> regulator in
> that path.
>

No, they are all controlled by RK809.

And This looks werid. Is your rocket driver compiled as a module? 
Please try compiling it as a module. When is the above error printed? 
Please provide the complete boot log.

> So: for an NPU domain whose supply is an I2C PMIC, is there a
> supported way to let
> genpd own the regulator without performing the I2C op in the
> power-transition path
> (a deferred/async regulator enable, or a flag), or should RK3568 keep vdd_npu as
> regulator-always-on? For v4 I'll keep always-on unless there's a cleaner path.
> 

-- 
Best, 
Chaoyi


From diogompaissilva at gmail.com  Mon Jun  8 04:49:40 2026
From: diogompaissilva at gmail.com (Diogo Silva)
Date: Mon, 8 Jun 2026 13:49:40 +0200
Subject: [PATCH v2] drm/rockchip: dsi: Open-code drm_simple_encoder_init()
In-Reply-To: <c8f30973-450e-4995-b6f5-03e7b6afc75b@kwiboo.se>
References: <5277524.h16uAIiOU7@phil> <20260607123739.393974-2-diogompaissilva@gmail.com>
 <c8f30973-450e-4995-b6f5-03e7b6afc75b@kwiboo.se>
Message-ID: <CAJpoHp7uF+Hgr_-oxxZEkaL+XbyLMv4=khMrfsDxPnty6=4oBQ@mail.gmail.com>

Hey Jonas,

> Please base your work on latest drm-misc tree, this has already been
> addressed in commit 3de723684be5 ("drm/rockchip: dw_hdmi: Use drmres
> helpers for encoder resources") [1].

Sorry, I'll rebase it on the DRM tree.

>
> Also instead of open-code, maybe a change to use drmm_encoder_init() is
> more appropriate for some of the other drivers?
>

Wouldn't it be better to first remove the deprecated function and then,
in another patch, change to the managed encoder as an improvement?

BR,
Diogo


From diogompaissilva at gmail.com  Mon Jun  8 05:40:19 2026
From: diogompaissilva at gmail.com (Diogo Silva)
Date: Mon,  8 Jun 2026 14:40:19 +0200
Subject: [PATCH v3] drm/rockchip: Remove dependency on DRM simple helpers
Message-ID: <20260608124018.480365-2-diogompaissilva@gmail.com>

Simple KMS helper are deprecated since they only add an intermediate
layer between drivers and the atomic modesetting.
This patch removes the dependency on drm simple helpers from rockchip
DRM drivers.

Signed-off-by: Diogo Silva <diogompaissilva at gmail.com>
---

v3:
 - rebase on drm-tip tree

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c  | 9 ++++++---
 drivers/gpu/drm/rockchip/cdn-dp-core.c           | 9 ++++++---
 drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c  | 9 +++++++--
 drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 8 ++++++--
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c        | 1 -
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c      | 1 -
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c   | 1 -
 drivers/gpu/drm/rockchip/rk3066_hdmi.c           | 8 ++++++--
 drivers/gpu/drm/rockchip/rockchip_lvds.c         | 9 +++++++--
 drivers/gpu/drm/rockchip/rockchip_rgb.c          | 8 ++++++--
 10 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 776954c7d052..46c245e35d21 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -30,7 +30,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -303,6 +302,10 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rockchip_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
 	.mode_fixup = rockchip_dp_drm_encoder_mode_fixup,
 	.mode_set = rockchip_dp_drm_encoder_mode_set,
@@ -361,8 +364,8 @@ static int rockchip_dp_drm_create_encoder(struct rockchip_dp_device *dp)
 							     dev->of_node);
 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder,
-				      DRM_MODE_ENCODER_TMDS);
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret) {
 		DRM_ERROR("failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 190cce9530c8..c3f41a4449f5 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -23,7 +23,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "cdn-dp-core.h"
 #include "cdn-dp-reg.h"
@@ -671,6 +670,10 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs cdn_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
 	.atomic_check = cdn_dp_encoder_atomic_check,
 };
@@ -988,8 +991,8 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 							     dev->of_node);
 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder,
-				      DRM_MODE_ENCODER_TMDS);
+	ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
 	if (ret) {
 		DRM_ERROR("failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 3547d91b25d3..a09b382d208e 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -25,7 +25,6 @@
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
@@ -825,6 +824,10 @@ static void dw_mipi_dsi_encoder_enable(struct drm_encoder *encoder)
 	clk_disable_unprepare(dsi->grf_clk);
 }
 
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi_encoder_helper_funcs = {
 	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
@@ -840,7 +843,9 @@ static int rockchip_dsi_drm_create_encoder(struct dw_mipi_dsi_rockchip *dsi,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dsi->dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+	ret = drm_encoder_init(drm_dev, encoder,
+				&dw_mipi_dsi_encoder_funcs,
+				DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		DRM_ERROR("Failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
index d2e76d36d724..9dc207c2d20d 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c
@@ -23,7 +23,6 @@
 #include <drm/bridge/dw_mipi_dsi2.h>
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_of.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include <uapi/linux/videodev2.h>
 
@@ -275,6 +274,10 @@ dw_mipi_dsi2_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs dw_mipi_dsi2_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const struct drm_encoder_helper_funcs
 dw_mipi_dsi2_encoder_helper_funcs = {
 	.atomic_enable = dw_mipi_dsi2_encoder_atomic_enable,
@@ -290,7 +293,8 @@ static int rockchip_dsi2_drm_create_encoder(struct dw_mipi_dsi2_rockchip *dsi2,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dsi2->dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_DSI);
+	ret = drm_encoder_init(drm_dev, encoder, &dw_mipi_dsi2_encoder_funcs,
+			       DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		dev_err(dsi2->dev, "Failed to initialize encoder with drm\n");
 		return ret;
diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 0de822360c8d..b23efb153c9e 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -20,7 +20,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index cffc0af5190f..b6e154c35e7c 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -18,7 +18,6 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..af34062685cd 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -24,7 +24,6 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_of.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 
diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 1996f8656612..b4ba9f894360 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -12,7 +12,6 @@
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include <linux/clk.h>
 #include <linux/mfd/syscon.h>
@@ -454,6 +453,10 @@ rk3066_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rk3066_hdmi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rk3066_hdmi_encoder_helper_funcs = {
 	.atomic_check   = rk3066_hdmi_encoder_atomic_check,
@@ -696,7 +699,8 @@ rk3066_hdmi_register(struct drm_device *drm, struct rk3066_hdmi *hdmi)
 		return -EPROBE_DEFER;
 
 	drm_encoder_helper_add(encoder, &rk3066_hdmi_encoder_helper_funcs);
-	drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+	drm_encoder_init(drm, encoder, &rk3066_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
 
 	hdmi->bridge.driver_private = hdmi;
 	hdmi->bridge.funcs = &rk3066_hdmi_bridge_funcs;
diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 7a0c4fa29f2f..f3be2c91d147 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -24,7 +24,6 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_lvds.h"
@@ -427,6 +426,10 @@ static void px30_lvds_encoder_disable(struct drm_encoder *encoder)
 	drm_panel_unprepare(lvds->panel);
 }
 
+static const struct drm_encoder_funcs rockchip_lvds_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rk3288_lvds_encoder_helper_funcs = {
 	.enable = rk3288_lvds_encoder_enable,
@@ -594,7 +597,9 @@ static int rockchip_lvds_bind(struct device *dev, struct device *master,
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
 							     dev->of_node);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_LVDS);
+	ret = drm_encoder_init(drm_dev, encoder,
+				      &rockchip_lvds_encoder_funcs,
+				      DRM_MODE_ENCODER_LVDS, NULL);
 	if (ret < 0) {
 		drm_err(drm_dev,
 			"failed to initialize encoder: %d\n", ret);
diff --git a/drivers/gpu/drm/rockchip/rockchip_rgb.c b/drivers/gpu/drm/rockchip/rockchip_rgb.c
index add3123e5ce7..2ad24b914989 100644
--- a/drivers/gpu/drm/rockchip/rockchip_rgb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_rgb.c
@@ -17,7 +17,6 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
-#include <drm/drm_simple_kms_helper.h>
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_rgb.h"
@@ -65,6 +64,10 @@ rockchip_rgb_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
+static const struct drm_encoder_funcs rockchip_rgb_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
 static const
 struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
 	.atomic_check = rockchip_rgb_encoder_atomic_check,
@@ -127,7 +130,8 @@ struct rockchip_rgb *rockchip_rgb_init(struct device *dev,
 	encoder = &rgb->encoder.encoder;
 	encoder->possible_crtcs = drm_crtc_mask(crtc);
 
-	ret = drm_simple_encoder_init(drm_dev, encoder, DRM_MODE_ENCODER_NONE);
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_rgb_encoder_funcs,
+			       DRM_MODE_ENCODER_NONE, NULL);
 	if (ret < 0) {
 		DRM_DEV_ERROR(drm_dev->dev,
 			      "failed to initialize encoder: %d\n", ret);
-- 
2.51.2



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 06:54:13 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 15:54:13 +0200
Subject: [PATCH v2 0/4] dt-bindings: mfd: syscon: Tighten checks
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>

Changes in v2:
1. New patches #2 and #3
1. Add missing part of patch #1, thus not adding Rob's Ack.
https://lore.kernel.org/all/20260531110404.12768-3-krzysztof.kozlowski at oss.qualcomm.com/

I tested dt_binding_check and dtbs_check for arm, arm64 and riscv and I
think I did not introduce new dtbs_check warnings. Old code anyway has
multiple abuses of syscon, thus tricky to judge for arm at least.

Best regards,
Krzysztof

---
Krzysztof Kozlowski (4):
      dt-bindings: mfd: syscon: Disallow simple-bus with syscon
      dt-bindings: mfd: syscon: Drop unneeded case for syscon + simple-mfd
      dt-bindings: mfd: syscon: Drop custom select for older dtschema
      ARM: dts: ti: Add specific compatibles for SCM conf nodes

 .../devicetree/bindings/mfd/syscon-common.yaml     |  31 +++++-
 Documentation/devicetree/bindings/mfd/syscon.yaml  | 116 ---------------------
 arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi           |   2 +-
 arch/arm/boot/dts/ti/omap/am437x-l4.dtsi           |   2 +-
 arch/arm/boot/dts/ti/omap/dm814x.dtsi              |   2 +-
 arch/arm/boot/dts/ti/omap/dm816x.dtsi              |   2 +-
 arch/arm/boot/dts/ti/omap/dra7-l4.dtsi             |   2 +-
 arch/arm/boot/dts/ti/omap/omap2430.dtsi            |   2 +-
 arch/arm/boot/dts/ti/omap/omap3.dtsi               |   2 +-
 arch/arm/boot/dts/ti/omap/omap4-l4.dtsi            |   2 +-
 arch/arm/boot/dts/ti/omap/omap5-l4.dtsi            |   6 +-
 11 files changed, 37 insertions(+), 132 deletions(-)
---
base-commit: 78f5e68a8d0a1123dd1b007688ccf0e6876a5c15
change-id: 20260608-n-dt-bindings-simple-bus-syscon-e39df408a02d

Best regards,
--  
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 06:54:14 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 15:54:14 +0200
Subject: [PATCH v2 1/4] dt-bindings: mfd: syscon: Disallow simple-bus with
 syscon
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v2-1-0203e6c249dc@oss.qualcomm.com>

"syscon" is a system controller with registers having their own
functions, thus not really a trivial MMIO simple bus.  "simple-bus" on
the other hand is just a bus on which multiple devices sit and the
"simple" means no functions are allowed here.

Combination of both "syscon" and "simple-bus" is abuse of DT for easier
instantiating of Linux device drivers so add a schema to disallow that.

Unfortunately there are a few old cases of that patterns, so add
exceptions:

1. "cznic,turris1x-cpld" and "img,pistachio-cr-periph" are already used
   in upstream DTS.

2. TI has several DTSI with a child of SCM device (e.g. "ti,am3-scm")
   using "syscon" and "simple-bus" but without a dedicated compatible
   documented anywhere.  Add new compatibles for such cases.

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

---

Changes in v2:
1. Complete patch. I accidentally sent only part of it, built on top of
   internal WIP which I forgot to squash.
   I received Ack from Rob, but change is significant, so please kindly
   re-review.
---
 .../devicetree/bindings/mfd/syscon-common.yaml     | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/syscon-common.yaml b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
index 14a08e7bc8bd..315357da146e 100644
--- a/Documentation/devicetree/bindings/mfd/syscon-common.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
@@ -57,6 +57,38 @@ allOf:
           minItems: 3
           maxItems: 5
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: simple-bus
+    then:
+      # simple-bus conflicts with syscon - if a device is a system controller
+      # with miscellaneous registers, then it has at least one dedicated
+      # function thus it is not a simple bus. Allow existing exceptions.
+      if:
+        properties:
+          compatible:
+            not:
+              contains:
+                # This list CANNOT grow
+                enum:
+                  - cznic,turris1x-cpld
+                  - img,pistachio-cr-periph
+                  - ti,am3352-scm-conf
+                  - ti,am4372-scm-conf
+                  - ti,dm814-scm-conf
+                  - ti,dm8168-scm-conf
+                  - ti,dra7-scm-conf
+                  - ti,omap2-scm-conf
+                  - ti,omap3-scm-conf
+                  - ti,omap4-sysc-padconf-global
+                  - ti,omap5-scm-conf
+                  - ti,omap5-scm-wkup-conf
+      then:
+        required:
+          - incorrect-usage-of-simple-bus-and-syscon
+
 additionalProperties: true
 
 examples:

-- 
2.53.0



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 06:54:15 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 15:54:15 +0200
Subject: [PATCH v2 2/4] dt-bindings: mfd: syscon: Drop unneeded case for
 syscon + simple-mfd
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v2-2-0203e6c249dc@oss.qualcomm.com>

Commit f97b0435c857 ("dt-bindings: mfd: syscon: Split and enforce
documenting MFD children") split the syscon.yaml bindings with intention
that combinations of "syscon" and "simple-mfd" will own bindings file
referencing the common syscon-common.yaml file and define its children.
That is why it left the quite generic/wide compatible list of up to five
entries with simple-mfd.

This permissive list of up to five entries with simple-mfd can be
removed because:
1. Such case - referencing syscon-common.yaml - did not materialize.

2. All documented bindings combining "syscon" and "simple-mfd" have
   their own schemas.

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

---

Changes in v2:
1. New patch
---
 Documentation/devicetree/bindings/mfd/syscon-common.yaml | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/syscon-common.yaml b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
index 315357da146e..b3462e876622 100644
--- a/Documentation/devicetree/bindings/mfd/syscon-common.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
@@ -46,17 +46,6 @@ required:
   - reg
 
 allOf:
-  - if:
-      properties:
-        compatible:
-          contains:
-            const: simple-mfd
-    then:
-      properties:
-        compatible:
-          minItems: 3
-          maxItems: 5
-
   - if:
       properties:
         compatible:

-- 
2.53.0



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 06:54:16 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 15:54:16 +0200
Subject: [PATCH v2 3/4] dt-bindings: mfd: syscon: Drop custom select for
 older dtschema
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v2-3-0203e6c249dc@oss.qualcomm.com>

Older dtschema <2024.02 required custom select to avoid applying this
binding to anything having "syscon" compatible.  That's not the case
anymore and this additional select has two headaches:

1. Duplicates all the compatibles listed in the schema.

2. Is error-prone, because it requires contributor to add the compatible
   in two places, otherwise the schema will be silently ignored.
   The select list already misses mentioning compatibles:
   mediatek,mt8365-infracfg-nao and renesas,r9a08g046-lvds-cmn (with the
   latter being reverted for different reasons).

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

---

Changes in v2:
1. New patch
---
 Documentation/devicetree/bindings/mfd/syscon.yaml | 116 ----------------------
 1 file changed, 116 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index 9c81010d5a74..b70018bf1bcf 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -19,122 +19,6 @@ description: |
 maintainers:
   - Lee Jones <lee at kernel.org>
 
-# Need a select with all compatibles listed for compatibility with older
-# dtschema (<2024.02), so this will not be selected for other schemas having
-# syscon fallback.
-select:
-  properties:
-    compatible:
-      contains:
-        enum:
-          - airoha,en7581-pbus-csr
-          - al,alpine-sysfabric-service
-          - allwinner,sun8i-a83t-system-controller
-          - allwinner,sun8i-h3-system-controller
-          - allwinner,sun8i-v3s-system-controller
-          - allwinner,sun50i-a64-system-controller
-          - altr,l3regs
-          - altr,sdr-ctl
-          - amd,pensando-elba-syscon
-          - amlogic,meson-mx-assist
-          - amlogic,meson-mx-bootrom
-          - amlogic,meson8-analog-top
-          - amlogic,meson8b-analog-top
-          - amlogic,meson8-pmu
-          - amlogic,meson8b-pmu
-          - apm,merlin-poweroff-mailbox
-          - apm,mustang-poweroff-mailbox
-          - apm,xgene-csw
-          - apm,xgene-efuse
-          - apm,xgene-mcb
-          - apm,xgene-rb
-          - apm,xgene-scu
-          - atmel,sama5d2-sfrbu
-          - atmel,sama5d3-nfc-io
-          - atmel,sama5d3-sfrbu
-          - atmel,sama5d4-sfrbu
-          - axis,artpec6-syscon
-          - brcm,cru-clkset
-          - brcm,sr-cdru
-          - brcm,sr-mhb
-          - cirrus,ep7209-syscon1
-          - cirrus,ep7209-syscon2
-          - cirrus,ep7209-syscon3
-          - cnxt,cx92755-uc
-          - econet,en751221-chip-scu
-          - freecom,fsg-cs2-system-controller
-          - fsl,imx93-aonmix-ns-syscfg
-          - fsl,imx93-wakeupmix-syscfg
-          - fsl,ls1088a-reset
-          - fsl,vf610-anatop
-          - fsl,vf610-mscm-cpucfg
-          - hisilicon,dsa-subctrl
-          - hisilicon,hi6220-sramctrl
-          - hisilicon,hip04-ppe
-          - hisilicon,pcie-sas-subctrl
-          - hisilicon,peri-subctrl
-          - hpe,gxp-sysreg
-          - loongson,ls1b-syscon
-          - loongson,ls1c-syscon
-          - lsi,axxia-syscon
-          - marvell,armada-3700-cpu-misc
-          - marvell,armada-3700-nb-pm
-          - marvell,armada-3700-avs
-          - marvell,armada-3700-usb2-host-device-misc
-          - marvell,armada-3700-usb2-host-misc
-          - marvell,dove-global-config
-          - mediatek,mt2701-pctl-a-syscfg
-          - mediatek,mt2712-pctl-a-syscfg
-          - mediatek,mt6397-pctl-pmic-syscfg
-          - mediatek,mt7981-topmisc
-          - mediatek,mt7988-topmisc
-          - mediatek,mt8135-pctl-a-syscfg
-          - mediatek,mt8135-pctl-b-syscfg
-          - mediatek,mt8173-pctl-a-syscfg
-          - mediatek,mt8365-syscfg
-          - microchip,lan966x-cpu-syscon
-          - microchip,mpfs-control-scb
-          - microchip,mpfs-sysreg-scb
-          - microchip,sam9x60-sfr
-          - microchip,sama7d65-ddr3phy
-          - microchip,sama7d65-sfrbu
-          - microchip,sama7g5-ddr3phy
-          - mscc,ocelot-cpu-syscon
-          - mstar,msc313-pmsleep
-          - nuvoton,ma35d1-sys
-          - nuvoton,wpcm450-shm
-          - nxp,s32g2-gpr
-          - nxp,s32g3-gpr
-          - qcom,apq8064-mmss-sfpb
-          - qcom,apq8064-sps-sic
-          - rockchip,px30-qos
-          - rockchip,rk3036-qos
-          - rockchip,rk3066-qos
-          - rockchip,rk3128-qos
-          - rockchip,rk3228-qos
-          - rockchip,rk3288-qos
-          - rockchip,rk3368-qos
-          - rockchip,rk3399-qos
-          - rockchip,rk3528-qos
-          - rockchip,rk3562-qos
-          - rockchip,rk3568-qos
-          - rockchip,rk3576-qos
-          - rockchip,rk3588-qos
-          - rockchip,rv1126-qos
-          - st,spear1340-misc
-          - stericsson,nomadik-pmu
-          - starfive,jh7100-sysmain
-          - ti,am62-opp-efuse-table
-          - ti,am62-usb-phy-ctrl
-          - ti,am625-dss-oldi-io-ctrl
-          - ti,am62p-cpsw-mac-efuse
-          - ti,am654-dss-oldi-io-ctrl
-          - ti,j784s4-acspcie-proxy-ctrl
-          - ti,j784s4-pcie-ctrl
-          - ti,keystone-pllctrl
-  required:
-    - compatible
-
 properties:
   compatible:
     oneOf:

-- 
2.53.0



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 06:54:17 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 15:54:17 +0200
Subject: [PATCH v2 4/4] ARM: dts: ti: Add specific compatibles for SCM conf
 nodes
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v2-4-0203e6c249dc@oss.qualcomm.com>

writing-bindings.rst rules dictate that "syscon" must come with a
specific compatible identifying the register layout.  Add specific
compatibles for these devices.

This also allows to solve a different problem: "syscon" is contradictory
to "simple-bus".  A system controller with registers having their own
functions is not really a trivial MMIO simple bus.  These two cannot be
used together, unless listed as an exception.

Reviewed-by: Andreas Kemnade <andreas at kemnade.info>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi | 2 +-
 arch/arm/boot/dts/ti/omap/am437x-l4.dtsi | 2 +-
 arch/arm/boot/dts/ti/omap/dm814x.dtsi    | 2 +-
 arch/arm/boot/dts/ti/omap/dm816x.dtsi    | 2 +-
 arch/arm/boot/dts/ti/omap/dra7-l4.dtsi   | 2 +-
 arch/arm/boot/dts/ti/omap/omap2430.dtsi  | 2 +-
 arch/arm/boot/dts/ti/omap/omap3.dtsi     | 2 +-
 arch/arm/boot/dts/ti/omap/omap4-l4.dtsi  | 2 +-
 arch/arm/boot/dts/ti/omap/omap5-l4.dtsi  | 6 +++---
 9 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
index 89d16fcc773e..1e09d2b48925 100644
--- a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
@@ -308,7 +308,7 @@ am33xx_pinmux: pinmux at 800 {
 				};
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,am3352-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
index e08f356e71cb..30fcce33f4b7 100644
--- a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
@@ -301,7 +301,7 @@ am43xx_pinmux: pinmux at 800 {
 				};
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,am4372-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm814x.dtsi b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
index 27d1f35a31fd..9e02bfa5c3a2 100644
--- a/arch/arm/boot/dts/ti/omap/dm814x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
@@ -432,7 +432,7 @@ control: control at 140000 {
 				ranges = <0 0x140000 0x20000>;
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,dm814-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm816x.dtsi b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
index a1e0e904e0f0..ee0090f7aa64 100644
--- a/arch/arm/boot/dts/ti/omap/dm816x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
@@ -100,7 +100,7 @@ dm816x_pinmux: pinmux at 800 {
 
 			/* Device Configuration Registers */
 			scm_conf: syscon at 600 {
-				compatible = "syscon", "simple-bus";
+				compatible = "ti,dm8168-scm-conf", "syscon", "simple-bus";
 				reg = <0x600 0x110>;
 				#address-cells = <1>;
 				#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
index c8d325b0f57b..9df7648c4b79 100644
--- a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
@@ -64,7 +64,7 @@ scm: scm at 0 {
 				ranges = <0 0 0x2000>;
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,dra7-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x1400>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap2430.dtsi b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
index 222613d2a4d1..01bd471f9223 100644
--- a/arch/arm/boot/dts/ti/omap/omap2430.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
@@ -50,7 +50,7 @@ omap2430_pmx: pinmux at 30 {
 				};
 
 				scm_conf: scm_conf at 270 {
-					compatible = "syscon",
+					compatible = "ti,omap2-scm-conf", "syscon",
 						     "simple-bus";
 					reg = <0x270 0x240>;
 					#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap3.dtsi b/arch/arm/boot/dts/ti/omap/omap3.dtsi
index 959069e24730..447736d2e53c 100644
--- a/arch/arm/boot/dts/ti/omap/omap3.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3.dtsi
@@ -116,7 +116,7 @@ omap3_pmx_core: pinmux at 30 {
 				};
 
 				scm_conf: scm_conf at 270 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,omap3-scm-conf", "syscon", "simple-bus";
 					reg = <0x270 0x330>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
index 4c78a0b28fab..c1afc49f456c 100644
--- a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
@@ -681,7 +681,7 @@ omap4_pmx_core: pinmux at 40 {
 			};
 
 			omap4_padconf_global: omap4_padconf_global at 5a0 {
-				compatible = "syscon",
+				compatible = "ti,omap4-sysc-padconf-global", "syscon",
 					     "simple-bus";
 				reg = <0x5a0 0x170>;
 				#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
index 915870eb5c99..3350128db22d 100644
--- a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
@@ -96,8 +96,7 @@ omap5_pmx_core: pinmux at 40 {
 				};
 
 				omap5_padconf_global: omap5_padconf_global at 5a0 {
-					compatible = "syscon",
-						     "simple-bus";
+					compatible = "ti,omap5-scm-conf", "syscon", "simple-bus";
 					reg = <0x5a0 0xec>;
 					#address-cells = <1>;
 					#size-cells = <1>;
@@ -2311,7 +2310,8 @@ omap5_scm_wkup_pad_conf: omap5_scm_wkup_pad_conf at da0 {
 				ranges = <0 0 0x60>;
 
 				scm_wkup_pad_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,omap5-scm-wkup-conf",
+						     "syscon", "simple-bus";
 					reg = <0x0 0x60>;
 					#address-cells = <1>;
 					#size-cells = <1>;

-- 
2.53.0



From mripard at kernel.org  Mon Jun  8 07:33:17 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 8 Jun 2026 16:33:17 +0200
Subject: [PATCH v6 02/22] drm/connector: Add HDMI 2.0 scrambler
 infrastructure
In-Reply-To: <bfdbf194-b400-4de3-bb68-74652dece74d@collabora.com>
References: <20260520-dw-hdmi-qp-scramb-v6-0-24b74603b782@collabora.com>
 <20260520-dw-hdmi-qp-scramb-v6-2-24b74603b782@collabora.com>
 <20260521-sweet-devout-panther-44d73c@penduick>
 <bfdbf194-b400-4de3-bb68-74652dece74d@collabora.com>
Message-ID: <20260608-unbiased-fine-civet-ef81ac@houat>

On Fri, May 22, 2026 at 01:57:16PM +0300, Cristian Ciocaltea wrote:
> Hi Maxime,
> 
> On 5/21/26 10:52 AM, Maxime Ripard wrote:
> > Hi,
> > 
> > Thanks for working on this!
> 
> Thanks for your quick review! :-)
> 
> > 
> > On Wed, May 20, 2026 at 09:38:13PM +0300, Cristian Ciocaltea wrote:
> >> Add the connector-level infrastructure to support HDMI 2.0 scrambling:
> >>
> >> - .scrambler_src_{enable|disable}() callbacks in
> >>   drm_connector_hdmi_funcs for source-side scrambling control
> >> - A delayed work item (scdc_work) with an associated callback (scdc_cb)
> >>   for periodic monitoring of sink-side scrambling status
> >> - A scrambler_enabled flag to track whether scrambling is currently
> >>   active
> >>
> >> These are intended to be used by SCDC scrambling helpers to coordinate
> >> scrambling setup and teardown between the source driver and the DRM
> >> core.
> >>
> >> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> >> ---
> >>  drivers/gpu/drm/drm_connector.c | 14 +++++++++++
> >>  include/drm/drm_connector.h     | 52 +++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 66 insertions(+)
> > 
> > So we would need kunit tests for this.
> 
> Ack.
> 
> > 
> >> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> >> index 3fa4d2082cd7..91e58362fbc0 100644
> >> --- a/drivers/gpu/drm/drm_connector.c
> >> +++ b/drivers/gpu/drm/drm_connector.c
> >> @@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
> >>  	}
> >>  }
> 
> [...]
> 
> >> +	/**
> >> +	 * @scdc_work: Work item currently used to monitor sink-side scrambling
> >> +	 * status and retry setup if the sink resets it.
> >> +	 */
> >> +	struct delayed_work scdc_work;
> >> +
> >> +	/** @scdc_cb: Callback to be invoked as part of @scdc_work.
> >> +	 *
> >> +	 * Currently used to monitor sink-side scrambling status and retry
> >> +	 * setup if the sink resets it.
> >> +	 *
> >> +	 * This is assigned by the framework when making use of
> >> +	 * drm_scdc_start_scrambling() helper.
> >> +	 */
> >> +	void (*scdc_cb)(struct drm_connector *connector);
> >> +
> > 
> > I'm really not sure what the monitor thing is about. If we have setup
> > the scrambler at enable time, and we set it again on hotplugging, why
> > would we need to monitor anything?
> 
> This is similar to 257d36d493e9 ("drm/vc4: hdmi: Add a workqueue to set
> scrambling") in order to deal with some displays needing a retry on scrambling
> setup.

Ah, I see, sorry :)

It looks pretty generic though, should we have a helper for this then?

> > Also, scrambling is only relevant for HDMI 2.0. We need a way to expose
> > that somehow and make sure that HDMI 2.0 drivers actually have
> > scrambling setup.
> 
> I assumed drivers that do not reject the HDMI 2.0 rates in their
> .tmds_char_rate_valid() are implicitly expected to support scrambling. 
> Thinking again we could extend the framework to provide some additional checks,
> but let's discuss the topic on the SCDC patch.

HDMI 2.0 isn't just about scrambling though, YUV420 is another big
addition, and iirc you have more audio formats too.

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-rockchip/attachments/20260608/6bcab009/attachment.sig>

From mripard at kernel.org  Mon Jun  8 07:35:42 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 08 Jun 2026 16:35:42 +0200
Subject: [PATCH v2 00/78] drm/bridge: Convert all reset users to
 create_state
Message-ID: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>

Hi, 

All the bridges use reset to create a blank state only and don't use it
to reset the hardware at all. This is what the new atomic_create_state
is exactly supposed to be doing, so we can convert all existing bridge
users to it, and remove the reset hook and helpers.

Let me know what you think,
Maxime 

Signed-off-by: Maxime Ripard <mripard at kernel.org>
---
Changes in v2:
- Split the return value fix for cadence bridges into their own patches
- Fix bisection
- Collect tags
- Link to v1: https://lore.kernel.org/r/20260530-drm-no-more-bridge-reset-v1-0-875d828d31bc at kernel.org

---
Maxime Ripard (78):
      drm/bridge: cdns-dsi: Return an error pointer on allocation failure
      drm/bridge: cdns-mhdp8546: Return an error pointer on allocation failure
      drm/atomic-state-helper: Rename __drm_atomic_helper_bridge_reset()
      drm/atomic-state-helper: Reorder __drm_atomic_helper_bridge_state_init() arguments
      drm/atomic-state-helper: Drop memset from __drm_atomic_helper_bridge_state_init()
      drm/bridge: Add new atomic_create_state callback
      drm/atomic-state-helper: Add drm_atomic_helper_bridge_create_state()
      drm/bridge: adv7511: Switch to atomic_create_state
      drm/bridge: analogix_dp: Switch to atomic_create_state
      drm/bridge: anx7625: Switch to atomic_create_state
      drm/bridge: chipone-icn6211: Switch to atomic_create_state
      drm/bridge: display-connector: Switch to atomic_create_state
      drm/bridge: fsl-ldb: Switch to atomic_create_state
      drm/bridge: imx8mp-hdmi-pvi: Switch to atomic_create_state
      drm/bridge: imx8qm-ldb: Switch to atomic_create_state
      drm/bridge: imx8qxp-ldb: Switch to atomic_create_state
      drm/bridge: imx8qxp-pixel-combiner: Switch to atomic_create_state
      drm/bridge: imx8qxp-pixel-link: Switch to atomic_create_state
      drm/bridge: imx8qxp-pxl2dpi: Switch to atomic_create_state
      drm/bridge: inno-hdmi: Switch to atomic_create_state
      drm/bridge: ite-it6263: Switch to atomic_create_state
      drm/bridge: ite-it6505: Switch to atomic_create_state
      drm/bridge: ite-it66121: Switch to atomic_create_state
      drm/bridge: lontium-lt9211: Switch to atomic_create_state
      drm/bridge: lontium-lt9611: Switch to atomic_create_state
      drm/bridge: lvds-codec: Switch to atomic_create_state
      drm/bridge: nwl-dsi: Switch to atomic_create_state
      drm/bridge: panel: Switch to atomic_create_state
      drm/bridge: parade-ps8640: Switch to atomic_create_state
      drm/bridge: samsung-dsim: Switch to atomic_create_state
      drm/bridge: sii902x: Switch to atomic_create_state
      drm/bridge: ssd2825: Switch to atomic_create_state
      drm/bridge: dw-dp: Switch to atomic_create_state
      drm/bridge: dw-hdmi-qp: Switch to atomic_create_state
      drm/bridge: dw-hdmi: Switch to atomic_create_state
      drm/bridge: dw-mipi-dsi: Switch to atomic_create_state
      drm/bridge: dw-mipi-dsi2: Switch to atomic_create_state
      drm/bridge: tc358762: Switch to atomic_create_state
      drm/bridge: tc358767: Switch to atomic_create_state
      drm/bridge: tc358768: Switch to atomic_create_state
      drm/bridge: tc358775: Switch to atomic_create_state
      drm/bridge: ti-dlpc3433: Switch to atomic_create_state
      drm/bridge: ti-sn65dsi83: Switch to atomic_create_state
      drm/bridge: ti-sn65dsi86: Switch to atomic_create_state
      drm/bridge: ti-tdp158: Switch to atomic_create_state
      drm/bridge: ti-tfp410: Switch to atomic_create_state
      drm/imx: parallel-display: Switch to atomic_create_state
      drm/ingenic: Switch to atomic_create_state
      drm/mediatek: dp: Switch to atomic_create_state
      drm/mediatek: dpi: Switch to atomic_create_state
      drm/mediatek: dsi: Switch to atomic_create_state
      drm/mediatek: hdmi: Switch to atomic_create_state
      drm/mediatek: hdmi_v2: Switch to atomic_create_state
      drm/meson: encoder_cvbs: Switch to atomic_create_state
      drm/meson: encoder_dsi: Switch to atomic_create_state
      drm/meson: encoder_hdmi: Switch to atomic_create_state
      drm/msm: dp: Switch to atomic_create_state
      drm/msm: hdmi: Switch to atomic_create_state
      drm/omap: hdmi4: Switch to atomic_create_state
      drm/omap: hdmi5: Switch to atomic_create_state
      drm/renesas: rcar-du: lvds: Switch to atomic_create_state
      drm/renesas: rcar-du: mipi_dsi: Switch to atomic_create_state
      drm/renesas: rz-du: mipi_dsi: Switch to atomic_create_state
      drm/rockchip: cdn-dp: Switch to atomic_create_state
      drm/rockchip: rk3066_hdmi: Switch to atomic_create_state
      drm/rockchip: lvds: Switch to atomic_create_state
      drm/stm: lvds: Switch to atomic_create_state
      drm/tests: bridge: Switch to atomic_create_state
      drm/tidss: encoder: Switch to atomic_create_state
      drm/tidss: oldi: Switch to atomic_create_state
      drm/vc4: dsi: Switch to atomic_create_state
      drm/verisilicon: Switch to atomic_create_state
      drm/xlnx: zynqmp_dp: Switch to atomic_create_state
      drm/atomic-state-helper: Remove drm_atomic_helper_bridge_reset()
      drm/bridge: cdns-dsi: Use __drm_atomic_helper_bridge_state_init()
      drm/bridge: cdns-dsi: Switch to atomic_create_state
      drm/bridge: cdns-mhdp8546: Switch to atomic_create_state
      drm/bridge: Remove atomic_reset support

 drivers/gpu/drm/bridge/adv7511/adv7511_drv.c       |  2 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  2 +-
 drivers/gpu/drm/bridge/analogix/anx7625.c          |  2 +-
 drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c     |  9 +++---
 .../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c    |  8 ++---
 drivers/gpu/drm/bridge/chipone-icn6211.c           |  2 +-
 drivers/gpu/drm/bridge/display-connector.c         |  2 +-
 drivers/gpu/drm/bridge/fsl-ldb.c                   |  2 +-
 drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c       |  2 +-
 drivers/gpu/drm/bridge/imx/imx8qm-ldb.c            |  2 +-
 drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c           |  2 +-
 .../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c    |  2 +-
 drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c    |  2 +-
 drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c       |  2 +-
 drivers/gpu/drm/bridge/inno-hdmi.c                 |  2 +-
 drivers/gpu/drm/bridge/ite-it6263.c                |  2 +-
 drivers/gpu/drm/bridge/ite-it6505.c                |  2 +-
 drivers/gpu/drm/bridge/ite-it66121.c               |  2 +-
 drivers/gpu/drm/bridge/lontium-lt9211.c            |  2 +-
 drivers/gpu/drm/bridge/lontium-lt9611.c            |  2 +-
 drivers/gpu/drm/bridge/lvds-codec.c                |  2 +-
 drivers/gpu/drm/bridge/nwl-dsi.c                   |  2 +-
 drivers/gpu/drm/bridge/panel.c                     |  2 +-
 drivers/gpu/drm/bridge/parade-ps8640.c             |  2 +-
 drivers/gpu/drm/bridge/samsung-dsim.c              |  2 +-
 drivers/gpu/drm/bridge/sii902x.c                   |  2 +-
 drivers/gpu/drm/bridge/ssd2825.c                   |  2 +-
 drivers/gpu/drm/bridge/synopsys/dw-dp.c            |  2 +-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c       |  2 +-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi.c          |  2 +-
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c      |  2 +-
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c     |  2 +-
 drivers/gpu/drm/bridge/tc358762.c                  |  2 +-
 drivers/gpu/drm/bridge/tc358767.c                  |  4 +--
 drivers/gpu/drm/bridge/tc358768.c                  |  2 +-
 drivers/gpu/drm/bridge/tc358775.c                  |  2 +-
 drivers/gpu/drm/bridge/ti-dlpc3433.c               |  2 +-
 drivers/gpu/drm/bridge/ti-sn65dsi83.c              |  2 +-
 drivers/gpu/drm/bridge/ti-sn65dsi86.c              |  2 +-
 drivers/gpu/drm/bridge/ti-tdp158.c                 |  2 +-
 drivers/gpu/drm/bridge/ti-tfp410.c                 |  2 +-
 drivers/gpu/drm/drm_atomic_state_helper.c          | 34 ++++++++++++----------
 drivers/gpu/drm/drm_bridge.c                       |  4 +--
 drivers/gpu/drm/imx/ipuv3/parallel-display.c       |  2 +-
 drivers/gpu/drm/ingenic/ingenic-drm-drv.c          |  2 +-
 drivers/gpu/drm/mediatek/mtk_dp.c                  |  2 +-
 drivers/gpu/drm/mediatek/mtk_dpi.c                 |  2 +-
 drivers/gpu/drm/mediatek/mtk_dsi.c                 |  2 +-
 drivers/gpu/drm/mediatek/mtk_hdmi.c                |  2 +-
 drivers/gpu/drm/mediatek/mtk_hdmi_v2.c             |  2 +-
 drivers/gpu/drm/meson/meson_encoder_cvbs.c         |  2 +-
 drivers/gpu/drm/meson/meson_encoder_dsi.c          |  2 +-
 drivers/gpu/drm/meson/meson_encoder_hdmi.c         |  2 +-
 drivers/gpu/drm/msm/dp/dp_drm.c                    |  4 +--
 drivers/gpu/drm/msm/hdmi/hdmi_bridge.c             |  2 +-
 drivers/gpu/drm/omapdrm/dss/hdmi4.c                |  2 +-
 drivers/gpu/drm/omapdrm/dss/hdmi5.c                |  2 +-
 drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c        |  2 +-
 drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c    |  2 +-
 drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c     |  2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c             |  2 +-
 drivers/gpu/drm/rockchip/rk3066_hdmi.c             |  2 +-
 drivers/gpu/drm/rockchip/rockchip_lvds.c           |  2 +-
 drivers/gpu/drm/stm/lvds.c                         |  2 +-
 drivers/gpu/drm/tests/drm_bridge_test.c            |  2 +-
 drivers/gpu/drm/tidss/tidss_encoder.c              |  2 +-
 drivers/gpu/drm/tidss/tidss_oldi.c                 |  2 +-
 drivers/gpu/drm/vc4/vc4_dsi.c                      |  2 +-
 drivers/gpu/drm/verisilicon/vs_bridge.c            |  4 +--
 drivers/gpu/drm/xlnx/zynqmp_dp.c                   |  2 +-
 include/drm/drm_atomic_state_helper.h              |  6 ++--
 include/drm/drm_bridge.h                           | 33 +++++++--------------
 72 files changed, 112 insertions(+), 120 deletions(-)
---
base-commit: 60dc0946bbad3eef8bc66a5a8b09b98dbc6e09c0
change-id: 20260530-drm-no-more-bridge-reset-ca20d5e22740

Best regards,
-- 
Maxime Ripard <mripard at kernel.org>



From mripard at kernel.org  Mon Jun  8 07:36:46 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 08 Jun 2026 16:36:46 +0200
Subject: [PATCH v2 64/78] drm/rockchip: cdn-dp: Switch to
 atomic_create_state
In-Reply-To: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
References: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
Message-ID: <20260608-drm-no-more-bridge-reset-v2-64-0a91018bf886@kernel.org>

The drm_bridge_funcs.atomic_reset callback and its
drm_atomic_helper_bridge_reset() helper are deprecated.

Switch to the atomic_create_state callback and its
drm_atomic_helper_bridge_create_state() counterpart.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
Signed-off-by: Maxime Ripard <mripard at kernel.org>
---
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>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
---
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 190cce9530c8..e159e1627f3c 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -823,11 +823,11 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge,
 }
 
 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,
-	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_create_state = drm_atomic_helper_bridge_create_state,
 	.detect = cdn_dp_bridge_detect,
 	.edid_read = cdn_dp_bridge_edid_read,
 	.atomic_enable = cdn_dp_bridge_atomic_enable,
 	.atomic_disable = cdn_dp_bridge_atomic_disable,
 	.mode_valid = cdn_dp_bridge_mode_valid,

-- 
2.54.0



From mripard at kernel.org  Mon Jun  8 07:36:47 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 08 Jun 2026 16:36:47 +0200
Subject: [PATCH v2 65/78] drm/rockchip: rk3066_hdmi: Switch to
 atomic_create_state
In-Reply-To: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
References: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
Message-ID: <20260608-drm-no-more-bridge-reset-v2-65-0a91018bf886@kernel.org>

The drm_bridge_funcs.atomic_reset callback and its
drm_atomic_helper_bridge_reset() helper are deprecated.

Switch to the atomic_create_state callback and its
drm_atomic_helper_bridge_create_state() counterpart.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
Signed-off-by: Maxime Ripard <mripard at kernel.org>
---
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>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
---
 drivers/gpu/drm/rockchip/rk3066_hdmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rk3066_hdmi.c b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
index 1996f8656612..9b8981fa19ae 100644
--- a/drivers/gpu/drm/rockchip/rk3066_hdmi.c
+++ b/drivers/gpu/drm/rockchip/rk3066_hdmi.c
@@ -495,11 +495,11 @@ rk3066_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
 }
 
 static const struct drm_bridge_funcs rk3066_hdmi_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_create_state = drm_atomic_helper_bridge_create_state,
 	.atomic_enable = rk3066_hdmi_bridge_atomic_enable,
 	.atomic_disable = rk3066_hdmi_bridge_atomic_disable,
 	.detect = rk3066_hdmi_bridge_detect,
 	.edid_read = rk3066_hdmi_bridge_edid_read,
 	.hdmi_clear_avi_infoframe = rk3066_hdmi_bridge_clear_avi_infoframe,

-- 
2.54.0



From mripard at kernel.org  Mon Jun  8 07:36:48 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Mon, 08 Jun 2026 16:36:48 +0200
Subject: [PATCH v2 66/78] drm/rockchip: lvds: Switch to atomic_create_state
In-Reply-To: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
References: <20260608-drm-no-more-bridge-reset-v2-0-0a91018bf886@kernel.org>
Message-ID: <20260608-drm-no-more-bridge-reset-v2-66-0a91018bf886@kernel.org>

The drm_bridge_funcs.atomic_reset callback and its
drm_atomic_helper_bridge_reset() helper are deprecated.

Switch to the atomic_create_state callback and its
drm_atomic_helper_bridge_create_state() counterpart.

Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
Signed-off-by: Maxime Ripard <mripard at kernel.org>
---
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>
Cc: dri-devel at lists.freedesktop.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org
---
 drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c
index 7a0c4fa29f2f..31dc206bedeb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_lvds.c
+++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c
@@ -117,11 +117,11 @@ rockchip_lvds_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *
 
 static const
 struct drm_bridge_funcs rockchip_lvds_bridge_funcs = {
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
-	.atomic_reset = drm_atomic_helper_bridge_reset,
+	.atomic_create_state = drm_atomic_helper_bridge_create_state,
 	.get_modes = rockchip_lvds_bridge_get_modes,
 };
 
 static int
 rockchip_lvds_encoder_atomic_check(struct drm_encoder *encoder,

-- 
2.54.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:15 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:15 -0500
Subject: [PATCH V6 0/6] Add Anbernic RG Vita-Pro
Message-ID: <20260608175521.67449-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the Anbernic RG Vita-Pro, based on the Rockchip RK3576 SoC.

Changes Since V1:
 - Updated documentation filename to matche compatible string.
 - Corrected order of allocating IRQ in charger driver and switched
   to using devm managed function to allocate work queue.
Changes Since V2:
 - Corrected issue with naming of panel binding document and added
   fallback compatible string.
 - Switched to devm helpers in panel driver. Note that
   devm_drm_panel_add() is currently only in the drm-next branch.
 - Optimized setting GPIOs for panel driver.
Changes Since V3:
 - Fixed numerous issues identifed by Sashiko bot, mainly relating
   to unclamped or improperly clamped values from within the
   charger driver.
 - Corrected hard-coded values in the panel driver unprepare routine
   as well as correcting an improperly checked return condition.
Changes Since V4:
 - Fixed errors identified by Sashiko bot on charger driver that could
   result in an improper value being written to the registers.
 - Corrected some error handling in the panel driver.
Changes Since V5:
 - Corrected minor errors in documentation and added default values.
 - Further corrected clamping behavior in charger driver.

Chris Morgan (6):
  dt-bindings: power: supply: sgm41542: document sgm41542
  power: supply: sgm41542: Add SG Micro sgm41542 charger
  dt-bindings: display: panel: Add Anbernic TD4310 panel
  drm/panel: anbernic-td4310: Add RG Vita Pro panel
  dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
  arm64: dts: rockchip: Add Anbernic RG Vita-Pro

 .../devicetree/bindings/arm/rockchip.yaml     |    6 +
 .../display/panel/anbernic,td4310.yaml        |   66 +
 .../power/supply/sgmicro,sgm41542.yaml        |   96 ++
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 drivers/gpu/drm/panel/Kconfig                 |   10 +
 drivers/gpu/drm/panel/Makefile                |    1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c |  257 ++++
 drivers/power/supply/Kconfig                  |    8 +
 drivers/power/supply/Makefile                 |    1 +
 drivers/power/supply/sgm41542_charger.c       | 1057 +++++++++++++
 11 files changed, 2830 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
 create mode 100644 drivers/power/supply/sgm41542_charger.c

-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:16 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:16 -0500
Subject: [PATCH V6 1/6] dt-bindings: power: supply: sgm41542: document sgm41542
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Document the SG Micro sgm41542 battery charger/boost converter.
The parameters of input-current-limit-microamp and
input-voltage-limit-microvolt are defined as such since they are in
common use among multiple bindings currently.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../power/supply/sgmicro,sgm41542.yaml        | 96 +++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
new file mode 100644
index 000000000000..af80fe528505
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SGM41542 Battery Charger
+
+description:
+  The SGMicro SGM41542 is a single cell battery charger/boost controller.
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+  - Xu Shengfei <xsf at rock-chips.com>
+
+allOf:
+  - $ref: power-supply.yaml#
+
+properties:
+  compatible:
+    const: sgmicro,sgm41542
+
+  input-current-limit-microamp:
+    default: 2400000
+    minimum: 100000
+    maximum: 3800000
+
+  input-voltage-limit-microvolt:
+    default: 4500000
+    minimum: 3900000
+    maximum: 12000000
+
+  interrupts:
+    maxItems: 1
+
+  monitored-battery:
+    description: |
+        The charger uses the following battery properties
+        constant-charge-current-max-microamp (default 2040000)
+        constant-charge-voltage-max-microvolt (default 4208000)
+        charge-term-current-microamp (default 180000)
+        precharge-current-microamp (default 180000)
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    properties:
+      otg-vbus:
+        type: object
+        description: OTG boost regulator
+        $ref: /schemas/regulator/regulator.yaml
+        unevaluatedProperties: false
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    battery: battery {
+      compatible = "simple-battery";
+      constant-charge-current-max-microamp = <10000000>;
+      constant-charge-voltage-max-microvolt = <4350000>;
+      precharge-current-microamp = <180000>;
+      charge-term-current-microamp = <300000>;
+    };
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      charger at 3b {
+        compatible = "sgmicro,sgm41542";
+        reg = <0x3b>;
+        input-current-limit-microamp = <3000000>;
+        input-voltage-limit-microvolt = <4500000>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        monitored-battery = <&battery>;
+
+        regulators {
+          otg-vbus {
+            regulator-max-microvolt = <5000000>;
+            regulator-min-microvolt = <5000000>;
+          };
+        };
+      };
+    };
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:18 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:18 -0500
Subject: [PATCH V6 3/6] dt-bindings: display: panel: Add Anbernic TD4310 panel
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
new file mode 100644
index 000000000000..f820dc2f732b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Anbernic TD4310 Based Panels
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+
+description:
+  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
+  (a 1080x1920 5.5 inch panel).
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - anbernic,panel-vita-pro
+      - const: anbernic,td4310
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: Panel power supply
+
+required:
+  - compatible
+  - port
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel at 0 {
+            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+            reg = <0>;
+            backlight = <&backlight>;
+            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+            rotation = <270>;
+            vdd-supply = <&vdd_lcd>;
+
+            port {
+                endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:19 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:19 -0500
Subject: [PATCH V6 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c | 257 ++++++++++++++++++
 3 files changed, 268 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d592f4f4b939..61dd00297ecc 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
 	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
 	  and RG-99 handheld gaming consoles.
 
+config DRM_PANEL_ANBERNIC_TD4310
+	tristate "Anbernic TD4310 LCD panel"
+	depends on GPIOLIB && OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here to enable support for Anbernic designed panels with the
+	  TD4310 panel controller such as the ones used on the Anbernic RG
+	  Vita Pro.
+
 config DRM_PANEL_ARM_VERSATILE
 	tristate "ARM Versatile panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a4291dc3905b..9d8f70c9de3e 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
 obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
new file mode 100644
index 000000000000..9a1b4525423c
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Anbernic panels with TD4310 panel controller.
+ *
+ * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/mipi_display.h>
+
+struct anbernic_panel_td4310_info {
+	const struct drm_display_mode *display_mode;
+	u16 width_mm;
+	u16 height_mm;
+	u32 bus_flags;
+	unsigned long mode_flags;
+	u32 format;
+	u32 lanes;
+	u16 prepare_delay;
+	u16 reset_delay;
+	u16 init_delay;
+	u16 enable_delay;
+	u16 disable_delay;
+	u16 unprepare_delay;
+};
+
+struct anbernic_panel_td4310 {
+	struct device *dev;
+	struct mipi_dsi_device *dsi;
+	struct drm_panel panel;
+	const struct anbernic_panel_td4310_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	struct regulator *vdd;
+	enum drm_panel_orientation orientation;
+};
+
+static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
+{
+	return container_of(panel, struct anbernic_panel_td4310, panel);
+}
+
+static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+	int ret;
+
+	ret = regulator_enable(ctx->vdd);
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+	if (ret)
+		goto err_enable;
+
+	if (ctx->panel_info->enable_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	if (ret)
+		goto err_reset;
+
+	mipi_dsi_msleep(&dsi_ctx, 10);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	if (ret)
+		goto err_reset;
+
+	if (ctx->panel_info->reset_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+
+	if (dsi_ctx.accum_err) {
+		ret = dsi_ctx.accum_err;
+		goto err_reset;
+	}
+
+	return 0;
+
+err_reset:
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+err_enable:
+	regulator_disable(ctx->vdd);
+	return ret;
+}
+
+static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->unprepare_delay);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->disable_delay);
+
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	regulator_disable(ctx->vdd);
+
+	return 0;
+}
+
+static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
+				    struct drm_connector *connector)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
+
+	connector->display_info.bpc = 8;
+	connector->display_info.width_mm = panel_info->width_mm;
+	connector->display_info.height_mm = panel_info->height_mm;
+	connector->display_info.bus_flags = panel_info->bus_flags;
+
+	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
+}
+
+static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+
+	return ctx->orientation;
+}
+
+static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
+	.prepare = panel_anbernic_td4310_prepare,
+	.unprepare = panel_anbernic_td4310_unprepare,
+	.get_modes = panel_anbernic_td4310_get_mode,
+	.get_orientation = panel_anbernic_td4310_get_orientation,
+};
+
+static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct anbernic_panel_td4310 *ctx;
+	int ret;
+
+	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
+				   &panel_anbernic_td4310_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ctx->dev = dev;
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	if (!ctx->panel_info)
+		return -EINVAL;
+
+	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Cannot get reset gpio\n");
+
+	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+				     "Cannot get enable gpio\n");
+
+	ctx->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(ctx->vdd))
+		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
+				     "Failed to request vdd regulator\n");
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	dsi->lanes = ctx->panel_info->lanes;
+	dsi->format = ctx->panel_info->format;
+	dsi->mode_flags = ctx->panel_info->mode_flags;
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	devm_drm_panel_add(dev, &ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+
+	return 0;
+}
+
+static const struct drm_display_mode anbernic_vitapro_mode = {
+	.clock = 140020,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 50,
+	.hsync_end = 1080 + 50 + 4,
+	.htotal = 1080 + 50 + 4 + 50,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 15,
+	.vsync_end = 1920 + 15 + 4,
+	.vtotal = 1920 + 15 + 4 + 32,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
+	.display_mode = &anbernic_vitapro_mode,
+	.width_mm = 69,
+	.height_mm = 121,
+	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
+		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+	.prepare_delay = 50,
+	.reset_delay = 220,
+	.enable_delay = 120,
+	.disable_delay = 50,
+	.unprepare_delay = 20,
+};
+
+static const struct of_device_id panel_anbernic_td4310_of_match[] = {
+	{
+		.compatible = "anbernic,panel-vita-pro",
+		.data = &anbernic_vitapro_info,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
+
+static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
+	.driver = {
+		.name = "panel-anbernic-td4310",
+		.of_match_table = panel_anbernic_td4310_of_match,
+	},
+	.probe	= panel_anbernic_td4310_probe,
+};
+module_mipi_dsi_driver(anbernic_panel_td4310_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:20 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:20 -0500
Subject: [PATCH V6 5/6] dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add compatible string for the Anbernic RG Vita-Pro.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b8babe9d3a26 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -66,6 +66,12 @@ properties:
               - anbernic,rg-ds
           - const: rockchip,rk3568
 
+      - description: Anbernic RK3576 Handheld Gaming Console
+        items:
+          - enum:
+              - anbernic,rg-vita-pro
+          - const: rockchip,rk3576
+
       - description: Ariaboard Photonicat
         items:
           - const: ariaboard,photonicat
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:21 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:21 -0500
Subject: [PATCH V6 6/6] arm64: dts: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add device tree for the Anbernic RG Vita-Pro, based on the Rockchip
RK3576. All hardware is currently working except for the accelerometer,
the touchscreen, the battery monitor, and DisplayPort over USB-C. PWM
is also missing currently, and as a result the LEDs and panel backlight
are currently controlled via GPIO but will be changed to PWM once
supported.

The Anbernic RG Vita-Pro includes the following hardware:
 - A 1080x1920 DSI display with touch.
 - 21 buttons.
 - 2 Analog joysticks controlled via userspace.
 - 3 LEDs.
 - 64GB eMMC, 2 SDMMC slots.
 - RTL8852BE WiFi (with Bluetooth via UART)
 - 1 USB 3.0 USB-C port in OTG mode.
 - 3.5mm headphone jack with play button support.
 - 5000mAH battery

The following hardware has incomplete driver support and is not yet
working:
 - An Invensense icm42607p accelerometer.
 - A Cellwise cw221x battery monitor.
 - A Synaptics i2c touchscreen.
 - DisplayPort over USB-C alt-mode.
 - PWM controller.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 2 files changed, 1328 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..7d86676f98e8 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-100ask-dshanpi-a1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-anbernic-rg-vita-pro.dtb
 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
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
new file mode 100644
index 000000000000..344ba1870533
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2026 Chris Morgan <macromorgan at hotmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+
+#include "rk3576.dtsi"
+
+/ {
+	model = "Anbernic RG Vita Pro";
+	chassis-type = "handset";
+	compatible = "anbernic,rg-vita-pro", "rockchip,rk3576";
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	adc_keys_home: adc-keys-home {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 1>;
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <60>;
+
+		button-home {
+			label = "HOME";
+			linux,code = <KEY_HOME>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	adc_keys_play: adc-keys-play {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 3>;
+		keyup-threshold-microvolt = <1300000>;
+		poll-interval = <60>;
+
+		button-play {
+			label = "PLAY";
+			linux,code = <KEY_PLAYPAUSE>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	/*
+	 * Battery values from BSP except for the following:
+	 *
+	 * factory-internal-resistance-micro-ohms - This was set to 80 which
+	 * is likely incorrect and changed to 80000.
+	 *
+	 * charge-full-design-microamp-hours - Was set to 8000000 but the
+	 * physical battery says 5000000.
+	 *
+	 * constant-charge-current-max-microamp - Was set to 10000000 which
+	 * both seems high and exceeds what the charger hardware can do.
+	 * Setting to 3800000 which is the maximum input current the charger
+	 * can handle.
+	 */
+	battery: battery {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <5000000>;
+		charge-term-current-microamp = <300000>;
+		constant-charge-current-max-microamp = <3800000>;
+		constant-charge-voltage-max-microvolt = <4350000>;
+		factory-internal-resistance-micro-ohms = <80000>;
+		precharge-current-microamp = <180000>;
+		precharge-upper-limit-microvolt = <3600000>;
+		voltage-max-design-microvolt = <4350000>;
+		voltage-min-design-microvolt = <3000000>;
+	};
+
+	hp_amp: audio-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&hp_amp_enable_h>;
+		pinctrl-names = "default";
+		sound-name-prefix = "Headphone Amp";
+	};
+
+	/*
+	 * LEDs and Backlights can be controlled as a PWM, but PWM
+	 * driver is not yet available.
+	 */
+	gpio_backlight: backlight {
+		compatible = "gpio-backlight";
+		gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&led_backlight_h>;
+		pinctrl-names = "default";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_amber_h>, <&led_green_h>, <&led_red_h>;
+		pinctrl-names = "default";
+
+		charging-led {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_CHARGING;
+			gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
+		};
+
+		full-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
+		};
+
+		bat-low-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_ALARM;
+			gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio_keys_control: gpio-keys-control {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&gamepad_keys_l>;
+		pinctrl-names = "default";
+
+		button-a {
+			gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
+			label = "EAST";
+			linux,code = <BTN_EAST>;
+		};
+
+		button-b {
+			gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+			label = "SOUTH";
+			linux,code = <BTN_SOUTH>;
+		};
+
+		button-down {
+			gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+			label = "DPAD-DOWN";
+			linux,code = <BTN_DPAD_DOWN>;
+		};
+
+		button-l1 {
+			gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>;
+			label = "TL";
+			linux,code = <BTN_TL>;
+		};
+
+		button-l2 {
+			gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+			label = "TL2";
+			linux,code = <BTN_TL2>;
+		};
+
+		button-left {
+			gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+			label = "DPAD-LEFT";
+			linux,code = <BTN_DPAD_LEFT>;
+		};
+
+		button-menu {
+			gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+			label = "MENU";
+			linux,code = <BTN_MODE>;
+		};
+
+		button-right {
+			gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+			label = "DPAD-RIGHT";
+			linux,code = <BTN_DPAD_RIGHT>;
+		};
+
+		button-r1 {
+			gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+			label = "T2";
+			linux,code = <BTN_TR>;
+		};
+
+		button-r2 {
+			gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+			label = "TR2";
+			linux,code = <BTN_TR2>;
+		};
+
+		button-select {
+			gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>;
+			label = "SELECT";
+			linux,code = <BTN_SELECT>;
+		};
+
+		button-start {
+			gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>;
+			label = "START";
+			linux,code = <BTN_START>;
+		};
+
+		button-thumbl {
+			gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+			label = "THUMBL";
+			linux,code = <BTN_THUMBL>;
+		};
+
+		button-thumbr {
+			gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>;
+			label = "THUMBR";
+			linux,code = <BTN_THUMBR>;
+		};
+
+		button-up {
+			gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+			label = "DPAD-UP";
+			linux,code = <BTN_DPAD_UP>;
+		};
+
+		button-x {
+			gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+			label = "NORTH";
+			linux,code = <BTN_NORTH>;
+		};
+
+		button-y {
+			gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+			label = "WEST";
+			linux,code = <BTN_WEST>;
+		};
+	};
+
+	gpio_keys_volume: gpio-keys-volume {
+		compatible = "gpio-keys";
+		autorepeat;
+		pinctrl-0 = <&vol_keys_l>;
+		pinctrl-names = "default";
+
+		vol-down-key {
+			gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEDOWN";
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+
+		vol-up-key {
+			gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEUP";
+			linux,code = <KEY_VOLUMEUP>;
+		};
+	};
+
+	hdmi-con {
+		compatible = "hdmi-connector";
+		type = "c";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_h>;
+		radio-type = "wlan";
+		shutdown-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+
+	sound: sound {
+		compatible = "simple-audio-card";
+		pinctrl-0 = <&hp_det>;
+		pinctrl-names = "default";
+		simple-audio-card,aux-devs = <&aw87391_pa_l>, <&aw87391_pa_r>,
+					     <&hp_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "rockchip,es8388-codec";
+		simple-audio-card,pin-switches = "Headphones", "Internal Speakers";
+		simple-audio-card,routing =
+			"LINPUT1", "Mic Jack",
+			"LINPUT2", "Mic Jack",
+			"RINPUT1", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone",
+			"Headphones", "Headphone Amp OUTL",
+			"Headphones", "Headphone Amp OUTR",
+			"Headphone Amp INL", "LOUT1",
+			"Headphone Amp INR", "ROUT1",
+			"Internal Speakers", "Left Amp OUT",
+			"Internal Speakers", "Right Amp OUT",
+			"Left Amp IN", "LOUT2",
+			"Right Amp IN", "ROUT2";
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Internal Speakers";
+		status = "okay";
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1100000>;
+		regulator-min-microvolt = <1100000>;
+		regulator-name = "vcc_1v1_nldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <2000000>;
+		regulator-min-microvolt = <2000000>;
+		regulator-name = "vcc_2v0_pldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_3v8_sys: regulator-vcc-3v8-sys {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <3800000>;
+		regulator-min-microvolt = <3800000>;
+		regulator-name = "vcc_3v8_sys";
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_3v3_sd_s0_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc_sdio: regulator-vcc-sdio {
+		compatible = "regulator-gpio";
+		regulator-name = "vcc_sdio";
+		gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_sdio_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <1800000>;
+		states = <1800000 0>, <3300000 1>;
+	};
+
+	vcc_wifi: regulator-vcc-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_wifi";
+		enable-active-high;
+		gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_wifi_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vdd_lcd: regulator-vdd-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_lcd";
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vdd_lcd_h>;
+		pinctrl-names = "default";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&dsi {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	panel: panel at 0 {
+		compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+		reg = <0>;
+		backlight = <&gpio_backlight>;
+		enable-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable>, <&lcd_rst>;
+		reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
+		rotation = <270>;
+		vdd-supply = <&vdd_lcd>;
+
+		port {
+			mipi_in_panel: endpoint {
+				remote-endpoint = <&mipi_out_panel>;
+			};
+		};
+	};
+};
+
+&dsi_in {
+	dsi_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dsi>;
+	};
+};
+
+&dsi_out {
+	mipi_out_panel: endpoint {
+		remote-endpoint = <&mipi_in_panel>;
+	};
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&hdmi_sound {
+	status = "okay";
+};
+
+&hdptxphy {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m1_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	/* synaptics,dsx-i2c touchscreen at 0x70 */
+};
+
+&i2c1 {
+	status = "okay";
+
+	pmic at 23 {
+		compatible = "rockchip,rk806";
+		reg = <0x23>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins
+			     &rk806_dvs1_null
+			     &rk806_dvs2_null
+			     &rk806_dvs3_null>;
+		system-power-controller;
+		vcc1-supply = <&vcc_3v8_sys>;
+		vcc2-supply = <&vcc_3v8_sys>;
+		vcc3-supply = <&vcc_3v8_sys>;
+		vcc4-supply = <&vcc_3v8_sys>;
+		vcc5-supply = <&vcc_3v8_sys>;
+		vcc6-supply = <&vcc_3v8_sys>;
+		vcc7-supply = <&vcc_3v8_sys>;
+		vcc8-supply = <&vcc_3v8_sys>;
+		vcc9-supply = <&vcc_3v8_sys>;
+		vcc10-supply = <&vcc_3v8_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc_3v8_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc_3v8_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_pwrdn: dvs1-pwrdn-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: dvs1-rst-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs1_slp: dvs1-slp-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_dvs: dvs2-dvs-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: dvs2-gpio-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_pwrdn: dvs2-pwrdn-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: dvs2-rst-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_slp: dvs2-slp-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_dvs: dvs3-dvs-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: dvs3-gpio-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_pwrdn: dvs3-pwrdn-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: dvs3-rst-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_slp: dvs3-slp-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		regulators {
+			vdd_cpu_big_s0: dcdc-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_big_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_npu_s0: dcdc-reg2 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_npu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vdd_gpu_s0: dcdc-reg5 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_logic_s0: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <800000>;
+				regulator-name = "vdd_logic_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdd_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo2_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdda_1v2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcca_3v3_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo6_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdda_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_ddr_pll_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v75_hdmi_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda0v75_hdmi_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_0v85_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda_0v75_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	/* inv,icm42607 IMU at 0x68 */
+};
+
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		assigned-clock-rates = <12288000>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		DVDD-supply = <&vcc_3v3_s3>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		pinctrl-0 = <&sai1m0_mclk>;
+		pinctrl-names = "default";
+		PVDD-supply = <&vcc_3v3_s3>;
+		#sound-dai-cells = <0>;
+	};
+
+	aw87391_pa_l: audio-codec at 58 {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x58>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Left Amp";
+	};
+
+	aw87391_pa_r: audio-codec at 5b {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x5b>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Right Amp";
+	};
+};
+
+&i2c6 {
+	pinctrl-0 = <&i2c6m3_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	sgm41542: charger at 3b {
+		compatible = "sgmicro,sgm41542";
+		reg = <0x3b>;
+		input-current-limit-microamp = <3000000>;
+		input-voltage-limit-microvolt = <4500000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-0 = <&charger_irq>;
+		pinctrl-names = "default";
+		monitored-battery = <&battery>;
+		status = "okay";
+
+		regulators {
+			vbus5v0_typec: otg-vbus {
+				regulator-name = "vbus5v0_typec";
+				regulator-max-microvolt = <5000000>;
+				regulator-min-microvolt = <5000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+
+	/* Unused iSmartWare SW2001 encryption device at 0x3c */
+
+	husb311: typec-portc at 4e {
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD1 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&usbc_int>;
+		pinctrl-names = "default";
+		status = "okay";
+		vbus-supply = <&vbus5v0_typec>;
+
+		connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			op-sink-microwatt = <10000000>;
+			power-role = "dual";
+			try-power-role  = "sink";
+
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_FIXED(9000, 2000, PDO_FIXED_USB_COMM)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs_ep: endpoint {
+						remote-endpoint = <&usb_drd0_hs_ep>;
+					};
+				};
+				port at 1 {
+					reg = <1>;
+					usbc0_ss_ep: endpoint {
+						remote-endpoint = <&usb_drd0_ss_ep>;
+					};
+				};
+				port at 2 {
+					reg = <2>;
+					usbc0_dp_ep: endpoint {
+						remote-endpoint = <&usbdp_phy_ep>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hym8563_int>;
+		wakeup-source;
+	};
+
+	/* cellwise,cw221X battery manager at 0x64 */
+};
+
+&mipidcphy {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_perstn>;
+	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_wifi>;
+	status = "okay";
+};
+
+&pinctrl {
+	audio {
+		hp_amp_enable_h: hp-amp-enable {
+			rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_det: hp-det {
+			rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	bluetooth {
+		bt_reset_gpio: bt-reset-pin {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_gpio: bt-wake-pin {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_host_irq: bt-wake-host-irq {
+			rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	charger {
+		charger_irq: charger-irq {
+			rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	display {
+		lcd_enable: lcd-enable {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		lcd_rst: lcd-rst {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	gpio-keys {
+		vol_keys_l: vol-keys_l {
+			rockchip,pins =
+				<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		gamepad_keys_l: gamepad-keys-l {
+			rockchip,pins =
+				<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	gpio-leds {
+		led_amber_h: led-amber-h {
+			rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_backlight_h: led-backlight-h {
+			rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_green_h: led-green-h {
+			rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_red_h: led-red-h {
+			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie0_perstn: pcie0-perstn {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	regulator {
+		vcc_3v3_sd_s0_h: vcc-3v3-sd-s0-h {
+			rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_sdio_h: vcc-sdio-h {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_wifi_h: vcc-wifi-h {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vdd_lcd_h: vdd-lcd-h {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtc {
+		hym8563_int: hym8563-int {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	touch {
+		touch_int: touch-int {
+			rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		usbc_int: usbc-int {
+			rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		usbc0_sbu1: usbc0-sbu1 {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		usbc0_sbu2: usbc0-sbu2 {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	wifi {
+		wifi_en_h: wifi-en-h {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sai1 {
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai6 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
+&sdio {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&sdmmc1m0_bus4>, <&sdmmc1m0_clk>,
+		    <&sdmmc1m0_cmd>, <&sdmmc1m0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vcc_sdio>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	no-sd;
+	no-sdio;
+	non-removable;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>,
+		    <&sdmmc0_cmd>, <&sdmmc0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi1 {
+	num-cs = <1>;
+	pinctrl-0 = <&spi1m2_pins>, <&spi1m2_csn0>;
+	status = "okay";
+
+	/* SPI controlled MCU for joystick and joystick LEDs. */
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_dsi: endpoint at ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi_in_vp1>;
+	};
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m1_xfer>, <&uart6m1_ctsn>, <&uart6m1_rtsn>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "realtek,rtl8822cs-bt";
+		device-wake-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		host-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&bt_reset_gpio>, <&bt_wake_gpio>, <&bt_wake_host_irq>;
+		pinctrl-names = "default";
+	};
+};
+
+&usbdp_phy {
+	mode-switch;
+	orientation-switch;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbc0_sbu1 &usbc0_sbu2>;
+	sbu1-dc-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		usbdp_phy_ep: endpoint {
+			remote-endpoint = <&usbc0_dp_ep>;
+		};
+	};
+};
+
+&usb_drd0_dwc3 {
+	usb-role-switch;
+	dr_mode = "otg";
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_drd0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_drd0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss_ep>;
+			};
+		};
+	};
+};
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun  8 10:55:17 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon,  8 Jun 2026 12:55:17 -0500
Subject: [PATCH V6 2/6] power: supply: sgm41542: Add SG Micro sgm41542 charger
In-Reply-To: <20260608175521.67449-1-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
Message-ID: <20260608175521.67449-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the SG Micro SGM41542 charger/boost converter.
Driver was adapted from Rockchip BSP driver [1] and confirmed
with vendor datasheet [2].

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
[2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/power/supply/Kconfig            |    8 +
 drivers/power/supply/Makefile           |    1 +
 drivers/power/supply/sgm41542_charger.c | 1057 +++++++++++++++++++++++
 3 files changed, 1066 insertions(+)
 create mode 100644 drivers/power/supply/sgm41542_charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 83392ed6a8da..57dae0913472 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -856,6 +856,14 @@ config CHARGER_RK817
 	help
 	  Say Y to include support for Rockchip RK817 Battery Charger.
 
+config CHARGER_SGM41542
+	tristate "SGM41542 charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the SGM41542 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB3XX Battery Charger"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7ee839dca7f3..c376889db317 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
+obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
new file mode 100644
index 000000000000..f6aff2c2335d
--- /dev/null
+++ b/drivers/power/supply/sgm41542_charger.c
@@ -0,0 +1,1057 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Charger driver for SGM4154x
+ *
+ * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Xu Shengfei <xsf at rock-chips.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/types.h>
+
+#define SGM4154X_MANUFACTURER			"SGMICRO"
+#define SGM4154X_NAME				"sgm41542"
+
+#define SGM4154X_CHRG_CTRL_0			0x00
+#define SGM4154X_HIZ_EN				BIT(7)
+#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
+#define SGM4154X_IINDPM_I_MIN_UA		100000
+#define SGM4154X_IINDPM_I_MAX_UA		3800000
+#define SGM4154X_IINDPM_STEP_UA			100000
+#define SGM4154X_IINDPM_DEF_UA			2400000
+
+#define SGM4154X_CHRG_CTRL_1			0x01
+#define SGM4154X_WDT_RST			BIT(6)
+#define SGM4154X_OTG_EN				BIT(5)
+#define SGM4154X_CHRG_EN			BIT(4)
+
+#define SGM4154X_CHRG_CTRL_2			0x02
+#define SGM4154X_BOOST_LIM			BIT(7)
+#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
+#define SGM4154X_ICHRG_I_STEP_UA		60000
+#define SGM4154X_ICHRG_I_MIN_UA			0
+#define SGM4154X_ICHRG_I_MAX_UA			3780000
+#define SGM4154X_ICHRG_I_DEF_UA			2040000
+
+#define SGM4154X_CHRG_CTRL_3			0x03
+#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
+#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_PRECHRG_I_MIN_UA		60000
+#define SGM4154X_PRECHRG_I_MAX_UA		780000
+#define SGM4154X_PRECHRG_I_DEF_UA		180000
+#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
+#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_TERMCHRG_I_MIN_UA		60000
+#define SGM4154X_TERMCHRG_I_MAX_UA		960000
+#define SGM4154X_TERMCHRG_I_DEF_UA		180000
+
+#define SGM4154X_CHRG_CTRL_4			0x04
+#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
+#define SGM4154X_VREG_V_MAX_UV			4624000
+#define SGM4154X_VREG_V_MIN_UV			3856000
+#define SGM4154X_VREG_V_DEF_UV			4208000
+#define SGM4154X_VREG_V_STEP_UV			32000
+#define SGM4154X_VRECHARGE			BIT(0)
+#define SGM4154X_VRECHRG_STEP_MV		100
+#define SGM4154X_VRECHRG_OFFSET_MV		100
+
+#define SGM4154X_CHRG_CTRL_5			0x05
+#define SGM4154X_TERM_EN			BIT(7)
+#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
+
+#define SGM4154X_CHRG_CTRL_6			0x06
+#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
+#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
+#define SGM4154X_OVP_10_5V			BIT(7)
+#define SGM4154X_OVP_6_5V			BIT(6)
+#define SGM4154X_OVP_5_5V			0
+#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
+#define SGM4154X_BOOSTV				GENMASK(5, 4)
+#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
+#define SGM4154X_VINDPM_V_MIN_UV		3900000
+#define SGM4154X_VINDPM_V_MAX_UV		12000000
+#define SGM4154X_VINDPM_STEP_UV			100000
+#define SGM4154X_VINDPM_DEF_UV			4500000
+
+#define SGM4154X_CHRG_CTRL_7			0x07
+
+#define SGM4154X_CHRG_STAT		0x08
+#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
+#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
+#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
+#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
+#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
+#define SGM4154X_USB_CDP		BIT(6)
+#define SGM4154X_USB_SDP		BIT(5)
+#define SGM4154X_NOT_CHRGING		0
+#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
+#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
+#define SGM4154X_FAST_CHRG		BIT(4)
+#define SGM4154X_PRECHRG		BIT(3)
+#define SGM4154X_PG_STAT		BIT(2)
+#define SGM4154X_THERM_STAT		BIT(1)
+#define SGM4154X_VSYS_STAT		BIT(0)
+
+#define SGM4154X_CHRG_FAULT		0x09
+#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
+#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
+#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
+#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
+#define SGM4154X_TEMP_WARM		BIT(1)
+#define SGM4154X_TEMP_NORMAL		BIT(0)
+
+#define SGM4154X_CHRG_CTRL_A		0x0a
+#define SGM4154X_VBUS_GOOD		BIT(7)
+#define SGM4154X_VINDPM_INT_MASK	BIT(1)
+#define SGM4154X_IINDPM_INT_MASK	BIT(0)
+
+#define SGM4154X_CHRG_CTRL_B		0x0b
+#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
+#define SGM4154X_PN_MASK		GENMASK(6, 3)
+
+#define SGM4154X_CHRG_CTRL_C		0x0c
+
+#define SGM4154X_CHRG_CTRL_D		0x0d
+#define SGM4154X_JEITA_EN		BIT(0)
+
+#define SGM4154X_INPUT_DET		0x0e
+#define SGM4154X_DPDM_ONGOING		BIT(7)
+
+#define SGM4154X_CHRG_CTRL_F		0x0f
+#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
+
+#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
+
+struct sgm4154x_init_data {
+	int ilim;	/* input current limit */
+	int vlim;	/* minimum system voltage limit */
+	int iterm;	/* termination current */
+	int iprechg;	/* precharge current */
+	int max_ichg;	/* maximum charge current */
+	int max_vreg;	/* maximum charge voltage */
+};
+
+struct sgm4154x_state {
+	bool vsys_stat;
+	bool therm_stat;
+	bool online;
+	u8 chrg_stat;
+	bool chrg_en;
+	bool vbus_gd;
+	u8 chrg_type;
+	u8 health;
+	u8 chrg_fault;
+	u8 ntc_fault;
+};
+
+struct sgm4154x_device {
+	struct device *dev;
+	struct power_supply *charger;
+	struct regmap *regmap;
+	struct sgm4154x_init_data init_data;
+	struct sgm4154x_state state;
+	struct regulator_dev *otg_rdev;
+	bool watchdog_enable;
+	struct workqueue_struct *sgm_monitor_wq;
+	struct delayed_work sgm_delay_work;
+};
+
+enum SGM4154X_VINDPM_OS {
+	VINDPM_OS_3900MV,
+	VINDPM_OS_5900MV,
+	VINDPM_OS_7500MV,
+	VINDPM_OS_10500MV,
+};
+
+enum sgm4154x_wdt_values {
+	SGM4154X_WDT_TIMER_DISABLE = 0,
+	SGM4154X_WDT_TIMER_40S = 1,
+	SGM4154X_WDT_TIMER_80S = 2,
+	SGM4154X_WDT_TIMER_160S = 3,
+};
+
+static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_TERMCHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set term current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
+
+	reg_val = FIELD_PREP(SGM4154X_PRECHRG_CUR_MASK, reg_val);
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_PRECHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set precharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, sgm->init_data.max_ichg);
+	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_2,
+				 SGM4154X_ICHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set icharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge current error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
+
+	return val * SGM4154X_ICHRG_I_STEP_UA;
+}
+
+static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
+{
+	int reg_val;
+	int ret;
+
+	/*
+	 * Note that the value of 0x01111 represents a "special value"
+	 * corresponding to 4352000uV instead of the expected 4336000uV,
+	 * per the datasheet. All other values are as expected. So not
+	 * only do we need to clamp between max and min values, but
+	 * also clamp anything below 4352000uv to 4304000uv to prevent
+	 * overcharging.
+	 */
+	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
+	if (chrg_volt < 4352000)
+		chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, 4304000);
+	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
+	reg_val = FIELD_PREP(SGM4154X_VREG_V_MASK, reg_val);
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VREG_V_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set charge voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge voltage error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
+
+	/*
+	 * 0x01111 is a special value meaning 4352000uV, all other
+	 * values are as expected based on the offset and step values.
+	 */
+	if (val == 0x0f)
+		return 4352000;
+
+	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
+}
+
+static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
+				       unsigned int vindpm)
+{
+	enum SGM4154X_VINDPM_OS os_val;
+	unsigned int offset;
+	u8 reg_val;
+	int ret;
+
+
+	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
+	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
+		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
+		return -EINVAL;
+	}
+
+	/*
+	 * Supported ranges per the datasheet are as follows:
+	 * 3.9v - 5.4v with a 3.9v offset
+	 * 5.9v - 7.4v with a 5.9v offset
+	 * 7.5v - 9.0v with a 7.5v offset
+	 * 10.5v - 12.0v with a 10.5v offset
+	 * Step size is a constant 100mv
+	 */
+	if (vindpm < 5900000) {
+		offset = 3900000;
+		vindpm = clamp(vindpm, offset, 5400000);
+		os_val = VINDPM_OS_3900MV;
+	} else if (vindpm < 7500000) {
+		offset = 5900000;
+		vindpm = clamp(vindpm, offset, 7400000);
+		os_val = VINDPM_OS_5900MV;
+	} else if (vindpm < 10500000) {
+		offset = 7500000;
+		vindpm = clamp(vindpm, offset, 9000000);
+		os_val = VINDPM_OS_7500MV;
+	} else {
+		offset = 10500000;
+		vindpm = clamp(vindpm, offset, 12000000);
+		os_val = VINDPM_OS_10500MV;
+	}
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_F,
+				 SGM4154X_VINDPM_OS_MASK,
+				 os_val);
+	if (ret) {
+		dev_err(sgm->dev, "set vin dpm error!\n");
+		return ret;
+	}
+
+	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VINDPM_V_MASK, reg_val);
+	if (ret)
+		dev_err(sgm->dev, "input voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
+{
+	int reg_val;
+	int ret;
+
+	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Per the datasheet, values between 100000uA and 3100000uA work
+	 * as expected with the register defined as having a step of
+	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
+	 * The register value of 0x1f however corresponds to 3800000uA not
+	 * 3200000uA as one would expect.
+	 */
+	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
+		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
+
+	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
+		iindpm = 3100000;
+
+	if (iindpm == SGM4154X_IINDPM_I_MAX_UA)
+		reg_val = 0x1f;
+	else
+		reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_0,
+				 SGM4154X_IINDPM_I_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set input current limit error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int ilim;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
+	if (ret) {
+		dev_err(sgm->dev, "get input current limit error!\n");
+		return ret;
+	}
+
+	ilim &= SGM4154X_IINDPM_I_MASK;
+
+	/* Max value is not 3200000uA as expected but is 3800000uA */
+	if (ilim == SGM4154X_IINDPM_I_MASK)
+		return SGM4154X_IINDPM_I_MAX_UA;
+
+	ilim = ilim * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
+
+	return ilim;
+}
+
+static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_WDT_RST,
+				 SGM4154X_WDT_RST);
+
+	if (ret)
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, u8 time)
+{
+	int ret;
+
+	if (time > 3)
+		return -EINVAL;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_5,
+				 SGM4154X_WDT_TIMER_MASK,
+				 time);
+
+	if (ret) {
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+		return ret;
+	}
+
+	if (time) {
+		if (!sgm->watchdog_enable)
+			queue_delayed_work(sgm->sgm_monitor_wq,
+					   &sgm->sgm_delay_work,
+					   msecs_to_jiffies(1000 * 5));
+		sgm->watchdog_enable = true;
+	} else {
+		sgm->watchdog_enable = false;
+		sgm4154x_watchdog_timer_reset(sgm);
+	}
+
+	return ret;
+}
+
+static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 SGM4154X_CHRG_EN);
+	if (ret)
+		dev_err(sgm->dev, "enable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 0);
+	if (ret)
+		dev_err(sgm->dev, "disable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VAC_OVP_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set vac ovp error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_recharge_volt_ua(struct sgm4154x_device *sgm, int recharge_volt)
+{
+	int reg_val;
+	int ret;
+
+	recharge_volt = recharge_volt / 1000;
+
+	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VRECHARGE,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set recharger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_state(struct sgm4154x_device *sgm,
+			      struct sgm4154x_state *state)
+{
+	int reg, ret;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
+		return ret;
+	}
+	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
+	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
+	state->online = !!(reg & SGM4154X_PG_STAT);
+	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
+	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
+		return ret;
+	}
+	state->chrg_fault = reg;
+	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
+	state->health = state->ntc_fault;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
+		return ret;
+	}
+	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
+
+	return ret;
+}
+
+static int sgm4154x_property_is_writeable(struct power_supply *psy,
+					  enum power_supply_property prop)
+{
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int sgm4154x_charger_set_property(struct power_supply *psy,
+					 enum power_supply_property prop,
+					 const union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			ret = sgm4154x_enable_charger(sgm);
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
+		} else {
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_DISABLE);
+			ret = sgm4154x_disable_charger(sgm);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sgm4154x_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm, &state);
+	if (ret) {
+		dev_err(sgm->dev, "get state error!\n");
+		return ret;
+	}
+	sgm->state = state;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		else if (!state.chrg_stat)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		switch (state.chrg_stat) {
+		case SGM4154X_PRECHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_FAST_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		case SGM4154X_TERM_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_NOT_CHRGING:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		}
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = SGM4154X_MANUFACTURER;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SGM4154X_NAME;
+		break;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = state.online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = state.vbus_gd;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		val->intval = sgm4154x_get_chrg_volt(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		val->intval = sgm4154x_get_ichrg_curr(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		val->intval = sgm->init_data.vlim;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		val->intval = sgm4154x_get_input_curr_lim(sgm);
+		if (val->intval < 0)
+			return  -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
+{
+	struct sgm4154x_device *sgm4154x = private;
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm4154x, &state);
+	if (ret) {
+		dev_err(sgm4154x->dev, "get state error!\n");
+		return IRQ_NONE;
+	}
+	sgm4154x->state = state;
+	if (state.vbus_gd) {
+		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
+			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
+			if (ret) {
+				dev_err(sgm4154x->dev, "set input current error!\n");
+				/* Reading IRQ clears interrupt, so return handled */
+				return IRQ_HANDLED;
+			}
+		}
+	}
+	power_supply_changed(sgm4154x->charger);
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property sgm4154x_power_supply_props[] = {
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_PRESENT
+};
+
+static struct power_supply_desc sgm4154x_power_supply_desc = {
+	.name = "sgm4154x-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = sgm4154x_power_supply_props,
+	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
+	.get_property = sgm4154x_charger_get_property,
+	.set_property = sgm4154x_charger_set_property,
+	.property_is_writeable = sgm4154x_property_is_writeable,
+};
+
+static const struct regmap_config sgm4154x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = SGM4154X_CHRG_CTRL_F,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
+				      struct device *dev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = sgm,
+					       .fwnode = dev->fwnode, };
+
+	sgm->charger = devm_power_supply_register(sgm->dev,
+						  &sgm4154x_power_supply_desc,
+						  &psy_cfg);
+	if (IS_ERR(sgm->charger))
+		return PTR_ERR(sgm->charger);
+
+	return 0;
+}
+
+static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
+{
+	struct power_supply_battery_info *bat_info;
+	int ret;
+	u32 val;
+
+	/*
+	 * If unable to read devicetree info, use default/reset
+	 * values from hardware. If the devicetree info has data out
+	 * of range for any of the values, use the default value.
+	 */
+	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
+	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
+	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
+	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
+	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
+	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
+
+	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
+	if (ret)
+		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
+	else {
+		if ((bat_info->constant_charge_current_max_ua >= SGM4154X_ICHRG_I_MIN_UA) &&
+			(bat_info->constant_charge_current_max_ua <= SGM4154X_ICHRG_I_MAX_UA))
+			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
+		if ((bat_info->constant_charge_voltage_max_uv >= SGM4154X_VREG_V_MIN_UV) &&
+			(bat_info->constant_charge_voltage_max_uv <= SGM4154X_VREG_V_MAX_UV))
+			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
+		if ((bat_info->charge_term_current_ua >= SGM4154X_TERMCHRG_I_MIN_UA) &&
+			(bat_info->charge_term_current_ua <= SGM4154X_TERMCHRG_I_MAX_UA))
+			sgm->init_data.iterm = bat_info->charge_term_current_ua;
+		if ((bat_info->precharge_current_ua >= SGM4154X_PRECHRG_I_MIN_UA) &&
+			(bat_info->precharge_current_ua <= SGM4154X_PRECHRG_I_MAX_UA))
+			sgm->init_data.iprechg = bat_info->precharge_current_ua;
+
+		power_supply_put_battery_info(sgm->charger, bat_info);
+	}
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-voltage-limit-microvolt",
+				       &val);
+	if (!ret)
+		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
+					    SGM4154X_VINDPM_V_MAX_UV);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-current-limit-microamp",
+				       &val);
+	if (!ret)
+		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
+					    SGM4154X_IINDPM_I_MAX_UA);
+
+	ret = sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_vac_ovp(sgm);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_D,
+			   SGM4154X_JEITA_EN,
+			   0);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_IINDPM_INT_MASK,
+			   SGM4154X_IINDPM_INT_MASK);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_VINDPM_INT_MASK,
+			   SGM4154X_VINDPM_INT_MASK);
+
+	/*
+	 * Recharge microvolt set to 200000 by BSP driver instead of hardware
+	 * default value of 100000.
+	 */
+	ret = sgm4154x_set_recharge_volt_ua(sgm, 200000);
+
+	return ret;
+}
+
+static const u32 sgm4154x_chg_otg_cur_ua[] = {
+	1200000, 2000000,
+};
+
+static const struct regulator_ops sgm4154x_vbus_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const struct regulator_desc sgm4154x_otg_rdesc = {
+	.of_match = "otg-vbus",
+	.name = "otg-vbus",
+	.regulators_node = of_match_ptr("regulators"),
+	.ops = &sgm4154x_vbus_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4850000,
+	.uV_step = 150000,
+	.n_voltages = 4,
+	.vsel_reg = SGM4154X_CHRG_CTRL_6,
+	.vsel_mask = SGM4154X_BOOSTV,
+	.enable_reg = SGM4154X_CHRG_CTRL_1,
+	.enable_mask = SGM4154X_OTG_EN,
+	.curr_table = sgm4154x_chg_otg_cur_ua,
+	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
+	.csel_reg = SGM4154X_CHRG_CTRL_2,
+	.csel_mask = SGM4154X_BOOST_LIM,
+};
+
+static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
+{
+	struct regulator_config config = {
+		.dev = sgm->dev,
+		.regmap = sgm->regmap,
+		.driver_data = sgm,
+	};
+
+	sgm->otg_rdev = devm_regulator_register(sgm->dev,
+						&sgm4154x_otg_rdesc,
+						&config);
+
+	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
+}
+
+static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
+	if (ret)
+		return ret;
+
+	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
+		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
+
+	return 0;
+}
+
+static void sgm_charger_work(struct work_struct *work)
+{
+	struct sgm4154x_device *sgm =
+		container_of(work,
+			     struct sgm4154x_device,
+			     sgm_delay_work.work);
+
+	sgm4154x_watchdog_timer_reset(sgm);
+	if (sgm->watchdog_enable)
+		queue_delayed_work(sgm->sgm_monitor_wq,
+				   &sgm->sgm_delay_work,
+				   msecs_to_jiffies(1000 * 5));
+}
+
+static void sgm4154x_disable_irq_wake(void *data)
+{
+	struct sgm4154x_device *sgm = data;
+	struct i2c_client *client = to_i2c_client(sgm->dev->parent);
+
+	disable_irq_wake(client->irq);
+}
+
+static int sgm4154x_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct sgm4154x_device *sgm;
+	int ret;
+
+	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
+	if (!sgm)
+		return -ENOMEM;
+
+	sgm->dev = dev;
+
+	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
+	if (IS_ERR(sgm->regmap))
+		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
+				     "Failed to allocate register map\n");
+
+	i2c_set_clientdata(client, sgm);
+
+	ret = sgm4154x_hw_chipid_detect(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to read HW ID\n");
+
+	device_init_wakeup(dev, 1);
+
+	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "sgm-monitor-wq",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE);
+	if (!sgm->sgm_monitor_wq)
+		return -EINVAL;
+
+	ret = devm_delayed_work_autocancel(dev, &sgm->sgm_delay_work,
+					   sgm_charger_work);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to register delayed work\n");
+
+	ret = sgm4154x_power_supply_init(sgm, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register power supply\n");
+
+	ret = sgm4154x_hw_init(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						sgm4154x_irq_handler_thread,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						"sgm41542-irq", sgm);
+		if (ret)
+			return ret;
+
+		enable_irq_wake(client->irq);
+		devm_add_action_or_reset(dev, sgm4154x_disable_irq_wake, sgm);
+	}
+
+	ret = sgm4154x_vbus_regulator_register(sgm);
+	if (ret) {
+		return dev_err_probe(dev, ret,
+				     "Unable to register VBUS regulator\n");
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id sgm4154x_i2c_ids[] = {
+	{ "sgm41542" },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
+
+static const struct of_device_id sgm4154x_of_match[] = {
+	{ .compatible = "sgmicro,sgm41542", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
+
+static struct i2c_driver sgm4154x_driver = {
+	.driver = {
+		.name = "sgm4154x-charger",
+		.of_match_table = sgm4154x_of_match,
+	},
+	.probe = sgm4154x_probe,
+	.id_table = sgm4154x_i2c_ids,
+};
+
+module_i2c_driver(sgm4154x_driver);
+
+MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
+MODULE_DESCRIPTION("sgm4154x charger driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From nicolas at ndufresne.ca  Mon Jun  8 13:20:09 2026
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Mon, 08 Jun 2026 16:20:09 -0400
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal
 de-blocking edges y=4 and y=12
In-Reply-To: <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
	 <5797ac61-dc61-4182-ac60-cc377564ff90@collabora.com>
	 <2565c949-a558-415f-8c79-e47812db8341@symple.nz>
	 <e3b93bda-fed8-4f21-b3d8-cdf28bfaba1c@collabora.com>
	 <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
	 <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
Message-ID: <f8352762151d02c0ade63a087e48df9f8bb23ba9.camel@ndufresne.ca>

Hi Simon, Detlev,

Le lundi 08 juin 2026 ? 17:11 +1200, Simon Wright a ?crit?:
> A reference implementation -- the DMA priming buffer plus the
> link-register kick sequence, ported from the BSP -- is in the repo I
> shared (the warmup code itself is in the sibling rkvdec-vdpu383-vp9 /
> -av1 repos, src/rkvdec-link.c):
> 
> ? https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug
> 
> I'm not sure of the right mainline form for a vendor-disassembly-
> derived priming sequence, so I've left it as a report + reference
> rather than a patch -- you're much better placed to decide how, or
> whether, it belongs in rkvdec. Happy to test any version on the RK3576
> boards here.

just a two cent proposal. We could save the resume state, and on the first frame
after resume, we'd prepend the workaround decode operation to the TBL. That
would be a bit cleaner, and would batch the workaround without having to
manually poll. The resume state is then cleared on the workaround decode IRQ
(IRQ needs to be enabled in the workaround). Its not a very impactful on
performance otherwise, but we know from past mpp workaround that they don't
always imply a HW bug, they often use workaround as hotfix for other issue they
haven't figure-out yet.

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-rockchip/attachments/20260608/7af8ec36/attachment.sig>

From nicolas at ndufresne.ca  Mon Jun  8 13:22:41 2026
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Mon, 08 Jun 2026 16:22:41 -0400
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal
 de-blocking edges y=4 and y=12
In-Reply-To: <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
	 <5797ac61-dc61-4182-ac60-cc377564ff90@collabora.com>
	 <2565c949-a558-415f-8c79-e47812db8341@symple.nz>
	 <e3b93bda-fed8-4f21-b3d8-cdf28bfaba1c@collabora.com>
	 <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
	 <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
Message-ID: <25a232dca0236788c75231c43ee8a01741148c37.camel@ndufresne.ca>

Hi Simon,

Le lundi 08 juin 2026 ? 17:11 +1200, Simon Wright a ?crit?:
> It's an un-primed hardware state after power-up, not BL31 and not a
> per-frame register. The Rockchip BSP runs a one-shot priming decode at
> every decoder power-on -- rk3576_workaround_run() in
> drivers/video/rockchip/mpp/hack/mpp_hack_rk3576.c builds a tiny
> self-contained H.264 task and runs it through the decoder at probe and
> on every pm_runtime resume. Mainline rkvdec has no equivalent, so the
> first decode(s) after each power-up run with indeterminate internal
> deblock state.

another one, in the link, it says you have compared SRAM vs DRAM for RCB, to
rule out the location of the RCB data as a problem. You haven't dumped the RCB
data before and after in a way that the state of the RCB data could not be
compared against Detlev (working) case. It if was an RCB data state, it way
simpler to just initialize it.

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-rockchip/attachments/20260608/6b857f73/attachment.sig>

From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 13:44:23 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 22:44:23 +0200
Subject: [PATCH v3 0/3] dt-bindings: mfd: syscon: Tighten checks
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>

Changes in v3:
- Drop patch #2:
  dt-bindings: mfd: syscon: Drop unneeded case for syscon + simple-mfd
- Bump dtschema requirement
- Link to v2: https://patch.msgid.link/20260608-n-dt-bindings-simple-bus-syscon-v2-0-0203e6c249dc at oss.qualcomm.com

Changes in v2:
1. New patches #2 and #3
1. Add missing part of patch #1, thus not adding Rob's Ack.
https://lore.kernel.org/all/20260531110404.12768-3-krzysztof.kozlowski at oss.qualcomm.com/

I tested dt_binding_check and dtbs_check for arm, arm64 and riscv and I
think I did not introduce new dtbs_check warnings. Old code anyway has
multiple abuses of syscon, thus tricky to judge for arm at least.

Best regards,
Krzysztof

---
Krzysztof Kozlowski (3):
      dt-bindings: mfd: syscon: Disallow simple-bus with syscon
      dt-bindings: mfd: syscon: Drop custom select for older dtschema
      ARM: dts: ti: Add specific compatibles for SCM conf nodes

 Documentation/devicetree/bindings/Makefile         |   2 +-
 .../devicetree/bindings/mfd/syscon-common.yaml     |  34 ++++++
 Documentation/devicetree/bindings/mfd/syscon.yaml  | 116 ---------------------
 arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi           |   2 +-
 arch/arm/boot/dts/ti/omap/am437x-l4.dtsi           |   2 +-
 arch/arm/boot/dts/ti/omap/dm814x.dtsi              |   2 +-
 arch/arm/boot/dts/ti/omap/dm816x.dtsi              |   2 +-
 arch/arm/boot/dts/ti/omap/dra7-l4.dtsi             |   2 +-
 arch/arm/boot/dts/ti/omap/omap2430.dtsi            |   2 +-
 arch/arm/boot/dts/ti/omap/omap3.dtsi               |   2 +-
 arch/arm/boot/dts/ti/omap/omap4-l4.dtsi            |   2 +-
 arch/arm/boot/dts/ti/omap/omap5-l4.dtsi            |   6 +-
 12 files changed, 46 insertions(+), 128 deletions(-)
---
base-commit: 78f5e68a8d0a1123dd1b007688ccf0e6876a5c15
change-id: 20260608-n-dt-bindings-simple-bus-syscon-e39df408a02d

Best regards,
--  
Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 13:44:24 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 22:44:24 +0200
Subject: [PATCH v3 1/3] dt-bindings: mfd: syscon: Disallow simple-bus with
 syscon
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v3-1-4eba9ec1212a@oss.qualcomm.com>

"syscon" is a system controller with registers having their own
functions, thus not really a trivial MMIO simple bus.  "simple-bus" on
the other hand is just a bus on which multiple devices sit and the
"simple" means no functions are allowed here.

Combination of both "syscon" and "simple-bus" is abuse of DT for easier
instantiating of Linux device drivers so add a schema to disallow that.

Unfortunately there are a few old cases of that patterns, so add
exceptions:

1. "cznic,turris1x-cpld" and "img,pistachio-cr-periph" are already used
   in upstream DTS.

2. TI has several DTSI with a child of SCM device (e.g. "ti,am3-scm")
   using "syscon" and "simple-bus" but without a dedicated compatible
   documented anywhere.  Add new compatibles for such cases.

Additionally, add comments around code enforcing two or three
compatibles: it is similar safeguard detecting incorrect bindings.

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

---

Changes in v3:
1. s/ti,omap5-scm-conf/ti,omap5-sysc-padconf-global/ because it is more
   appropriate (specific)
2. Add comments, why simple-mfd+syscon has dedicated if:then:

Changes in v2:
1. Complete patch. I accidentally sent only part of it, built on top of
   internal WIP which I forgot to squash.
   I received Ack from Rob, but change is significant, so please kindly
   re-review.
---
 .../devicetree/bindings/mfd/syscon-common.yaml     | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/syscon-common.yaml b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
index 14a08e7bc8bd..2d5eef5add54 100644
--- a/Documentation/devicetree/bindings/mfd/syscon-common.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon-common.yaml
@@ -32,6 +32,7 @@ properties:
   compatible:
     contains:
       const: syscon
+    # Always require a specific compatible for syscon
     minItems: 2
     maxItems: 5  # Should be enough
 
@@ -52,11 +53,44 @@ allOf:
           contains:
             const: simple-mfd
     then:
+      # Always require a specific compatible for syscon with simple-mfd
       properties:
         compatible:
           minItems: 3
           maxItems: 5
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: simple-bus
+    then:
+      # simple-bus conflicts with syscon - if a device is a system controller
+      # with miscellaneous registers, then it has at least one dedicated
+      # function thus it is not a simple bus. Allow existing exceptions.
+      if:
+        properties:
+          compatible:
+            not:
+              contains:
+                # This list CANNOT grow
+                enum:
+                  - cznic,turris1x-cpld
+                  - img,pistachio-cr-periph
+                  - ti,am3352-scm-conf
+                  - ti,am4372-scm-conf
+                  - ti,dm814-scm-conf
+                  - ti,dm8168-scm-conf
+                  - ti,dra7-scm-conf
+                  - ti,omap2-scm-conf
+                  - ti,omap3-scm-conf
+                  - ti,omap4-sysc-padconf-global
+                  - ti,omap5-scm-wkup-conf
+                  - ti,omap5-sysc-padconf-global
+      then:
+        required:
+          - incorrect-usage-of-simple-bus-and-syscon
+
 additionalProperties: true
 
 examples:

-- 
2.53.0



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 13:44:25 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 22:44:25 +0200
Subject: [PATCH v3 2/3] dt-bindings: mfd: syscon: Drop custom select for
 older dtschema
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v3-2-4eba9ec1212a@oss.qualcomm.com>

Older dtschema <2024.02 required custom select to avoid applying this
binding to anything having "syscon" compatible.  That's not the case
anymore and this additional select has two headaches:

1. Duplicates all the compatibles listed in the schema.

2. Is error-prone, because it requires contributor to add the compatible
   in two places, otherwise the schema will be silently ignored.
   The select list already misses mentioning compatibles:
   mediatek,mt8365-infracfg-nao and renesas,r9a08g046-lvds-cmn (with the
   latter being reverted for different reasons).

This requires bumping minimum dtschema requirement to v2024.04, which
feels old enough to be a safe requirement.

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

---

Changes in v3:
1. Bump dtschema requirement

Changes in v2:
1. New patch
---
 Documentation/devicetree/bindings/Makefile        |   2 +-
 Documentation/devicetree/bindings/mfd/syscon.yaml | 116 ----------------------
 2 files changed, 1 insertion(+), 117 deletions(-)

diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile
index 7b668f7fd400..40c2094f47c2 100644
--- a/Documentation/devicetree/bindings/Makefile
+++ b/Documentation/devicetree/bindings/Makefile
@@ -6,7 +6,7 @@ DT_MK_SCHEMA ?= dt-mk-schema
 DT_SCHEMA_LINT = $(shell which yamllint || \
   echo "warning: python package 'yamllint' not installed, skipping" >&2)
 
-DT_SCHEMA_MIN_VERSION = 2023.9
+DT_SCHEMA_MIN_VERSION = 2024.4
 
 PHONY += check_dtschema_version
 check_dtschema_version:
diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index 9c81010d5a74..b70018bf1bcf 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -19,122 +19,6 @@ description: |
 maintainers:
   - Lee Jones <lee at kernel.org>
 
-# Need a select with all compatibles listed for compatibility with older
-# dtschema (<2024.02), so this will not be selected for other schemas having
-# syscon fallback.
-select:
-  properties:
-    compatible:
-      contains:
-        enum:
-          - airoha,en7581-pbus-csr
-          - al,alpine-sysfabric-service
-          - allwinner,sun8i-a83t-system-controller
-          - allwinner,sun8i-h3-system-controller
-          - allwinner,sun8i-v3s-system-controller
-          - allwinner,sun50i-a64-system-controller
-          - altr,l3regs
-          - altr,sdr-ctl
-          - amd,pensando-elba-syscon
-          - amlogic,meson-mx-assist
-          - amlogic,meson-mx-bootrom
-          - amlogic,meson8-analog-top
-          - amlogic,meson8b-analog-top
-          - amlogic,meson8-pmu
-          - amlogic,meson8b-pmu
-          - apm,merlin-poweroff-mailbox
-          - apm,mustang-poweroff-mailbox
-          - apm,xgene-csw
-          - apm,xgene-efuse
-          - apm,xgene-mcb
-          - apm,xgene-rb
-          - apm,xgene-scu
-          - atmel,sama5d2-sfrbu
-          - atmel,sama5d3-nfc-io
-          - atmel,sama5d3-sfrbu
-          - atmel,sama5d4-sfrbu
-          - axis,artpec6-syscon
-          - brcm,cru-clkset
-          - brcm,sr-cdru
-          - brcm,sr-mhb
-          - cirrus,ep7209-syscon1
-          - cirrus,ep7209-syscon2
-          - cirrus,ep7209-syscon3
-          - cnxt,cx92755-uc
-          - econet,en751221-chip-scu
-          - freecom,fsg-cs2-system-controller
-          - fsl,imx93-aonmix-ns-syscfg
-          - fsl,imx93-wakeupmix-syscfg
-          - fsl,ls1088a-reset
-          - fsl,vf610-anatop
-          - fsl,vf610-mscm-cpucfg
-          - hisilicon,dsa-subctrl
-          - hisilicon,hi6220-sramctrl
-          - hisilicon,hip04-ppe
-          - hisilicon,pcie-sas-subctrl
-          - hisilicon,peri-subctrl
-          - hpe,gxp-sysreg
-          - loongson,ls1b-syscon
-          - loongson,ls1c-syscon
-          - lsi,axxia-syscon
-          - marvell,armada-3700-cpu-misc
-          - marvell,armada-3700-nb-pm
-          - marvell,armada-3700-avs
-          - marvell,armada-3700-usb2-host-device-misc
-          - marvell,armada-3700-usb2-host-misc
-          - marvell,dove-global-config
-          - mediatek,mt2701-pctl-a-syscfg
-          - mediatek,mt2712-pctl-a-syscfg
-          - mediatek,mt6397-pctl-pmic-syscfg
-          - mediatek,mt7981-topmisc
-          - mediatek,mt7988-topmisc
-          - mediatek,mt8135-pctl-a-syscfg
-          - mediatek,mt8135-pctl-b-syscfg
-          - mediatek,mt8173-pctl-a-syscfg
-          - mediatek,mt8365-syscfg
-          - microchip,lan966x-cpu-syscon
-          - microchip,mpfs-control-scb
-          - microchip,mpfs-sysreg-scb
-          - microchip,sam9x60-sfr
-          - microchip,sama7d65-ddr3phy
-          - microchip,sama7d65-sfrbu
-          - microchip,sama7g5-ddr3phy
-          - mscc,ocelot-cpu-syscon
-          - mstar,msc313-pmsleep
-          - nuvoton,ma35d1-sys
-          - nuvoton,wpcm450-shm
-          - nxp,s32g2-gpr
-          - nxp,s32g3-gpr
-          - qcom,apq8064-mmss-sfpb
-          - qcom,apq8064-sps-sic
-          - rockchip,px30-qos
-          - rockchip,rk3036-qos
-          - rockchip,rk3066-qos
-          - rockchip,rk3128-qos
-          - rockchip,rk3228-qos
-          - rockchip,rk3288-qos
-          - rockchip,rk3368-qos
-          - rockchip,rk3399-qos
-          - rockchip,rk3528-qos
-          - rockchip,rk3562-qos
-          - rockchip,rk3568-qos
-          - rockchip,rk3576-qos
-          - rockchip,rk3588-qos
-          - rockchip,rv1126-qos
-          - st,spear1340-misc
-          - stericsson,nomadik-pmu
-          - starfive,jh7100-sysmain
-          - ti,am62-opp-efuse-table
-          - ti,am62-usb-phy-ctrl
-          - ti,am625-dss-oldi-io-ctrl
-          - ti,am62p-cpsw-mac-efuse
-          - ti,am654-dss-oldi-io-ctrl
-          - ti,j784s4-acspcie-proxy-ctrl
-          - ti,j784s4-pcie-ctrl
-          - ti,keystone-pllctrl
-  required:
-    - compatible
-
 properties:
   compatible:
     oneOf:

-- 
2.53.0



From krzysztof.kozlowski at oss.qualcomm.com  Mon Jun  8 13:44:26 2026
From: krzysztof.kozlowski at oss.qualcomm.com (Krzysztof Kozlowski)
Date: Mon, 08 Jun 2026 22:44:26 +0200
Subject: [PATCH v3 3/3] ARM: dts: ti: Add specific compatibles for SCM conf
 nodes
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <20260608-n-dt-bindings-simple-bus-syscon-v3-3-4eba9ec1212a@oss.qualcomm.com>

writing-bindings.rst rules dictate that "syscon" must come with a
specific compatible identifying the register layout.  Add specific
compatibles for these devices.

This also allows to solve a different problem: "syscon" is contradictory
to "simple-bus".  A system controller with registers having their own
functions is not really a trivial MMIO simple bus.  These two cannot be
used together, unless listed as an exception.

Reviewed-by: Andreas Kemnade <andreas at kemnade.info>
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

---

Changes in v3:
1. s/ti,omap5-scm-conf/ti,omap5-sysc-padconf-global/ because it is more
   appropriate (specific)
---
 arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi | 2 +-
 arch/arm/boot/dts/ti/omap/am437x-l4.dtsi | 2 +-
 arch/arm/boot/dts/ti/omap/dm814x.dtsi    | 2 +-
 arch/arm/boot/dts/ti/omap/dm816x.dtsi    | 2 +-
 arch/arm/boot/dts/ti/omap/dra7-l4.dtsi   | 2 +-
 arch/arm/boot/dts/ti/omap/omap2430.dtsi  | 2 +-
 arch/arm/boot/dts/ti/omap/omap3.dtsi     | 2 +-
 arch/arm/boot/dts/ti/omap/omap4-l4.dtsi  | 2 +-
 arch/arm/boot/dts/ti/omap/omap5-l4.dtsi  | 6 +++---
 9 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
index 89d16fcc773e..1e09d2b48925 100644
--- a/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am33xx-l4.dtsi
@@ -308,7 +308,7 @@ am33xx_pinmux: pinmux at 800 {
 				};
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,am3352-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
index e08f356e71cb..30fcce33f4b7 100644
--- a/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/am437x-l4.dtsi
@@ -301,7 +301,7 @@ am43xx_pinmux: pinmux at 800 {
 				};
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,am4372-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm814x.dtsi b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
index 27d1f35a31fd..9e02bfa5c3a2 100644
--- a/arch/arm/boot/dts/ti/omap/dm814x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm814x.dtsi
@@ -432,7 +432,7 @@ control: control at 140000 {
 				ranges = <0 0x140000 0x20000>;
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,dm814-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x800>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dm816x.dtsi b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
index a1e0e904e0f0..ee0090f7aa64 100644
--- a/arch/arm/boot/dts/ti/omap/dm816x.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dm816x.dtsi
@@ -100,7 +100,7 @@ dm816x_pinmux: pinmux at 800 {
 
 			/* Device Configuration Registers */
 			scm_conf: syscon at 600 {
-				compatible = "syscon", "simple-bus";
+				compatible = "ti,dm8168-scm-conf", "syscon", "simple-bus";
 				reg = <0x600 0x110>;
 				#address-cells = <1>;
 				#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
index c8d325b0f57b..9df7648c4b79 100644
--- a/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/dra7-l4.dtsi
@@ -64,7 +64,7 @@ scm: scm at 0 {
 				ranges = <0 0 0x2000>;
 
 				scm_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,dra7-scm-conf", "syscon", "simple-bus";
 					reg = <0x0 0x1400>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap2430.dtsi b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
index 222613d2a4d1..01bd471f9223 100644
--- a/arch/arm/boot/dts/ti/omap/omap2430.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap2430.dtsi
@@ -50,7 +50,7 @@ omap2430_pmx: pinmux at 30 {
 				};
 
 				scm_conf: scm_conf at 270 {
-					compatible = "syscon",
+					compatible = "ti,omap2-scm-conf", "syscon",
 						     "simple-bus";
 					reg = <0x270 0x240>;
 					#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap3.dtsi b/arch/arm/boot/dts/ti/omap/omap3.dtsi
index 959069e24730..447736d2e53c 100644
--- a/arch/arm/boot/dts/ti/omap/omap3.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap3.dtsi
@@ -116,7 +116,7 @@ omap3_pmx_core: pinmux at 30 {
 				};
 
 				scm_conf: scm_conf at 270 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,omap3-scm-conf", "syscon", "simple-bus";
 					reg = <0x270 0x330>;
 					#address-cells = <1>;
 					#size-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
index 4c78a0b28fab..c1afc49f456c 100644
--- a/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap4-l4.dtsi
@@ -681,7 +681,7 @@ omap4_pmx_core: pinmux at 40 {
 			};
 
 			omap4_padconf_global: omap4_padconf_global at 5a0 {
-				compatible = "syscon",
+				compatible = "ti,omap4-sysc-padconf-global", "syscon",
 					     "simple-bus";
 				reg = <0x5a0 0x170>;
 				#address-cells = <1>;
diff --git a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
index 915870eb5c99..72849e1c95b0 100644
--- a/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
+++ b/arch/arm/boot/dts/ti/omap/omap5-l4.dtsi
@@ -96,8 +96,7 @@ omap5_pmx_core: pinmux at 40 {
 				};
 
 				omap5_padconf_global: omap5_padconf_global at 5a0 {
-					compatible = "syscon",
-						     "simple-bus";
+					compatible = "ti,omap5-sysc-padconf-global", "syscon", "simple-bus";
 					reg = <0x5a0 0xec>;
 					#address-cells = <1>;
 					#size-cells = <1>;
@@ -2311,7 +2310,8 @@ omap5_scm_wkup_pad_conf: omap5_scm_wkup_pad_conf at da0 {
 				ranges = <0 0 0x60>;
 
 				scm_wkup_pad_conf: scm_conf at 0 {
-					compatible = "syscon", "simple-bus";
+					compatible = "ti,omap5-scm-wkup-conf",
+						     "syscon", "simple-bus";
 					reg = <0x0 0x60>;
 					#address-cells = <1>;
 					#size-cells = <1>;

-- 
2.53.0



From macromorgan at hotmail.com  Mon Jun  8 13:52:38 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 8 Jun 2026 15:52:38 -0500
Subject: [PATCH V10 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <aiL0g8d0Y_JeAC5c@ashevche-desk.local>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
 <20260604201832.60656-4-macroalpha82@gmail.com>
 <aiL0g8d0Y_JeAC5c@ashevche-desk.local>
Message-ID: <PH0PR19MB99733851DADB0671AE5F76B788A51C2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Fri, Jun 05, 2026 at 07:08:35PM +0300, Andy Shevchenko wrote:
> On Thu, Jun 04, 2026 at 03:18:25PM -0500, Chris Morgan wrote:
> 
> > Add the core component of a new inv_icm42607 driver. This includes
> > a few setup functions and the full register definition in the
> > header file.
> 
> ...
> 
> > +#ifndef INV_ICM42607_H_
> > +#define INV_ICM42607_H_
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/bitops.h>
> 
> I haven't found users for these two.
> 
> + bits.h // BIT() / GENMASK()

I'll correct this.

> 
> > +#include <linux/iio/iio.h>
> > +#include <linux/mutex.h>
> > +#include <linux/regmap.h>
> 
> 
> > +#include <linux/regulator/consumer.h>
> 
> No users for this one.
> 
> + types.h // for bool
> 
> ...
> 

And this.

> > +enum inv_icm42607_sensor_mode {
> > +	INV_ICM42607_SENSOR_MODE_OFF,
> > +	INV_ICM42607_SENSOR_MODE_STANDBY,
> > +	INV_ICM42607_SENSOR_MODE_LOW_POWER,
> > +	INV_ICM42607_SENSOR_MODE_LOW_NOISE,
> 
> Are those enums map 1:1 to HW bits or bitfields? If so, assign explicitly each
> of them.

I'll explicitly set every value in the enums to be clear.

> 
> > +	INV_ICM42607_SENSOR_MODE_NB
> 
> Is this a terminator like NUMBER_OF ?

This is a terminator, yes. I will not set these explicitly and keep
commas off of them to keep them easily identifable as terminators.

> 
> > +};
> 
> ...
> 
> > +/* ODR values */
> > +enum inv_icm42607_odr {
> > +	INV_ICM42607_ODR_1600HZ = 5,
> 
> See above. This one is problematic. No one should rely on Linux/C enums when
> it's about HW bits. All HW related stuff has to be explicit.
> 

I will explicitly set the values here.

> > +	INV_ICM42607_ODR_800HZ,
> > +	INV_ICM42607_ODR_400HZ,
> > +	INV_ICM42607_ODR_200HZ,
> > +	INV_ICM42607_ODR_100HZ,
> > +	INV_ICM42607_ODR_50HZ,
> > +	INV_ICM42607_ODR_25HZ,
> > +	INV_ICM42607_ODR_12_5HZ,
> > +	INV_ICM42607_ODR_6_25HZ_LP,
> > +	INV_ICM42607_ODR_3_125HZ_LP,
> > +	INV_ICM42607_ODR_1_5625HZ_LP,
> > +	INV_ICM42607_ODR_NB
> > +};
> 
> ...
> 
> > +struct inv_icm42607_sensor_conf {
> > +	int mode;
> > +	int fs;
> > +	int odr;
> > +	int filter;
> 
> All of them are supposed to be signed? Why?
> 
> > +};
> 

A later commit will use -1 for invalid values.

> ...
> 
> > +struct inv_icm42607_hw {
> > +	uint8_t whoami;
> 
> What's wrong with u8?

Nothing, I'll make the change.

> 
> > +	const char *name;
> > +	const struct inv_icm42607_conf *conf;
> > +};
> 
> ...
> 
> > +#include <linux/delay.h>
> > +#include <linux/dev_printk.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/property.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> 
> IWYU, please.
> 
> ...
> 

This may sound like a dumb question, but what's the best way to invoke
iwyu for a kernel? None of the readmes or man pages seem to be getting
me anywhere...

> > +/**
> > + *  inv_icm42607_setup() - check and setup chip
> > + *  @st:	driver internal state
> > + *  @bus_setup:	callback for setting up bus specific registers
> > + *
> > + *  Returns 0 on success, a negative error code otherwise.
> 
> If you do kernel-doc, validate it. Return section is missing here.
> 

I'll just nuke it, most of the stuff is fairly self explanatory anyway.

> > + */
> 
> ...
> 
> > +{
> > +	const struct device *dev = regmap_get_device(st->map);
> > +	unsigned int val;
> > +	int ret;
> > +
> > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	if (val != st->hw->whoami)
> > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > +			 val, st->hw->whoami, st->hw->name);
> 
> dev_warn_probe() ?
> 
> > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > +	if (ret)
> > +		return ret;
> 
> > +	fsleep(INV_ICM42607_RESET_TIME_MS * 1000);
> 
> USEC_PER_MSEC (needs time.h)

> 
> > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > +				       INV_ICM42607_RESET_TIME_MS * 100,
> > +				       INV_ICM42607_RESET_TIME_MS * 10000);
> 
> These are weird, as in the first case it's actually 1/10th of _RESET_TIME_MS.
> Perhaps you need to reconsider what you use as that constant. Personally I
> prefer to see just plain values with the multipliers (to convert to ?s).
> 

I honestly don't know what a good wait period between polling should
be, so I guessed at 1/10th the timeout period. I will however change
the timeout to us.

> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "reset error, reset done bit not set\n");
> > +
> > +	/* Sync the regcache again after a reset. */
> > +	regcache_mark_dirty(st->map);
> > +	ret = regcache_sync(st->map);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = bus_setup(st);
> 
> Hmm... This is bad name with potential of name collision in the future (in case
> driver bus code wants to have the same name for the function).

Thanks, I'll rename the function.

> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> > +			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> > +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
> > +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return inv_icm42607_set_conf(st, st->hw->conf);
> > +}
> 
> ...
> 
> > +int inv_icm42607_core_probe(struct regmap *regmap,
> > +			    const struct inv_icm42607_hw *hw,
> > +			    inv_icm42607_bus_setup bus_setup)
> > +{
> > +	struct device *dev = regmap_get_device(regmap);
> > +	struct inv_icm42607_state *st;
> > +	int ret;
> > +
> > +	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
> > +	if (!st)
> > +		return -ENOMEM;
> > +
> > +	ret = devm_mutex_init(dev, &st->lock);
> > +	if (ret)
> > +		return ret;
> > +
> > +	st->hw = hw;
> > +	st->map = regmap;
> > +
> > +	ret = iio_read_mount_matrix(dev, &st->orientation);
> > +	if (ret)
> 
> > +		return dev_err_probe(dev, ret,
> > +				     "failed to retrieve mounting matrix %d\n", ret);
> 
> Remove duplicate ret printing.
> 

Understood.

> > +
> > +	ret = devm_regulator_get_enable(dev, "vdd");
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "Failed to get vdd regulator\n");
> > +
> > +	st->vddio_supply = devm_regulator_get(dev, "vddio");
> > +	if (IS_ERR(st->vddio_supply))
> > +		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
> > +				     "Failed to get vddio regulator\n");
> > +
> > +	ret = inv_icm42607_enable_vddio_reg(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
> > +	if (ret)
> > +		return ret;
> 
> > +	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
> > +	ret = inv_icm42607_setup(st, bus_setup);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return 0;
> 
> Just
> 
> 	return inv_icm42607_setup(st, bus_setup);
> 
> ? Or is it going to be extended in the next changes?
> 
> > +}

It will get extended, so I'll keep this for now if that's okay.

> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you for your feedback. And please let me know about the iwyu
tool, that seems like it would be useful.

- Chris


From sebastian.reichel at collabora.com  Mon Jun  8 14:19:54 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Mon, 8 Jun 2026 23:19:54 +0200
Subject: [PATCH V6 2/6] power: supply: sgm41542: Add SG Micro sgm41542
 charger
In-Reply-To: <20260608175521.67449-3-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
 <20260608175521.67449-3-macroalpha82@gmail.com>
Message-ID: <aicv4neDA5Ke0FAB@venus>

Hi,

On Mon, Jun 08, 2026 at 12:55:17PM -0500, Chris Morgan wrote:
> Add support for the SG Micro SGM41542 charger/boost converter.
> Driver was adapted from Rockchip BSP driver [1] and confirmed
> with vendor datasheet [2].
> 
> [1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
> [2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---
>  drivers/power/supply/Kconfig            |    8 +
>  drivers/power/supply/Makefile           |    1 +
>  drivers/power/supply/sgm41542_charger.c | 1057 +++++++++++++++++++++++
>  3 files changed, 1066 insertions(+)
>  create mode 100644 drivers/power/supply/sgm41542_charger.c
> [...]
> +static int sgm4154x_set_recharge_volt_ua(struct sgm4154x_device *sgm, int recharge_volt)
> +{
> +	int reg_val;
> +	int ret;
> +
> +	recharge_volt = recharge_volt / 1000;
> +
> +	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_MV) / SGM4154X_VRECHRG_STEP_MV;

These are the only millivolt offset/steps, so drop the 1000 divison
and simply do:

#define SGM4154X_VRECHRG_OFFSET_UV      100000
#define SGM4154X_VRECHRG_STEP_UV        100000

reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_UV) / SGM4154X_VRECHRG_STEP_UV;

Otherwise LGTM.

> [...]

Greetings,

-- Sebastian
-------------- 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-rockchip/attachments/20260608/771dca22/attachment.sig>

From jakob.unterwurzacher at cherry.de  Tue Jun  9 01:10:41 2026
From: jakob.unterwurzacher at cherry.de (Jakob Unterwurzacher)
Date: Tue, 9 Jun 2026 10:10:41 +0200
Subject: [PATCH] arm64: dts: rockchip: fix emmc reset polarity on
 px30-cobra
In-Reply-To: <3631825.d7IHhHJzqS@phil>
References: <20260512092225.34835-1-jakob.unterwurzacher@cherry.de>
 <3631825.d7IHhHJzqS@phil>
Message-ID: <907fc663-6ccd-4bf7-906c-04f8603a692d@cherry.de>

On 6/2/26 23:08, Heiko Stuebner wrote:
> 
> as Quentin remarked, author (@gmail) and signed-off-by do not match.
> While I'm generally open to fixing things, when it touches the DCO this
> isn't the case.
> 
> So please resend this with the correct author.
> 
> In general "git send-email" will do the correct thing (that From: line),
> when patch author and email-id do not match.

For posterity:

What seems to be happening is that Gmail rewrites the "From: " header on 
the server side. git send-email does now know this, so doesn't add the 
extra "From: " line.

Making the final "From: " explicit in .gitconfig using

[sendemail]
	from = Jakob Unterwurzacher <jakobunt at gmail.com>

now makes git send-email add that extra "From: " line in the email body 
as expected.

I'll resend the patch now.

Thanks, Jakob


From jakobunt at gmail.com  Tue Jun  9 01:17:25 2026
From: jakobunt at gmail.com (Jakob Unterwurzacher)
Date: Tue,  9 Jun 2026 10:17:25 +0200
Subject: [PATCH v2] arm64: dts: rockchip: fix emmc reset polarity on px30-cobra
Message-ID: <20260609081728.30616-2-jakobunt@gmail.com>

From: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>

Technically, the reset signal is active low - it's called RST_n after all.

But it is ignored completely unless RST_n_FUNCTION=1 (byte 162 in extcsd)
is set in the emmc. It is 0 per default.

For emmcs that have RST_n_FUNCTION=1 we failed like this:

	[    3.074480] mmc1: Failed to initialize a non-removable card

With this change they work normally.

Cc: stable at vger.kernel.org
Fixes: bb510ddc9d3e ("arm64: dts: rockchip: add px30-cobra base dtsi and board variants")
Signed-off-by: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>
---
v2: Add correct "From: " line

 arch/arm64/boot/dts/rockchip/px30-cobra.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
index b7e669d8ba4d..90751b04f95c 100644
--- a/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30-cobra.dtsi
@@ -35,7 +35,7 @@ emmc_pwrseq: emmc-pwrseq {
 		compatible = "mmc-pwrseq-emmc";
 		pinctrl-0 = <&emmc_reset>;
 		pinctrl-names = "default";
-		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
 	};
 
 	gpio-leds {
-- 
2.47.3



From simon at symple.nz  Tue Jun  9 01:33:38 2026
From: simon at symple.nz (Simon Wright)
Date: Tue, 9 Jun 2026 20:33:38 +1200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <25a232dca0236788c75231c43ee8a01741148c37.camel@ndufresne.ca>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5797ac61-dc61-4182-ac60-cc377564ff90@collabora.com>
 <2565c949-a558-415f-8c79-e47812db8341@symple.nz>
 <e3b93bda-fed8-4f21-b3d8-cdf28bfaba1c@collabora.com>
 <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
 <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
 <25a232dca0236788c75231c43ee8a01741148c37.camel@ndufresne.ca>
Message-ID: <34662f2d-cdf9-4ce8-a618-12a0f64cd03a@symple.nz>

Hi Nicolas,

(Replying to both your notes.)

On the cleaner implementation:

> on the first frame after resume, we'd prepend the workaround decode
> operation to the TBL [...] cleared on the workaround decode IRQ

That's nicer than what I have. For reference, the warmup here already runs as a
minimal link/CCU submit (its own descriptor + register set on the link bank,
separate from the single-shot decode path), which I currently poll. I tried just
arming the link IRQ on that standalone submit, and it never fires - the warmup
only raises the status register, no interrupt - so it does look like it needs to
ride a real link-table task, as you suggest, to be reaped by IRQ. Happy to test
any version on the RK3576 boards here.

On whether it's really a HW bug:

> we know from past mpp workaround that they don't always imply a HW bug

Fair. I did try to rule out the most likely "masking a simpler issue"
candidate - the filterd RCB (slot 6) data state, per your other note - and it's
content-independent:

- Dumping slot 6 after each decode: its content - including the meaningful
  deblock-context head, not just an uninitialised tail - is non-deterministic
  run to run even across byte-identical good decodes. So there's no stable
  "working" RCB state to compare a bad run against; good and bad runs both span
  unrelated contents with no shared signature.
- Zero-initialising slot 6 before every decode doesn't change the failure rate
  (the allocator already zalloc-zeroes it); a 0xAA sentinel is overwritten by
  the HW rather than read into the output.

So it points to the HW racing on its own deblock-context handling rather than
reading stale buffer data. I couldn't reduce it to a register / RCB / clock /
gating difference vs MPP either, which is what pushed me to the power-up priming. 
I can't claim it isn't masking something deeper, but it isn't the RCB-data case.

Regards,
Simon


From quentin.schulz at cherry.de  Tue Jun  9 02:10:48 2026
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Tue, 9 Jun 2026 11:10:48 +0200
Subject: [PATCH v2] arm64: dts: rockchip: fix emmc reset polarity on
 px30-cobra
In-Reply-To: <20260609081728.30616-2-jakobunt@gmail.com>
References: <20260609081728.30616-2-jakobunt@gmail.com>
Message-ID: <46835bda-c863-4284-90b9-8789031c0bb8@cherry.de>

Hi Jakob,

On 6/9/26 10:17 AM, Jakob Unterwurzacher wrote:
> From: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>
> 
> Technically, the reset signal is active low - it's called RST_n after all.
> 
> But it is ignored completely unless RST_n_FUNCTION=1 (byte 162 in extcsd)
> is set in the emmc. It is 0 per default.
> 
> For emmcs that have RST_n_FUNCTION=1 we failed like this:
> 
> 	[    3.074480] mmc1: Failed to initialize a non-removable card
> 
> With this change they work normally.
> 
> Cc: stable at vger.kernel.org
> Fixes: bb510ddc9d3e ("arm64: dts: rockchip: add px30-cobra base dtsi and board variants")
> Signed-off-by: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>

Please try to not forget to add tags (Reviewed-by, Acked-by, Tested-by, 
...) given in earlier versions of a newer version of the patch (except 
if substantial changes were made, which isn't the case here).

Reviewed-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From piotr.oniszczuk at gmail.com  Tue Jun  9 03:21:01 2026
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Tue, 9 Jun 2026 12:21:01 +0200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
Message-ID: <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>

Simon,

You done fantastic work with nailing this issue!

In fact I suspect this issue is exact long time blocker for all on mine rk3576 users wanting to use 3576 in media player use-case.

I have 3 diff 3576 devices (nanopi-m5, nanopi-r76s and rock4d) and really want to verify are mine h264 hw decoding issues on 3576 caused by issue you discovered.

Have you PoC patch for 7.1 to verify this?



> Wiadomo?? napisana przez Simon Wright <Simon at symple.nz> w dniu 15 maj 2026, o godz. 08:20:
> 
> Hi Detlev,
> 
> I'm seeing systematic pixel corruption on VDPU383 H.264 decodes on RK3576 (NanoPi
> R76S).  The decoded luma plane is correct for rows 0?3 and row 8, but wrong for rows
> 4 and 12 (and the corresponding rows in every subsequent macroblock row).  The error
> propagates to all following P-frames.
> 
> I confirmed the mismatch is in the raw V4L2 CAPTURE buffer two independent ways:
> 
>   1. GStreamer v4l2slh264dec output compared to avdec_h264 with no videoconvert step.
>   2. A hand-written Rust V4L2 decoder that submits only SPS+PPS+SCALING_MATRIX+
>      DECODE_PARAMS (SLICE_PARAMS returns EINVAL on VIDIOC_QUERY_EXT_CTRL on this BSP,
>      so the control set is the same as GStreamer's actual submission) ? identical
>      20.3% mismatch at the identical first-diff byte.  This rules out any GStreamer
>      post-processing or control-submission effect as the cause.
> 
> Hardware:
>   Board:      NanoPi R76S (RK3576, VDPU383)
>   Kernel:     Linux 7.0.1 (mainline rkvdec-vdpu383-h264.c, unmodified)
>   GStreamer:  1.28.2 (with v4l2slh264dec from gst-plugins-bad)
>   Content:    1920?1080 Baseline H.264, SMPTE colour bars, openh264enc
> 
> 
> MINIMAL REPRODUCER
> ------------------
> 
> Generate a test file (any H.264 Annex-B with visible content works; I used openh264enc
> with SMPTE bars):
> 
>   gst-launch-1.0 videotestsrc num-buffers=60 pattern=smpte \
>     ! video/x-raw,width=1920,height=1080,framerate=30/1 \
>     ! openh264enc ! h264parse ! filesink location=test.h264
> 
> Decode via HW, capture raw NV12:
> 
>   gst-launch-1.0 filesrc location=test.h264 num-buffers=60 \
>     ! h264parse ! v4l2slh264dec ! 'video/x-raw' \
>     ! filesink location=hw.raw
> 
> Decode via SW, capture raw NV12:
> 
>   gst-launch-1.0 filesrc location=test.h264 num-buffers=60 \
>     ! h264parse ! avdec_h264 ! videoconvert ! 'video/x-raw,format=NV12' \
>     ! filesink location=sw.raw
> 
> For a 1920?1080 NV12 frame (frame 0), compare the first 3,110,400 bytes:
> 
>   cmp hw.raw sw.raw
> 
> Expected: identical.
> Observed: first mismatch at byte 7680 (Y plane, row=4, col=0).
> 
> With SMPTE bars (white region at the top), SW Y[row=3] = 0xe9 (correct white-bar luma).
> HW Y[row=4] = 0xaf instead of 0xe9; HW Y[row=3] = 0xe9 (correct).
> Overall mismatch rate: 20.3% of bytes in frame 0.
> 
> 
> QUANTIFIED EVIDENCE (frame 0, IDR)
> -----------------------------------
> 
>   SW decode:  Y bytes [7680..7695] = e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9 e9
>   HW decode:  Y bytes [7680..7695] = af af af af af af af af af af af af af af af af
>   First diff: byte 7680 ? Y plane row=4, col=0
> 
> Error propagation:
>   Frame 0 (IDR):  20.3% mismatch, first_diff = byte 7680 (Y row=4)
>   Frame 1 (P):    23.0% mismatch, first_diff = byte 253 (error propagated to row=0)
>   Frames 5?30 (P): 25?26% mismatch, stable
> 
> ANALYSIS
> --------
> 
> A diagnostic experiment implicates the filterd_rcb buffer (RCB index 6).  Redirecting
> filterd_rcb buffers 6, 7, 8 to point at the output buffer produced 98.4% corruption
> with first diff at row=1, which indicates the hardware reads p-side pixel context from
> filterd_rcb (rather than from the reconstruction buffer) when applying horizontal
> deblocking.
> 
> Based on the error pattern, our hypothesis is that filterd_rcb uses an 8-row circular
> index (slot = row mod 8).  If so, H.264's 4-row deblocking boundaries within each
> 16-row macroblock row would cause a slot collision that HEVC (with 8-row CTU boundaries)
> does not encounter:
> 
>   Edge y=4:  p0 from row 3  ? slot 3  (zero-initialised on IDR ? wrong)
>   Edge y=8:  p0 from row 7  ? slot 7  (written before this edge is reached ? correct)
>   Edge y=12: p0 from row 11 ? slot 3  (still holds row-3 data from the y=4 pass ? wrong)
> 
> This would explain why y=8 decodes correctly while y=4 and y=12 do not.  We don't have
> hardware documentation for VDPU383, so we can't confirm whether this is the actual
> mechanism.
> 
> We tried several register adjustments hoping to change the filterd_rcb update granularity:
> ctu_align_wr_en (reg027), buf_empty_en (reg009), ref strides (reg083?106), and
> num_views in the SPS table.  None changed the corruption.
> 
> Is there a known configuration difference for H.264's narrower deblocking edges, or a
> BSP-level fix we've missed?
> 
> 
> ATTACHED REPRODUCER
> -------------------
> 
> The C program below (builds against GStreamer on-device, ~100 lines) automates the
> comparison and produces per-frame mismatch statistics:
> 
>   gcc -O0 -g -o h264_hw_vs_sw_dump h264_hw_vs_sw_dump.c \
>       $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-video-1.0 gstreamer-app-1.0)
> 
>   ./h264_hw_vs_sw_dump /path/to/test.h264
> 
> --- BEGIN h264_hw_vs_sw_dump.c ---
> /*
>  * H.264 HW vs SW byte-level comparison via GStreamer appsink.
>  *
>  * Decodes one frame of an H.264 Annex-B file via two paths:
>  *   SW:  h264parse ! avdec_h264 ! videoconvert ! NV12 appsink
>  *   HW:  h264parse ! v4l2slh264dec             ! NV12 appsink
>  *
>  * Reports first divergent byte, mismatch percentage, and unique Y values for
>  * both decoders.  If HW bytes differ from SW bytes, the bug is in the kernel
>  * rkvdec-vdpu383-h264.c driver.
>  *
>  * Build on device:
>  *   gcc -O0 -g -o h264_hw_vs_sw_dump h264_hw_vs_sw_dump.c \
>  *       $(pkg-config --cflags --libs gstreamer-1.0 gstreamer-video-1.0 gstreamer-app-1.0)
>  */
> 
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <stdint.h>
> #include <unistd.h>
> #include <gst/gst.h>
> #include <gst/video/video.h>
> #include <gst/app/gstappsink.h>
> 
> typedef struct {
>     uint8_t *data;
>     int      width, height;
>     size_t   y_size, uv_size, total;
> } DecodedFrame;
> 
> static void free_frame(DecodedFrame *f) { if (f) { free(f->data); f->data = NULL; } }
> 
> static DecodedFrame *run_pipeline(const char *pipeline_str, const char *label)
> {
>     fprintf(stderr, "[%s] pipeline: %s\n", label, pipeline_str);
>     GError *err = NULL;
>     GstElement *pipeline = gst_parse_launch(pipeline_str, &err);
>     if (!pipeline || err) {
>         fprintf(stderr, "[%s] gst_parse_launch: %s\n", label, err ? err->message : "unknown");
>         return NULL;
>     }
>     GstElement *sink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");
>     gst_app_sink_set_emit_signals(GST_APP_SINK(sink), FALSE);
>     gst_app_sink_set_drop(GST_APP_SINK(sink), FALSE);
>     gst_app_sink_set_max_buffers(GST_APP_SINK(sink), 1);
>     gst_element_set_state(pipeline, GST_STATE_PLAYING);
> 
>     GstSample *sample = gst_app_sink_pull_sample(GST_APP_SINK(sink));
>     if (!sample) {
>         fprintf(stderr, "[%s] no sample\n", label);
>         gst_element_set_state(pipeline, GST_STATE_NULL);
>         gst_object_unref(sink); gst_object_unref(pipeline);
>         return NULL;
>     }
>     GstBuffer *buf  = gst_sample_get_buffer(sample);
>     GstCaps   *caps = gst_sample_get_caps(sample);
>     GstVideoInfo vinfo;
>     gst_video_info_from_caps(&vinfo, caps);
> 
>     int w = GST_VIDEO_INFO_WIDTH(&vinfo);
>     int h = GST_VIDEO_INFO_HEIGHT(&vinfo);
>     GstVideoFrame vframe;
>     gst_video_frame_map(&vframe, &vinfo, buf, GST_MAP_READ);
> 
>     size_t y_size  = (size_t)w * h;
>     size_t uv_size = (size_t)w * (h / 2);
>     DecodedFrame *frame = calloc(1, sizeof(*frame));
>     frame->data  = malloc(y_size + uv_size);
>     frame->width = w; frame->height = h;
>     frame->y_size = y_size; frame->uv_size = uv_size;
>     frame->total = y_size + uv_size;
> 
>     uint8_t *y_src = GST_VIDEO_FRAME_PLANE_DATA(&vframe, 0);
>     int y_stride   = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, 0);
>     for (int row = 0; row < h; row++)
>         memcpy(frame->data + row * w, y_src + row * y_stride, w);
> 
>     uint8_t *uv_src = GST_VIDEO_FRAME_PLANE_DATA(&vframe, 1);
>     int uv_stride   = GST_VIDEO_FRAME_PLANE_STRIDE(&vframe, 1);
>     uint8_t *uv_dst = frame->data + y_size;
>     for (int row = 0; row < h / 2; row++)
>         memcpy(uv_dst + row * w, uv_src + row * uv_stride, w);
> 
>     gst_video_frame_unmap(&vframe);
>     gst_sample_unref(sample);
>     gst_element_set_state(pipeline, GST_STATE_NULL);
>     gst_object_unref(sink); gst_object_unref(pipeline);
>     return frame;
> }
> 
> static void compare_frames(DecodedFrame *sw, DecodedFrame *hw)
> {
>     size_t n = sw->total < hw->total ? sw->total : hw->total;
>     size_t first_diff = (size_t)-1, diffs = 0;
>     for (size_t i = 0; i < n; i++) {
>         if (sw->data[i] != hw->data[i]) {
>             if (first_diff == (size_t)-1) first_diff = i;
>             diffs++;
>         }
>     }
>     if (!diffs) {
>         fprintf(stderr, "MATCH: HW == SW (%zu bytes)\n", n);
>         return;
>     }
>     size_t y_size  = (size_t)sw->width * sw->height;
>     const char *plane = first_diff < y_size ? "Y" : "UV";
>     size_t off = first_diff < y_size ? first_diff : first_diff - y_size;
>     fprintf(stderr, "MISMATCH: %zu/%zu bytes differ (%.1f%%)\n", diffs, n, 100.0*diffs/n);
>     fprintf(stderr, "  First diff: byte %zu -> %s plane offset %zu (row=%zu col=%zu)\n",
>             first_diff, plane, off, off / sw->width, off % sw->width);
>     fprintf(stderr, "  SW[%zu..]: ", first_diff);
>     for (size_t i = first_diff; i < first_diff+16 && i < n; i++)
>         fprintf(stderr, "%02x ", sw->data[i]);
>     fprintf(stderr, "\n  HW[%zu..]: ", first_diff);
>     for (size_t i = first_diff; i < first_diff+16 && i < n; i++)
>         fprintf(stderr, "%02x ", hw->data[i]);
>     fprintf(stderr, "\n");
> }
> 
> int main(int argc, char **argv)
> {
>     if (argc < 2) { fprintf(stderr, "Usage: %s <h264_annex_b>\n", argv[0]); return 1; }
>     gst_init(NULL, NULL);
>     char sw_pipe[1024], hw_pipe[1024];
>     snprintf(sw_pipe, sizeof(sw_pipe),
>         "filesrc location=%s ! h264parse ! avdec_h264 ! videoconvert ! "
>         "video/x-raw,format=NV12 ! appsink name=sink", argv[1]);
>     snprintf(hw_pipe, sizeof(hw_pipe),
>         "filesrc location=%s ! h264parse ! v4l2slh264dec ! "
>         "video/x-raw,format=NV12 ! appsink name=sink", argv[1]);
> 
>     DecodedFrame *sw = run_pipeline(sw_pipe, "SW");
>     DecodedFrame *hw = run_pipeline(hw_pipe, "HW");
>     if (sw && hw) compare_frames(sw, hw);
>     if (sw) { free_frame(sw); free(sw); }
>     if (hw) { free_frame(hw); free(hw); }
>     return 0;
> }
> --- END h264_hw_vs_sw_dump.c ---
> 
> Thanks,
> Simon Wright
> Symple Solutions, Dunedin, New Zealand
> 
> 



From midgy971 at gmail.com  Tue Jun  9 04:11:07 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Tue, 9 Jun 2026 13:11:07 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com> <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com> <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
Message-ID: <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>

Hello Chaoyi,

You were right - building rocket as a module fixes it. Thanks for the pointer.

I rebuilt with CONFIG_DRM_ACCEL_ROCKET=m (everything else the same:
need_regulator on
the RK3568 NPU power domain via a DOMAIN_M_R variant, domain-supply =
<&vdd_npu>, and the
regulator-always-on workaround dropped). The board now boots cleanly
and, more importantly,
an NPU job submit no longer hangs: I ran the test workload five times
with no RCU stall and
no freeze.

So with rocket=m the need_regulator approach works on RK3568, and I'll
keep it for v4
(domain-supply + need_regulator, instead of marking vdd_npu
always-on). rocket=m is the
normal configuration anyway; my earlier hang came from building it =y
in a self-contained
image, so it probed in the initcalls (around 2 s) and the genpd ->
I2C-PMIC regulator
transition ran before the system was ready. As a module it loads from
udev much later
(~6.8 s here), after the I2C controller and regulator core are fully up.

On your question of when the device-link error is printed - it is at
power-domain
controller probe, not at the rocket probe:

  [    2.700618] vdd_npu: Bringing 500000uV into 825000-825000uV
  [    2.749637] rockchip-pm-domain fdd90000.power-management:power-controller:
                 Failed to create device link (0x180) with supplier 0-0020 for
                 /power-management at fdd90000/power-controller/power-domain at 6
  [    2.945955] platform fde40000.npu: Adding to iommu group 3
  ...
  [    6.840374] rocket: loading out-of-tree module taints kernel.
  [    6.877647] [drm] Initialized rocket 0.0.0 for rknn on minor 0
  [    6.879950] rocket fde40000.npu: Rockchip NPU core 0 version: 0

So the device-link to the rk809 PMIC (0-0020) fails to form at ~2.75
s, well before rocket
loads at ~6.8 s. It is non-fatal here - the vdd_npu rail is brought up
by the regulator core
and all jobs run - and there is no "failed to get ack on domain npu"
NoC warning this boot
(the always-on kernel had one). The complete boot log is attached.

Two notes / one question:
- This boot used fw_devlink=permissive on the command line. Is the
"Failed to create device
  link ... supplier 0-0020" at pmdomain probe expected/benign, or is
there a clean way to make
  it order correctly (so it also works without permissive, and a =y
build wouldn't deadlock in
  the initcalls)?
- (The convolution output is still uniform zero-point / the job times
out - that is the
  separate NPU compute-completion issue, unrelated to the power-domain
work. Finley, that is
  the one I flagged earlier re PVTPLL/NoC.)

Kind regards,
Midgy

Le lun. 8 juin 2026 ? 11:38, Chaoyi Chen <chaoyi.chen at rock-chips.com> a ?crit :
>
> Hi Midgy,
>
> On 6/8/2026 5:14 PM, Midgy Balon wrote:
> > Hello Chaoyi,
> >
> > Following up on the need_regulator suggestion -- I implemented and
> > tested it on the
> > board, and unfortunately it doesn't avoid the deadlock on RK3568; it
> > moves it from
> > boot to the NPU job submit.
> >
> > What I did: gave the RK3568 NPU power domain a regulator (a DOMAIN_M_R
> > variant with
> > need_regulator = true), wired domain-supply = <&vdd_npu>, and dropped the
> > regulator-always-on workaround.
> >
> > Boot is now clean and the NPU probes, but there is a warning during boot:
> >
> >   rockchip-pm-domain ...: Failed to create device link (0x180) with supplier
> >   0-0020 for .../power-domain at 6
> >
> > (0-0020 is the rk809 PMIC that supplies vdd_npu.) Then on the first NPU job
> > submit the board hard-hangs with an RCU stall:
> >
> >   rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
> >   rcu:     3-...!: (1 GPs behind) ...
> >   rcu: rcu_preempt kthread starved for 5115 jiffies! ... RCU_GP_WAIT_FQS(5)
> >   rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected
> >
> > My reading: vdd_npu is on the rk809 *I2C* PMIC, so when genpd
> > enables/disables the
> > regulator during the NPU's runtime-PM power transition, the I2C
> > transfer runs in a
> > context that starves RCU and the box freezes. (I suspect
> > need_regulator is fine on
> > the RK3588 NPU because its supply isn't behind an I2C PMIC.) The always-on
> > workaround avoids this precisely because genpd never touches the I2C
> > regulator in
> > that path.
> >
>
> No, they are all controlled by RK809.
>
> And This looks werid. Is your rocket driver compiled as a module?
> Please try compiling it as a module. When is the above error printed?
> Please provide the complete boot log.
>
> > So: for an NPU domain whose supply is an I2C PMIC, is there a
> > supported way to let
> > genpd own the regulator without performing the I2C op in the
> > power-transition path
> > (a deferred/async regulator enable, or a flag), or should RK3568 keep vdd_npu as
> > regulator-always-on? For v4 I'll keep always-on unless there's a cleaner path.
> >
>
> --
> Best,
> Chaoyi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 2026-06-09_rocket-m-needreg.log
Type: text/x-log
Size: 70113 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20260609/554e3e6d/attachment-0001.bin>

From bartosz.golaszewski at oss.qualcomm.com  Tue Jun  9 04:24:43 2026
From: bartosz.golaszewski at oss.qualcomm.com (Bartosz Golaszewski)
Date: Tue,  9 Jun 2026 13:24:43 +0200
Subject: (subset) [PATCH 0/3] gpio: rockchip: Fix generic IRQ chip leak and modernize resource mapping
In-Reply-To: <20260607230504.35392-1-scardracs@disroot.org>
References: <20260607230504.35392-1-scardracs@disroot.org>
Message-ID: <178100427596.130110.2423070495677836224.b4-ty@oss.qualcomm.com>


On Mon, 08 Jun 2026 01:05:01 +0200, Marco Scardovi wrote:
> This series fixes a generic IRQ chip leak in the gpio-rockchip driver
> and performs two small cleanups to use standard platform device helper APIs.
> 
> Patch 1 fixes a leak caused by generic IRQ chips not being removed before
> IRQ domain teardown.
> 
> Patch 2 converts register mapping to use devm_platform_ioremap_resource().
> 
> [...]

Applied, thanks!

[1/3] gpio: rockchip: fix generic IRQ chip leak on remove
      https://git.kernel.org/brgl/c/1c1e0fc88d6ef65bf15d517853251f75ab9d18c3

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski at oss.qualcomm.com>


From nicolas at ndufresne.ca  Tue Jun  9 05:31:15 2026
From: nicolas at ndufresne.ca (Nicolas Dufresne)
Date: Tue, 09 Jun 2026 08:31:15 -0400
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal
 de-blocking edges y=4 and y=12
In-Reply-To: <34662f2d-cdf9-4ce8-a618-12a0f64cd03a@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
	 <5797ac61-dc61-4182-ac60-cc377564ff90@collabora.com>
	 <2565c949-a558-415f-8c79-e47812db8341@symple.nz>
	 <e3b93bda-fed8-4f21-b3d8-cdf28bfaba1c@collabora.com>
	 <4358f22d-247c-43d3-89d4-27b57bbe90aa@symple.nz>
	 <66768711-6943-43f5-95fa-3d97dc638844@symple.nz>
	 <25a232dca0236788c75231c43ee8a01741148c37.camel@ndufresne.ca>
	 <34662f2d-cdf9-4ce8-a618-12a0f64cd03a@symple.nz>
Message-ID: <169bb3cb1d7e940c43916178cf5cb6dab2993fb4.camel@ndufresne.ca>

Hi,

Le mardi 09 juin 2026 ? 20:33 +1200, Simon Wright a ?crit?:
> So it points to the HW racing on its own deblock-context handling rather than
> reading stale buffer data. I couldn't reduce it to a register / RCB / clock /
> gating difference vs MPP either, which is what pushed me to the power-up priming. 
> I can't claim it isn't masking something deeper, but it isn't the RCB-data case.

thanks for the feedback, and yes, sounds like a workaround is the way forward
for the time being (or forever).

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-rockchip/attachments/20260609/f5a6837d/attachment.sig>

From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:49 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:49 +0200
Subject: [PATCH v17 02/28] drm/display: hdmi-state-helper: Use default case
 for unsupported formats
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-2-35739b5782cc@collabora.com>

Switch statements that do not handle all possible values of an
enumeration will generate a warning during compilation. In preparation
for adding a COUNT value to the end of the enum, this needs to be dealt
with.

Add a default case to sink_supports_format_bpc's DRM_OUTPUT_COLOR_FORMAT
switch statement, and move the log-and-return unknown pixel format
handling into it.

No functional change.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index a331ebdd65af..c68b159f0a7f 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -542,10 +542,11 @@ sink_supports_format_bpc(const struct drm_connector *connector,
 		drm_dbg_kms(dev, "YUV444 format supported in that configuration.\n");
 
 		return true;
-	}
 
-	drm_dbg_kms(dev, "Unsupported pixel format.\n");
-	return false;
+	default:
+		drm_dbg_kms(dev, "Unsupported pixel format.\n");
+		return false;
+	}
 }
 
 static enum drm_mode_status

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:48 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:48 +0200
Subject: [PATCH v17 01/28] drm/amd/display: Remove unnecessary
 SIGNAL_TYPE_HDMI_TYPE_A check
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-1-35739b5782cc@collabora.com>

From: Werner Sembach <wse at tuxedocomputers.com>

Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check that was performed in the
drm_mode_is_420_only() case, but not in the drm_mode_is_420_also() &&
force_yuv420_output case.

Without further knowledge if YCbCr 4:2:0 is supported outside of HDMI,
there is no reason to use RGB when the display
reports drm_mode_is_420_only() even on a non HDMI connection.

This patch also moves both checks in the same if-case. This  eliminates an
extra else-if-case.

Signed-off-by: Werner Sembach <wse at tuxedocomputers.com>
Signed-off-by: Andri Yngvason <andri at yngvason.is>
Tested-by: Andri Yngvason <andri at yngvason.is>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index ba7f98a87808..dfe97897127c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6917,12 +6917,9 @@ static void fill_stream_properties_from_drm_display_mode(
 	timing_out->v_border_top = 0;
 	timing_out->v_border_bottom = 0;
 	/* TODO: un-hardcode */
-	if (drm_mode_is_420_only(info, mode_in)
-			&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
-		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
-	else if (drm_mode_is_420_also(info, mode_in)
-			&& aconnector
-			&& aconnector->force_yuv420_output)
+	if (drm_mode_is_420_only(info, mode_in) ||
+	    (aconnector && aconnector->force_yuv420_output &&
+	     drm_mode_is_420_also(info, mode_in)))
 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
 	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
 			&& aconnector

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:47 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:47 +0200
Subject: [PATCH v17 00/28] Add new general DRM property "color format"
Message-ID: <20260609-color-format-v17-0-35739b5782cc@collabora.com>

Hello,

this is a follow-up to
https://lore.kernel.org/all/20250911130739.4936-1-marius.vlad at collabora.com/
which in of itself is a follow-up to
https://lore.kernel.org/dri-devel/20240115160554.720247-1-andri at yngvason.is/ where
a new DRM connector property has been added allowing users to
force a particular color format.

That in turn was actually also a follow-up from Werner Sembach's posted at
https://lore.kernel.org/dri-devel/20210630151018.330354-1-wse at tuxedocomputers.com/

As the number of cooks have reached critical mass, I'm hoping I'll be
the last person to touch this particular series.

We have an implementation in Weston at
https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/1825 that
adds support for this property. This patch series has been tested
against that MR on i915 (HDMI, DP), amdgpu (HDMI, DP) and on rockchip
(HDMI).

You can also manually test this with modetest like so, but beware that
this is a non-atomic invocation, so testing YUV420 like this will result
in weird outcomes if only some of the modes support YUV420:

  $ modetest -s 115:1920x1080-60 at NV12 -w 115:'color format':4

where 115 is the connector ID and '4' is the enum value for a particular
color format.

General notes on the approach taken by me: instead of silently switching
to a different format than was explicitly requested, or even worse,
outputting something to the sink the sink doesn't support, bubble up an
error to userspace instead. "color format" is a "I want this" type
property, not a "force this" type property, i.e. the kernel will respect
the limits imposed by the hardware.

Things I've tested:
- HDMI (YCbCr 4:4:4 + YCbCr 4:2:2 (8-bit) + RGB + Auto) on RK3588
- HDMI (YCbCr 4:4:4 + YCbCr 4:2:2 (8-bit) + RGB + Auto) on RK3576
- HDMI (YCbCr 4:4:4, YCbCr 4:2:0, RGB, Auto) + DP (YCbCr 4:4:4, RGB,
  Auto) on Intel N97 (i915).
- HDMI (YCbCr 4:4:4, YCbCr 4:2:2, YCbCr 4:2:0, RGB, Auto) + DP (YCbCr
  4:4:4, RGB, Auto) on an AMD Radeon RX 550 (amdgpu).

Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
Changes in v17:
- Rebase onto drm-misc-next
- Reorder i915 patches to end of series
- Link to v16: https://patch.msgid.link/20260523-color-format-v16-0-24340c5e4732 at collabora.com

Changes in v16:
- drm/i915/dp: Don't check for dfp conversion to determine ycbcr444
  output capability
- drm/i915/dp: Replicate intel_dp_has_hdmi_sink check for YCBCR444 as well
- drm/i915/dp: Reorder formats and checks in sink_format_valid
- drm/i915/hdmi: Fix inverted HAS_GMCH check for YCBCR444 capability
- drm/i915/hdmi: Add has_hdmi_sink check to YCBCR444 sink_format_valid
- drm/i915/hdmi: Reorder formats in sink_format_valid
- drm/i915/hdmi: Drop documentation for internal function
- Link to v15: https://patch.msgid.link/20260522-color-format-v15-0-21fb136c9df2 at collabora.com

Changes in v15:
- Drop redundant drm_connector_color_format_valid() function
- dw-hdmi-qp-rockchip: make dw_hdmi_qp_rockchip_get_vop_format()'s
  return type int, check bstate for IS_ERR rather than NULL, and pass up
  error codes to caller
- rebase onto recent drm-tip, necessitating
  s/drm_atomic_state/drm_atomic_commit/ in the KUnit tests
- Link to v14: https://patch.msgid.link/20260423-color-format-v14-0-449a419ccbd4 at collabora.com

Changes in v14:
- i915: Check for source support of YCbCr444 in both the sink format
  validation and when registering the properites on the connectors.
- i915: Split HDMI and DP implementations into separate patches, with
  their own supported color formats masks.
- Link to v13: https://patch.msgid.link/20260413-color-format-v13-0-ab37d4dfba48 at collabora.com

Changes in v13:
- Introduce a new drm_connector_funcs member that returns the
  connector state's color format with additional bells and whistles.
- Implement this new func in drm_bridge_connector to return whatever the
  HDMI implementation did if an HDMI bridge is present.
- Call into the drm_connector.h function wrapping this new func in the
  recursive bridge chain bus format selection code.
- Link to v12: https://patch.msgid.link/20260409-color-format-v12-0-ce84e1817a27 at collabora.com

Changes in v12:
- Rebase on top of Ville's i915 format selection cleanup series
- i915: Reimplement based on new format selection code. Drop the DP-MST
  implementation, as sinks with different sets of supported formats
  complicate the matter.
- Adjust documentation on drm_connector_color_format enum values to
  mention quantization ranges.
- Add documentation to drm-kms page to document the string values for
  the property. Mostly the same documentation as the enum values, but
  from a more userspace-centric perspective. This is done in the patch
  that introduces the property, but I didn't drop the existing R-b as
  it isn't a functional change.
- Update documentation of "colorspace" property to mention that "color
  format" property controls the output format.
- amdgpu: Remove property from DP-MST, as it's unclear whether it'd work
  properly with sinks that have different sets of supported formats
- Link to v11: https://patch.msgid.link/20260324-color-format-v11-0-605559af4fb4 at collabora.com

Changes in v11:
- amdgpu: fix property registration on DP-MST
- i915: fix property registration on DP-MST
- rebase on drm-tip, which includes Maxime's refactor series that was
  previously declared a dependency of this series
- Link to v10: https://lore.kernel.org/r/20260305-color-format-v10-0-a58c68a11868 at collabora.com

Changes in v10:
- Make DRM_OUTPUT_COLOR_FORMAT_COUNT and
  DRM_CONNECTOR_COLOR_FORMAT_COUNT part of the enum definition (thanks
  to Maxime)
- Preemptively avoid the warning that would be generated by the
  enumification of DRM_OUTPUT_COLOR_FORMAT_COUNT by modifying the
  problematic switch statement in drm_hdmi_state_helper's
  sink_supports_format_bpc.
- drm/bridge: Change HDMI check from checking for the last bridge having
  a DRM_BRIDGE_OP_HDMI in ops to checking if last_bridge->type is HDMIA.
  This is not quite the suggestion Dmitry had, but according to the
  documentation of the drm_bridge.type member, and the
  display-connector.c code, it should be correct.
- Combine drm_mode_create_color_format_property and
  drm_connector_attach_color_format_property into one function named the
  latter. (thanks to Dmitry Baryshkov)
- Change author of 'drm: Add new general DRM property "color format"'
  to myself as it has by now changed quite a bit, and add Andri and
  Werner as Co-developed-by, as per Andri's suggestion.
- hdmi-state-helper: Rework hdmi_compute_config to make code flow more
  obvious, and drop Dmitry's R-b as a consequence (thanks to Maxime)
- Move dw-hdmi-qp's atomic_get_output_bus_fmts into
  drm_bridge_helper.c, along with kernel doc string (thanks to Dmitry)
- Future-proof the aforementioned get_output_bus_fmts use of hweight8 on
  the supported_formats bitmask with a BUILD_BUG_ON.
- Add a KUnit test for the HDMI output bus formats helper
- Link to v9: https://lore.kernel.org/r/20260227-color-format-v9-0-658c3b9db7ef at collabora.com

Changes in v9:
- Document what the "AUTO" behaviour is in the color format enum (thanks
  to Maxime)
- drm/bridge: dw-hdmi-qp: Fix a rebase oopsie that reintroduced some
  functions that were dropped. (thanks to Cristian)
- drm/bridge: Shuffle "1:1" in the bridge fmt selection docs to earlier
  in the sentence. (thanks to Randy Dunlap)
- i915: Check chosen output format against requested format for dp-mst
- All color format driver implementations: rebase and rework on top of
  Maxime's series
- As part of this rework, rename drm_color_format_enum to
  drm_connector_color_format
- drm kunit tests: rework for the new enums. Changes were trivial, so
  trailers were kept
- Link to v8: https://lore.kernel.org/r/20260216-color-format-v8-0-5722ce175dd5 at collabora.com

Changes in v8:
- Drop "drm/rockchip: vop2: Fix YUV444 output", as the original problem
  could not be reproduced anymore, and the justification did not make
  sense.
- Remove the 12-bit format from "drm/rockchip: vop2: Recognise 10/12-bit
  YUV422 as YUV formats".
- Refactor to keep the original DRM_COLOR_FORMAT bitshifted defines
  as-is, but introduce a new drm_color_format_enum enum.
- Adjust conversion functions for the newly refactored enum, ensuring
  they only return valid enum values, and only convert in directions
  that open up no error value cans of worms.
- Rework the property uapi code for the newly refactored enum, since
  it no longer needs to do any bitshifting or ffs().
- Rework all the device drivers for the new enum.
- Rework all the tests for the refactored enum.
- Rework the hdmi state helper for the new enum, and also make it more
  explicit about the auto behaviour by not relying on a conversion
  function to map AUTO to RGB, but do this in the framework itself.
- rockchip dw_hdmi_qp: Fix the GRF value to check for color >= 0 instead
  of color > 0, as the latter broke switching back to RGB.
- Rebase onto a recent drm-tip. This necessitated blindly reworking some
  of the i915 dp-mst code.
- Drop the __maybe_unused edid test patch, as I could no longer
  reproduce the build warnings I added it for. I blame ghosts.
- drm_bridge tests: remove "destroyed" member from struct
  drm_bridge_chain_priv and all associated code, as it was not used in
  any test.
- Link to v7: https://lore.kernel.org/r/20260121-color-format-v7-0-ef790dae780c at collabora.com

Changes in v7:
- Fix drm_bridge kunit test build failure caused by rebasing across an
  API change.
- Make compilers shut up about unused EDID definitions in the test
  suites.
- Empty line checkpatch fixes that b4 prep --check didn't catch.
- Link to v6: https://lore.kernel.org/r/20260121-color-format-v6-0-7b81a771cd0b at collabora.com

Changes in v6:
- Checkpatch fixes
- Add drm_bridge.c kerneldoc fix patch to b4 deps so the kernel docs
  required for every contribution to the subsystem can be built
- dw-hdmi-qp core has gained the atomic_get_output_bus_fmts bridge func,
  which allows it to participate in the drm_bridge chain recursive format
  selection code properly.
- The Rockchip dw-hdmi-qp integration now no longer reimplements the
  color format logic (improperly), but reads the bus format of the first
  bridge as set by the recursive bridge format selection. If the input
  format is FIXED, it'll use the output format. Otherwise, the input
  format is used.
- In the synopsys drivers, YUV422 uses the same bus format as the non-qp
  hdmi encoder driver. Probably correcter this way. The Rockchip vop2
  is_yuv function has been extended to recognise this format as well.
- KUnit tests for drm_bridge chains are now included, which exercise the
  chain's recursive bus format selection.
- On HDMI connectors, the drm_bridge bus format selection will try to target
  the color format that the HDMI layer came up with. This means the AUTO
  logic is not duplicated for HDMI connectors.
- The enum conversion function commit gained a function for converting
  from hdmi_colorspace to drm_color_format, and its author changed as no
  original code remains anyway. Marius is still included as a
  Co-developer.
- Some tests for the HDMI state helper's mode_valid have been written.
  They are incomplete as we lack a test EDID for a 420-also mode that
  would violate the clock constraints on RGB. I hacked one together with
  a hex editor, but it reports a too high of a clock rate, and there's
  no EDID editor I could find which supports these extension blocks.
- The color_format KUnit tests have been more heavily parameterised, the
  auto case absorbed into other tests, and the comments around them
  rewritten.
- Add a few paragraphs of documentation that explain the bridge format
  selection, and how to make use of it in a display driver.
- Link to v5: https://lore.kernel.org/r/20251128-color-format-v5-0-63e82f1db1e1 at collabora.com

Changes in v5:
- Rebase onto drm-tip
- Drop DRM_MODE_COLOR_FORMAT_* as an enum
- Unify DRM_COLOR_FORMAT_NONE and DRM_COLOR_FORMAT_AUTO, with AUTO being
  0. This makes conversion and general logic much easier.
- Adjust the drm_color_format enum to not needlessly renumber the
  existing defines, as it doesn't need to correspond to how HDMI numbers
  them.
- Make the DRM-to-HDMI conversion function static inline __pure, because
  the assembly it generates is tiny, and the function is pure.
- Don't accept nothing as the list of supported color formats for
  registration of the property.
- Drop the per-connector variants of the color format registration
  function, as it's not needed.
- drm_hdmi_state_helper: Fix mode_valid rejecting 420-only modes.
- drm_hdmi_state_helper: Only fall back to YUV420 with
  DRM_COLOR_FORMAT_AUTO.
- drm_hdmi_state_helper: Remove redundant AUTO->RGB condition, as the
  conversion already does this.
- Add KUnit tests for hdmi_compute_config.
- drm/bridge: Refactor bus_format_is_color_fmt and add a few more YUV422
  formats.
- Register the color format property in drmm_connector_hdmi_init based
  on the supported HDMI formats passed to it. This means rockchip
  dw_hdmi_qp no longer needs to register it.
- amdgpu: Simplify YUV420 logic
- amdgpu: Don't try to pick YUV444 on YUV420-only modes
- i915: Try to make behaviour more or less the same as that of the drm
  hdmi state helper.
- rockchip dw_hdmi_qp: Set supported HDMI formats
- rockchip dw_hdmi_qp: Set the right VO GRF values depending on color
  format.
- rockchip dw_hdmi_qp: Act on the color format property in this driver,
  rather than in VOP2, by setting the bus_format appropriately.
- rockchip VOP2: Can the BCSH-based implementation. BCSH isn't available
  on all video ports of the hardware, and the code was extremely
  suspect. Instead, plug into the existing YUV-to-RGB/RGB-to-YUV code,
  which can be done now that the HDMI driver sets the bus format.
- A whole bunch of Rockchip VOP2 fixes.
- Link to v4: https://lore.kernel.org/r/20251117-color-format-v4-0-0ded72bd1b00 at collabora.com

Changes in v4:
- Rebase onto next-20251117
- Get rid of HDMI_COLORSPACE_AUTO
- Split hdmi_compute_config change into separate patch
- Add missing symbol export for color_format_to_hdmi_colorspace to fix
  builds in certain configurations
- Drop "drm: Pass supported color formats straight onto drm_bridge"
- Make dw-hdmi-qp set the platform data's supported color formats as
  the bridge's supported HDMI color formats
- drm_hdmi_state_helper: pass requested color format to
  hdmi_compute_format_bpc if set.
- drm_bridge: limit the bus formats to those explicitly requested with
  the color format property during the atomic bridge check call,
  specifically in drm_atomic_bridge_chain_select_bus_fmts.
- i915: Remove INTEL_OUTPUT_FORMAT_AUTO, as automatic format selection
  does not need to involve the hardware state
- i915: Deduplicate ntel_output_format_to_drm_color_format code by
  moving it as a static inline __pure function into a shared header
- i915: rework logic in HDMI, DP and DP-MST output config functions to
  remove redundant locals, simplify execution flow, and return an error
  to userspace if an explicit color_format request can't be satisfied.
- i915: assign myself as the author and make the others Co-developers,
  so that they don't get the blame for any of my bugs.
- amdgpu: refactor fill_stream_properties_from_drm_display_mode to
  improve readability and ensure that impossible color format requests
  get bubbled up to userspace as errors
- amdgpu: don't pick YUV444 over RGB.
- amdgpu: assign authorship to myself, with others as Co-developers, as
  logic was modified and the blame should fall on me
- dw_hdmi_qp-rockchip: set the supported color formats platform data
  member
- rockchip: remove drm property registration for rk3066_hdmi and
  inno_hdmi. None of the platforms that use these use vop2 as the
  video output processor.
- Link to v3: https://lore.kernel.org/all/20250911130739.4936-1-marius.vlad at collabora.com/

Changes in v3 by mvlad compared to Andri's v2 series:
- renamed the property to just 'color format'
- the property is added dynamically similar to the Colorspace property
- a key point from previous comments was that drivers should advertise
  the color formats they support and userspace would query EDID and
  perform an intersection from those color formats which users can
  further use. With this patch set each driver that adds this property
  has such list of hard-coded color formats, but fundamentally the idea
  is that driver can query the HW and do that on its own. The
  infrastructure is now in place to allow to do that
- by default the 'AUTO' color format is set. With this patch series that
  has been introduced as a fallback to RGB. Drivers could further
  customize this behavour and could perform additional checks on the sink
  to pick another suitable color format they'd like for AUTO
- drm_bridge bridge code has been improved to allow initialization with
  the same color formats list as the DRM connector property. Similarly, bpc
  pick-up now takes the color format into consideration when deciding
  which bpc to choose from
- The new DRM color format re-uses HDMI_COLORPSACE enum and provides an
  enum translations between the two to avoid touching all other drivers that
  use HDMI_COLORPSACE enum. I believe at this point that this allows the
  least amount of disruption and avoids a massive bike shedding around
  that part
- a rockchip implementation has been by my colleague Derek Foreman
- YUV444 color format has been added in i915
- address comment about "Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A
  check" where aconnector might be invalid
- Link to v2: https://lore.kernel.org/dri-devel/20240115160554.720247-1-andri at yngvason.is/

---
Nicolas Frattaroli (27):
      drm/display: hdmi-state-helper: Use default case for unsupported formats
      drm: Add new general DRM property "color format"
      drm/connector: Let connectors have a say in their color format
      drm/display: bridge_connector: Use HDMI color format for HDMI conns
      drm/bridge: Act on the DRM color format property
      drm/atomic-helper: Add HDMI bridge output bus formats helper
      drm/display: hdmi-state-helper: Act on color format DRM property
      drm/display: hdmi-state-helper: Try subsampling in mode_valid
      drm/amdgpu: Implement "color format" DRM property
      drm/rockchip: Add YUV422 output mode constants for VOP2
      drm/rockchip: vop2: Add RK3576 to the RG swap special case
      drm/rockchip: vop2: Recognise 10-bit YUV422 as YUV format
      drm/rockchip: vop2: Set correct output format for RK3576 YUV422
      drm/bridge: dw-hdmi-qp: Use common HDMI output bus fmts helper
      drm/rockchip: dw_hdmi_qp: Implement "color format" DRM property
      drm/rockchip: dw_hdmi_qp: Set supported_formats platdata
      drm/connector: Register color format property on HDMI connectors
      drm/tests: hdmi: Add tests for the color_format property
      drm/tests: hdmi: Add tests for HDMI helper's mode_valid
      drm/tests: bridge: Add KUnit tests for bridge chain format selection
      drm/tests: bridge: Add test for HDMI output bus formats helper
      drm/bridge: Document bridge chain format selection
      drm/connector: Update docs of "colorspace" for color format prop
      drm/i915/hdmi: Add YCBCR444 handling for sink formats
      drm/i915/dp: Add YCBCR444 handling for sink formats
      drm/i915/hdmi: Implement "color format" DRM property
      drm/i915/dp: Implement "color format" DRM property

Werner Sembach (1):
      drm/amd/display: Remove unnecessary SIGNAL_TYPE_HDMI_TYPE_A check

 Documentation/gpu/drm-kms-helpers.rst              |   6 +
 Documentation/gpu/drm-kms.rst                      |   6 +
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c  |  91 +-
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c       |   1 +
 drivers/gpu/drm/display/drm_bridge_connector.c     |  24 +
 drivers/gpu/drm/display/drm_hdmi_state_helper.c    |  53 +-
 drivers/gpu/drm/drm_atomic_helper.c                |  86 ++
 drivers/gpu/drm/drm_atomic_uapi.c                  |   4 +
 drivers/gpu/drm/drm_bridge.c                       | 104 ++-
 drivers/gpu/drm/drm_connector.c                    | 178 +++-
 drivers/gpu/drm/i915/display/intel_dp.c            |  81 +-
 drivers/gpu/drm/i915/display/intel_hdmi.c          |  76 +-
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c     | 111 ++-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h        |   4 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c       |  21 +-
 drivers/gpu/drm/tests/drm_bridge_test.c            | 971 +++++++++++++++++++++
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 345 ++++++++
 include/drm/drm_atomic_helper.h                    |   7 +
 include/drm/drm_connector.h                        |  96 ++
 19 files changed, 2228 insertions(+), 37 deletions(-)
---
base-commit: f2f4e6d45fecc6ead92bf5ea06a04a00c245904e
change-id: 20251028-color-format-49fd202b7183

Best regards,
--  
Nicolas Frattaroli <nicolas.frattaroli at collabora.com>



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:50 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:50 +0200
Subject: [PATCH v17 03/28] drm: Add new general DRM property "color format"
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-3-35739b5782cc@collabora.com>

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 string values for the new enum property are:
 - "AUTO" (setup by default, driver internally picks the color format)
 - "RGB"
 - "YUV 4:4:4"
 - "YUV 4:2:2"
 - "YUV 4:2:0"

Drivers should advertise from this list the formats they support in an
optimistic best-case scenario. EDID data from the sink can then be used
in the kernel's atomic check phase to restrict this set of formats, as
well as by userspace to make a correct choice in the first place.

Co-developed-by: Werner Sembach <wse at tuxedocomputers.com>
Signed-off-by: Werner Sembach <wse at tuxedocomputers.com>
Co-developed-by: Andri Yngvason <andri at yngvason.is>
Signed-off-by: Andri Yngvason <andri at yngvason.is>
Signed-off-by: Marius Vlad <marius.vlad at collabora.com>
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 Documentation/gpu/drm-kms.rst       |   6 ++
 drivers/gpu/drm/drm_atomic_helper.c |   5 ++
 drivers/gpu/drm/drm_atomic_uapi.c   |   4 +
 drivers/gpu/drm/drm_connector.c     | 155 ++++++++++++++++++++++++++++++++++++
 include/drm/drm_connector.h         |  84 +++++++++++++++++++
 5 files changed, 254 insertions(+)

diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst
index e4f7153543b3..0dd440a14946 100644
--- a/Documentation/gpu/drm-kms.rst
+++ b/Documentation/gpu/drm-kms.rst
@@ -610,6 +610,12 @@ Color Management Properties
 .. kernel-doc:: drivers/gpu/drm/drm_color_mgmt.c
    :doc: overview
 
+Color Format Property
+---------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_connector.c
+   :doc: Color format
+
 Tile Group Property
 -------------------
 
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 51f39edc31ed..3547f797a850 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 			if (old_connector_state->max_requested_bpc !=
 			    new_connector_state->max_requested_bpc)
 				new_crtc_state->connectors_changed = true;
+
+			if (old_connector_state->color_format !=
+			    new_connector_state->color_format)
+				new_crtc_state->connectors_changed = true;
+
 		}
 
 		if (funcs->atomic_check)
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 6441b55cc274..c7f80d90794c 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -935,6 +935,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		state->privacy_screen_sw_state = val;
 	} else if (property == connector->broadcast_rgb_property) {
 		state->hdmi.broadcast_rgb = val;
+	} else if (property == connector->color_format_property) {
+		state->color_format = val;
 	} else if (connector->funcs->atomic_set_property) {
 		return connector->funcs->atomic_set_property(connector,
 				state, property, val);
@@ -1020,6 +1022,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = state->privacy_screen_sw_state;
 	} else if (property == connector->broadcast_rgb_property) {
 		*val = state->hdmi.broadcast_rgb;
+	} else if (property == connector->color_format_property) {
+		*val = state->color_format;
 	} else if (connector->funcs->atomic_get_property) {
 		return connector->funcs->atomic_get_property(connector,
 				state, property, val);
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index a5d13b92b665..296195087a4c 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1397,6 +1397,18 @@ static const u32 hdmi_colorspaces =
 	BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
 	BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
 
+static const u32 hdmi_colorformats =
+	BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+static const u32 dp_colorformats =
+	BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
 /*
  * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
  * Format Table 2-120
@@ -2944,6 +2956,149 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
 
+/**
+ * DOC: Color format
+ *
+ * The connector "color format" property allows userspace to request a specific
+ * color model on the output of the connector. Not all values listed by the
+ * property are guaranteed to work for every sink; rather, it is an optimistic
+ * listing of color formats that the source could output depending on
+ * circumstances.
+ *
+ * Whether it actually can output a certain color format is determined during
+ * the atomic check phase. Consequently, a userspace application that sets the
+ * color format to a value other than "AUTO" should check whether its atomic
+ * commit succeeded.
+ *
+ * Possible values for "color format":
+ *
+ * "AUTO":
+ *	The driver or display protocol helpers should pick a suitable color
+ *	format. All implementations of a specific display protocol will behave
+ *	the same way with "AUTO", but different display protocols do not
+ *	necessarily have the same "AUTO" semantics.
+ *
+ *	For HDMI connectors, "AUTO" picks RGB, but falls back to YUV 4:2:0 if
+ *	the bandwidth required for full-scale RGB is not available, or the mode
+ *	is YUV 4:2:0-only, as long as the mode, source, and sink all support
+ *	YUV 4:2:0.
+ * "RGB":
+ *	RGB output format. The quantization range (limited/full) depends on the
+ *	value of the "Broadcast RGB" property if it is present on the connector.
+ * "YUV 4:4:4":
+ *	YUV 4:4:4 (a.k.a. YCbCr 4:4:4) output format. Chroma is not subsampled.
+ *	The quantization range defaults to limited.
+ * "YUV 4:2:2":
+ *	YUV 4:2:2 (a.k.a. YCbCr 4:2:2) output format. Chroma has half the
+ *	horizontal resolution of Luma. The quantization range defaults to
+ *	limited.
+ * "YUV 4:2:0":
+ *	YUV 4:2:0 (a.k.a. YCbCr 4:2:0) output format. Chroma has half the
+ *	horizontal and vertical resolution of Luma. The quantization range
+ *	defaults to limited.
+ *
+ * A sink may only support some color formats in specific modes and at specific
+ * bit depths. The atomic modesetting API should be used to set a working
+ * configuration in one go, as an unsupported combination of parameters is
+ * rejected.
+ */
+
+/**
+ * drm_connector_attach_color_format_property - create and attach color format property
+ * @connector: connector to create the color format property on
+ * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
+ *                           values the connector supports
+ *
+ * Called by a driver to create a color format property. The property is
+ * attached to the connector automatically on success.
+ *
+ * @supported_color_formats should only include color formats the connector
+ * type can actually support.
+ *
+ * Returns:
+ * 0 on success, negative errno on error
+ */
+int drm_connector_attach_color_format_property(struct drm_connector *connector,
+					       unsigned long supported_color_formats)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
+	unsigned int i = 0;
+	unsigned long fmt;
+
+	if (connector->color_format_property)
+		return 0;
+
+	if (!supported_color_formats) {
+		drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
+			connector->base.id, connector->name);
+		return -EINVAL;
+	}
+
+	if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
+		drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
+			connector->base.id, connector->name);
+		return -EINVAL;
+	}
+
+	switch (connector->connector_type) {
+	case DRM_MODE_CONNECTOR_HDMIA:
+	case DRM_MODE_CONNECTOR_HDMIB:
+		if (supported_color_formats & ~hdmi_colorformats) {
+			drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
+				connector->base.id, connector->name);
+			return -EINVAL;
+		}
+		break;
+	case DRM_MODE_CONNECTOR_DisplayPort:
+	case DRM_MODE_CONNECTOR_eDP:
+		if (supported_color_formats & ~dp_colorformats) {
+			drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
+				connector->base.id, connector->name);
+			return -EINVAL;
+		}
+		break;
+	}
+
+	enum_list[0].name = "AUTO";
+	enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
+
+	for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
+		switch (fmt) {
+		case DRM_OUTPUT_COLOR_FORMAT_RGB444:
+			enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+			break;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
+			enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+			break;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
+			enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+			break;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
+			enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+			break;
+		default:
+			drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
+				 fmt, connector->base.id, connector->name);
+			continue;
+		}
+		enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
+	}
+
+	connector->color_format_property =
+		drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
+					 enum_list, i + 1);
+
+	if (!connector->color_format_property)
+		return -ENOMEM;
+
+	drm_object_attach_property(&connector->base, connector->color_format_property,
+				   DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_connector_attach_color_format_property);
+
 /**
  * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
  * @old_state: old connector state to compare
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 529755c2e862..e1f6072ce7c9 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -571,12 +571,80 @@ enum drm_colorspace {
  *   YCbCr 4:2:2 output format (ie. with horizontal subsampling)
  * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
  *   YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
+ * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
+ *   Number of valid output color format values in this enum
  */
 enum drm_output_color_format {
 	DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
 	DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
 	DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
 	DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+	DRM_OUTPUT_COLOR_FORMAT_COUNT,
+};
+
+/**
+ * enum drm_connector_color_format - Connector Color Format Request
+ *
+ * This enum, unlike &enum drm_output_color_format, is used to specify requests
+ * for a specific color format on a connector through the DRM "color format"
+ * property. The difference is that it has an "AUTO" value to specify that
+ * no specific choice has been made.
+ */
+enum drm_connector_color_format {
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
+	 * helpers should pick a suitable color format. All implementations of a
+	 * specific display protocol must behave the same way with "AUTO", but
+	 * different display protocols do not necessarily have the same "AUTO"
+	 * semantics.
+	 *
+	 * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
+	 * bandwidth required for full-scale RGB is not available, or the mode
+	 * is YCbCr 4:2:0-only, as long as the mode and output both support
+	 * YCbCr 4:2:0.
+	 *
+	 * For display protocols other than HDMI, the recursive bridge chain
+	 * format selection picks the first chain of bridge formats that works,
+	 * as has already been the case before the introduction of the "color
+	 * format" property. Non-HDMI bridges should therefore either sort their
+	 * bus output formats by preference, or agree on a unified auto format
+	 * selection logic that's implemented in a common state helper (like
+	 * how HDMI does it).
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_AUTO = 0,
+
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_RGB444: RGB output format. The
+	 * quantization range depends on the value of the "Broadcast RGB"
+	 * property if it is present on the connector.
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: YCbCr 4:4:4 output format (ie.
+	 * not subsampled). Quantization range is "Limited" by default.
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: YCbCr 4:2:2 output format (ie.
+	 * with horizontal subsampling). Quantization range is "Limited" by
+	 * default.
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: YCbCr 4:2:0 output format (ie.
+	 * with horizontal and vertical subsampling). Quantization range is
+	 * "Limited" by default.
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+
+	/**
+	 * @DRM_CONNECTOR_COLOR_FORMAT_COUNT: Number of valid connector color
+	 * format values in this enum
+	 */
+	DRM_CONNECTOR_COLOR_FORMAT_COUNT,
 };
 
 const char *
@@ -1167,6 +1235,13 @@ struct drm_connector_state {
 	 */
 	enum drm_colorspace colorspace;
 
+	/**
+	 * @color_format: State variable for Connector property to request
+	 * color format change on Sink. This is most commonly used to switch
+	 * between RGB to YUV and vice-versa.
+	 */
+	enum drm_connector_color_format color_format;
+
 	/**
 	 * @writeback_job: Writeback job for writeback connectors
 	 *
@@ -2181,6 +2256,12 @@ struct drm_connector {
 	 */
 	struct drm_property *colorspace_property;
 
+	/**
+	 * @color_format_property: Connector property to set the suitable
+	 * color format supported by the sink.
+	 */
+	struct drm_property *color_format_property;
+
 	/**
 	 * @path_blob_ptr:
 	 *
@@ -2664,6 +2745,9 @@ bool drm_connector_has_possible_encoder(struct drm_connector *connector,
 					struct drm_encoder *encoder);
 const char *drm_get_colorspace_name(enum drm_colorspace colorspace);
 
+int drm_connector_attach_color_format_property(struct drm_connector *connector,
+					       unsigned long supported_color_formats);
+
 /**
  * drm_for_each_connector_iter - connector_list iterator macro
  * @connector: &struct drm_connector pointer used as cursor

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:51 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:51 +0200
Subject: [PATCH v17 04/28] drm/connector: Let connectors have a say in
 their color format
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-4-35739b5782cc@collabora.com>

Add a function to get the connector color format from a connector state,
and a new function pointer in drm_connector_funcs to allow connectors to
override what connector color format it returns.

This is useful for the bridge chain recursive bus format selection code,
which does not wish to implement connector implementation specific
checks like whether it involves HDMI.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/drm_connector.c | 16 ++++++++++++++++
 include/drm/drm_connector.h     | 12 ++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 296195087a4c..95c65ed18709 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -3694,6 +3694,22 @@ void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
 }
 EXPORT_SYMBOL(drm_connector_oob_hotplug_event);
 
+/**
+ * drm_connector_get_color_format - Return connector color format of @conn_state
+ * @conn_state: pointer to the &struct drm_connector_state to go check
+ *
+ */
+enum drm_connector_color_format
+drm_connector_get_color_format(const struct drm_connector_state *conn_state)
+{
+	struct drm_connector *connector = conn_state->connector;
+
+	if (connector->funcs->color_format)
+		return connector->funcs->color_format(conn_state);
+
+	return conn_state->color_format;
+}
+EXPORT_SYMBOL(drm_connector_get_color_format);
 
 /**
  * DOC: Tile group
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index e1f6072ce7c9..4317166562cf 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1803,6 +1803,16 @@ struct drm_connector_funcs {
 	 * Allows connectors to create connector-specific debugfs files.
 	 */
 	void (*debugfs_init)(struct drm_connector *connector, struct dentry *root);
+
+	/**
+	 * @color_format:
+	 *
+	 * Allows connectors to return a connector color format other than
+	 * @conn_state.color_format for purposes of e.g. display protocol
+	 * specific helper logic having already mapped it to an output format.
+	 */
+	enum drm_connector_color_format (*color_format)(
+		const struct drm_connector_state *conn_state);
 };
 
 /**
@@ -2619,6 +2629,8 @@ drm_connector_is_unregistered(struct drm_connector *connector)
 
 void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode,
 				     enum drm_connector_status status);
+enum drm_connector_color_format
+drm_connector_get_color_format(const struct drm_connector_state *conn_state);
 const char *drm_get_connector_type_name(unsigned int connector_type);
 const char *drm_get_connector_status_name(enum drm_connector_status status);
 const char *drm_get_subpixel_order_name(enum subpixel_order order);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:52 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:52 +0200
Subject: [PATCH v17 05/28] drm/display: bridge_connector: Use HDMI color
 format for HDMI conns
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-5-35739b5782cc@collabora.com>

For bridge connectors which contain an HDMI bridge at some stage, the
HDMI state helpers' format selection logic should be involved.

Add an implementation for the drm_bridge_funcs color_format function,
which translates from the HDMI state's output format to a connector
format for bridge connectors involving an HDMI bridge, but return the
connector state's color_format member unchanged otherwise.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index cafa498c3848..92f8a2d7aab4 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -283,6 +283,29 @@ drm_bridge_connector_create_state(struct drm_connector *connector)
 	return conn_state;
 }
 
+static enum drm_connector_color_format
+drm_bridge_connector_color_format(const struct drm_connector_state *conn_state)
+{
+	struct drm_bridge_connector *bridge_connector =
+		to_drm_bridge_connector(conn_state->connector);
+
+	if (bridge_connector->bridge_hdmi) {
+		switch (conn_state->hdmi.output_format) {
+		default:
+		case DRM_OUTPUT_COLOR_FORMAT_RGB444:
+			return DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
+			return DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
+			return DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
+		case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
+			return DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
+		}
+	}
+
+	return conn_state->color_format;
+}
+
 static const struct drm_connector_funcs drm_bridge_connector_funcs = {
 	.detect = drm_bridge_connector_detect,
 	.force = drm_bridge_connector_force,
@@ -292,6 +315,7 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = {
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 	.debugfs_init = drm_bridge_connector_debugfs_init,
 	.oob_hotplug_event = drm_bridge_connector_oob_hotplug_event,
+	.color_format = drm_bridge_connector_color_format,
 };
 
 /* -----------------------------------------------------------------------------

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:53 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:53 +0200
Subject: [PATCH v17 06/28] drm/bridge: Act on the DRM color format property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-6-35739b5782cc@collabora.com>

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. Call into the connector function to get
the connector state's connector color format. For bridge connectors
including an HDMI bridge, this will make use of whatever the HDMI
implementation set as output formats, and AUTO will never be part of the
rejection logic.

Reject any output bus formats that do not correspond to the requested
color format. DRM_CONNECTOR_COLOR_FORMAT_AUTO is always accepted as a
matching color format for a bus format, meaning that non-HDMI bridge
chains will end up picking the first bus format choice that works, as
has already been the case previously.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/drm_bridge.c | 64 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 9a185032a3bd..9d6fcf986022 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -1151,6 +1151,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_connector_color_format fmt)
+{
+	if (fmt == DRM_CONNECTOR_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_CONNECTOR_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_CONNECTOR_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_CONNECTOR_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_CONNECTOR_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.
@@ -1194,6 +1235,7 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
 	struct drm_encoder *encoder = bridge->encoder;
 	struct drm_bridge_state *last_bridge_state;
 	unsigned int i, num_out_bus_fmts = 0;
+	enum drm_connector_color_format fmt;
 	u32 *out_bus_fmts;
 	int ret = 0;
 
@@ -1235,11 +1277,31 @@ drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge,
 			out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED;
 	}
 
+	/*
+	 * Instead of directly accessing conn_state.color_format, call into a
+	 * connector function that allows connector implementations (e.g. for
+	 * bridge connectors including HDMI bridges, where the HDMI helpers will
+	 * have already chosen an appropriate output format) to override the
+	 * selected format.
+	 */
+	fmt = drm_connector_get_color_format(conn_state);
+
 	for (i = 0; i < num_out_bus_fmts; i++) {
+		if (!bus_format_is_color_fmt(out_bus_fmts[i], fmt)) {
+			drm_dbg_kms(last_bridge->dev,
+				    "Skipping bus format 0x%04x as it doesn't match format %d\n",
+				    out_bus_fmts[i], fmt);
+			ret = -ENOTSUPP;
+			continue;
+		}
 		ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state,
 					       conn_state, out_bus_fmts[i]);
-		if (ret != -ENOTSUPP)
+		if (ret != -ENOTSUPP) {
+			drm_dbg_kms(last_bridge->dev,
+				    "Found bridge chain ending with bus format 0x%04x\n",
+				    out_bus_fmts[i]);
 			break;
+		}
 	}
 
 	kfree(out_bus_fmts);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:54 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:54 +0200
Subject: [PATCH v17 07/28] drm/atomic-helper: Add HDMI bridge output bus
 formats helper
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-7-35739b5782cc@collabora.com>

The drm_bridge_funcs atomic_get_output_bus_fmts operation should be the
same for likely every HDMI connector bridge, unless such an HDMI
connector bridge has some special hardware restrictions that I cannot
envision yet.

To avoid code duplication and standardize on a set of media bus formats
that the HDMI output color formats translate to, add a common helper
function that implements this operation to the drm bridge helpers.

The function returns a list of output bus formats based on the HDMI
bridge's current output bits-per-component, and its bitmask of supported
color formats.

To guard against future expansion of DRM_OUTPUT_COLOR_FORMAT outgrowing
the hweight8 call, add a BUILD_BUG_ON statement where it's used that
checks for DRM_OUTPUT_COLOR_FORMAT_COUNT. The justification for not
using hweight32 in all cases is that not all ISAs have a popcount
instruction, and will benefit from a smaller/faster software
implementation that doesn't have to operate across all bits.

The justification for not defining an hweight_color depending on the
value of DRM_OUTPUT_COLOR_FORMAT_COUNT is that this count enum value is
only known at compile time, not at preprocessor time.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 81 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  7 ++++
 2 files changed, 88 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 3547f797a850..285aac3554df 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -28,6 +28,7 @@
 #include <linux/export.h>
 #include <linux/dma-fence.h>
 #include <linux/ktime.h>
+#include <linux/media-bus-format.h>
 
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
@@ -4107,3 +4108,83 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
 	return input_fmts;
 }
 EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
+
+/**
+ * drm_atomic_helper_bridge_get_hdmi_output_bus_fmts - helper implementing
+ *                                           atomic_get_output_bus_fmts for HDMI
+ * @bridge: pointer to &struct drm_bridge
+ * @bridge_state: pointer to the current bridge state
+ * @crtc_state: pointer to the current CRTC state
+ * @conn_state: pointer to the current connector state
+ * @num_output_fmts: pointer to where the number of entries in the returned array
+ *                   will be stored. Set to 0 if unsuccessful.
+ *
+ * Common implementation for the &drm_bridge_funcs.atomic_get_output_bus_fmts
+ * operation that's applicable to HDMI connectors.
+ *
+ * Returns: a newly allocated array of u32 values of length \*@num_output_fmts,
+ * representing all the MEDIA_BUS_FMTS\_ for the current connector state's
+ * chosen HDMI output bits per compoennt, or %NULL if it fails to allocate one.
+ */
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					unsigned int *num_output_fmts)
+{
+	unsigned int num_fmts = 0;
+	u32 *out_fmts;
+
+	/*
+	 * bridge->supported_formats is a bit field of BIT(enum drm_output_color_format)
+	 * values. The smallest hweight that is smaller than or equal to
+	 * %DRM_OUTPUT_COLOR_FORMAT_COUNT will do for counting set bits here.
+	 */
+	BUILD_BUG_ON(const_true(DRM_OUTPUT_COLOR_FORMAT_COUNT > 8));
+	out_fmts = kmalloc_array(hweight8(bridge->supported_formats),
+				 sizeof(u32), GFP_KERNEL);
+	if (!out_fmts) {
+		*num_output_fmts = 0;
+		return NULL;
+	}
+
+	switch (conn_state->hdmi.output_bpc) {
+	case 12:
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB121212_1X36;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV12_1X36;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY12_1X24;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
+		break;
+	case 10:
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB101010_1X30;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV10_1X30;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY10_1X20;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+		break;
+	default:
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB888_1X24;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV8_1X24;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY8_1X16;
+		if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+			out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+		break;
+	}
+
+	*num_output_fmts = num_fmts;
+
+	return out_fmts;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_get_hdmi_output_bus_fmts);
+
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index b84152810abb..4cfeec70d648 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -295,4 +295,11 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
 					u32 output_fmt,
 					unsigned int *num_input_fmts);
 
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+					struct drm_bridge_state *bridge_state,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state,
+					unsigned int *num_output_fmts);
+
 #endif /* DRM_ATOMIC_HELPER_H_ */

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:55 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:55 +0200
Subject: [PATCH v17 08/28] drm/display: hdmi-state-helper: Act on color
 format DRM property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-8-35739b5782cc@collabora.com>

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 translating the requested drm_connector_color_format to
a drm_output_color_format enum value as per the logic HDMI should use
for this: Auto is translated to RGB, and a fallback to YUV420 is only
performed if the original color format was auto.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 31 +++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
index c68b159f0a7f..069f9bf2489e 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -671,8 +671,39 @@ 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 drm_output_color_format fmt;
 	int ret;
 
+	if (conn_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
+		switch (conn_state->color_format) {
+		case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+			drm_warn(connector->dev, "AUTO format in non-AUTO path.\n");
+			fallthrough;
+		case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+			fmt = DRM_OUTPUT_COLOR_FORMAT_RGB444;
+			break;
+		case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+			fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR444;
+			break;
+		case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
+			fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR422;
+			break;
+		case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+			fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+			break;
+		default:
+			drm_dbg_kms(connector->dev, "HDMI does not support color format '%d'.\n",
+				conn_state->color_format);
+			return -EINVAL;
+		}
+
+		return hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc, fmt);
+	}
+
+	/*
+	 * For %DRM_CONNECTOR_COLOR_FORMAT_AUTO, try RGB first, and fall back
+	 * to the less bandwidth-intensive YCBCR420 if RGB fails.
+	 */
 	ret = hdmi_compute_format_bpc(connector, conn_state, mode, max_bpc,
 				      DRM_OUTPUT_COLOR_FORMAT_RGB444);
 	if (ret) {

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:56 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:56 +0200
Subject: [PATCH v17 09/28] drm/display: hdmi-state-helper: Try subsampling
 in mode_valid
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-9-35739b5782cc@collabora.com>

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 or 420-also modes.

Fix this by checking whether the mode is 420-capable first. If so, then
proceed by checking it with DRM_OUTPUT_COLOR_FORMAT_YCBCR420 so long as
the connector has legalized 420, otherwise error out. If the mode is not
420-capable, check with RGB as was previously always the case.

Fixes: 47368ab437fd ("drm/display: hdmi: add generic mode_valid helper")
Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/display/drm_hdmi_state_helper.c | 15 ++++++++++++++-
 1 file changed, 14 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 069f9bf2489e..ce17eeefc2da 100644
--- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
+++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
@@ -943,8 +943,21 @@ drm_hdmi_connector_mode_valid(struct drm_connector *connector,
 			      const struct drm_display_mode *mode)
 {
 	unsigned long long clock;
+	enum drm_output_color_format fmt;
+
+	if (drm_mode_is_420_only(&connector->display_info, mode)) {
+		if (connector->ycbcr_420_allowed)
+			fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+		else
+			return MODE_NO_420;
+	} else if (drm_mode_is_420_also(&connector->display_info, mode) &&
+		   connector->ycbcr_420_allowed) {
+		fmt = DRM_OUTPUT_COLOR_FORMAT_YCBCR420;
+	} else {
+		fmt = DRM_OUTPUT_COLOR_FORMAT_RGB444;
+	}
 
-	clock = drm_hdmi_compute_mode_clock(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+	clock = drm_hdmi_compute_mode_clock(mode, 8, fmt);
 	if (!clock)
 		return MODE_ERROR;
 

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:57 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:57 +0200
Subject: [PATCH v17 10/28] drm/amdgpu: Implement "color format" DRM
 property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-10-35739b5782cc@collabora.com>

The "color format" DRM property allows userspace to explicitly pick a
color format to use. If an unsupported color format is requested,
userspace will be given an error instead of silently having its request
disobeyed.

The default case, which is AUTO, picks YCbCr 4:2:0 if it's a 4:2:0-only
mode, and RGB in all other cases.

Co-developed-by: Werner Sembach <wse at tuxedocomputers.com>
Signed-off-by: Werner Sembach <wse at tuxedocomputers.com>
Co-developed-by: Andri Yngvason <andri at yngvason.is>
Signed-off-by: Andri Yngvason <andri at yngvason.is>
Co-developed-by: Marius Vlad <marius.vlad at collabora.com>
Signed-off-by: Marius Vlad <marius.vlad at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 90 ++++++++++++++++++++---
 1 file changed, 79 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index dfe97897127c..ece581609cf7 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -6899,11 +6899,14 @@ static void fill_stream_properties_from_drm_display_mode(
 	const struct dc_stream_state *old_stream,
 	int requested_bpc)
 {
+	bool is_dp_or_hdmi = dc_is_hdmi_signal(stream->signal) || dc_is_dp_signal(stream->signal);
 	struct dc_crtc_timing *timing_out = &stream->timing;
 	const struct drm_display_info *info = &connector->display_info;
 	struct amdgpu_dm_connector *aconnector = NULL;
 	struct hdmi_vendor_infoframe hv_frame;
 	struct hdmi_avi_infoframe avi_frame;
+	bool want_420;
+	bool want_422;
 	ssize_t err;
 
 	if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
@@ -6916,20 +6919,41 @@ static void fill_stream_properties_from_drm_display_mode(
 	timing_out->h_border_right = 0;
 	timing_out->v_border_top = 0;
 	timing_out->v_border_bottom = 0;
-	/* TODO: un-hardcode */
-	if (drm_mode_is_420_only(info, mode_in) ||
-	    (aconnector && aconnector->force_yuv420_output &&
-	     drm_mode_is_420_also(info, mode_in)))
+
+	want_420 = (aconnector && aconnector->force_yuv420_output) ||
+		   (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420);
+	want_422 = (aconnector && aconnector->force_yuv422_output) ||
+		   (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422);
+
+	if (drm_mode_is_420_only(info, mode_in) &&
+	    (want_420 || connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)) {
 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
-	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
-			&& aconnector
-			&& aconnector->force_yuv422_output)
+	} else if (drm_mode_is_420_also(info, mode_in) && want_420) {
+		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+	} else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) &&
+		   want_422 && is_dp_or_hdmi) {
 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422;
-	else if ((connector->display_info.color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
-			&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
+	} else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 &&
+		   (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) &&
+		   is_dp_or_hdmi) {
 		timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
-	else
+	} else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444 ||
+		   connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO) {
 		timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+	} else {
+		/*
+		 * If a format was explicitly requested but the requested format
+		 * can't be satisfied, set it to an invalid value so that an
+		 * error bubbles up to userspace. This way, userspace knows it
+		 * needs to make a better choice.
+		 */
+		if (connector_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO)
+			timing_out->pixel_encoding = PIXEL_ENCODING_UNDEFINED;
+		else if (drm_mode_is_420_only(info, mode_in))
+			timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
+		else
+			timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+	}
 
 	timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
 	timing_out->display_color_depth = convert_color_depth_from_display_info(
@@ -8279,6 +8303,38 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc,
 	return dc_result;
 }
 
+static enum dc_status
+dm_validate_stream_color_format(const struct drm_connector_state *drm_state,
+				const struct dc_stream_state *stream)
+{
+	enum dc_pixel_encoding encoding;
+
+	if (!drm_state->color_format)
+		return DC_OK;
+
+	switch (drm_state->color_format) {
+	case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+	case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+		encoding = PIXEL_ENCODING_RGB;
+		break;
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+		encoding = PIXEL_ENCODING_YCBCR444;
+		break;
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422:
+		encoding = PIXEL_ENCODING_YCBCR422;
+		break;
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+		encoding = PIXEL_ENCODING_YCBCR420;
+		break;
+	default:
+		encoding = PIXEL_ENCODING_UNDEFINED;
+		break;
+	}
+
+	return encoding == stream->timing.pixel_encoding ?
+		DC_OK : DC_UNSUPPORTED_VALUE;
+}
+
 struct dc_stream_state *
 create_validate_stream_for_sink(struct drm_connector *connector,
 				const struct drm_display_mode *drm_mode,
@@ -8325,6 +8381,9 @@ create_validate_stream_for_sink(struct drm_connector *connector,
 		if (dc_result == DC_OK)
 			dc_result = dm_validate_stream_and_context(adev->dm.dc, stream);
 
+		if (dc_result == DC_OK)
+			dc_result = dm_validate_stream_color_format(drm_state, stream);
+
 		if (dc_result != DC_OK) {
 			drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n",
 				      drm_mode->hdisplay,
@@ -9154,6 +9213,12 @@ static const u32 supported_colorspaces =
 	BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) |
 	BIT(DRM_MODE_COLORIMETRY_BT2020_YCC);
 
+static const u32 supported_colorformats =
+	BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+	BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
 void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
 				     struct amdgpu_dm_connector *aconnector,
 				     int connector_type,
@@ -9270,8 +9335,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
 	    connector_type == DRM_MODE_CONNECTOR_eDP) {
 		drm_connector_attach_hdr_output_metadata_property(&aconnector->base);
 
-		if (!aconnector->mst_root)
+		if (!aconnector->mst_root) {
 			drm_connector_attach_vrr_capable_property(&aconnector->base);
+			drm_connector_attach_color_format_property(&aconnector->base,
+								   supported_colorformats);
+		}
 
 		if (adev->dm.hdcp_workqueue)
 			drm_connector_attach_content_protection_property(&aconnector->base, true);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:58 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:58 +0200
Subject: [PATCH v17 11/28] drm/rockchip: Add YUV422 output mode constants
 for VOP2
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-11-35739b5782cc@collabora.com>

The Rockchip display controller has a general YUV422 output mode, and
some SoC-specific connector-specific output modes for RK3576.

Add them, based on the values in downstream and the TRM (dsp_out_mode in
RK3576 TRM Part 2, register POST*_CTRL_POST_DSP_CTRL).

Reviewed-by: Andy Yan <andyshrk at 163.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 2e86ad00979c..4705dc6b8bd7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -30,10 +30,14 @@
 #define ROCKCHIP_OUT_MODE_P565		2
 #define ROCKCHIP_OUT_MODE_BT656		5
 #define ROCKCHIP_OUT_MODE_S888		8
+#define ROCKCHIP_OUT_MODE_YUV422	9
 #define ROCKCHIP_OUT_MODE_S888_DUMMY	12
 #define ROCKCHIP_OUT_MODE_YUV420	14
 /* for use special outface */
 #define ROCKCHIP_OUT_MODE_AAAA		15
+/* SoC specific output modes */
+#define ROCKCHIP_OUT_MODE_YUV422_RK3576_DP	12
+#define ROCKCHIP_OUT_MODE_YUV422_RK3576_HDMI	13
 
 /* output flags */
 #define ROCKCHIP_OUTPUT_DSI_DUAL	BIT(0)

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:43:59 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:43:59 +0200
Subject: [PATCH v17 12/28] drm/rockchip: vop2: Add RK3576 to the RG swap
 special case
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-12-35739b5782cc@collabora.com>

Much like RK3588, RK3576 requires an RG swap to be performed for YUV444
8-bit and YUV444 10-bit bus formats.

Add its version to the already existing check for RK3588, so that YUV444
output is correct on this platform.

Fixes: 944757a4cba6 ("drm/rockchip: vop2: Add support for rk3576")
Reviewed-by: Andy Yan <andyshrk at 163.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
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 9b261f0c7eec..6230735bbabc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -337,7 +337,8 @@ static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode)
 
 static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format)
 {
-	if (vop2->version == VOP_VERSION_RK3588) {
+	if (vop2->version == VOP_VERSION_RK3588 ||
+	    vop2->version == VOP_VERSION_RK3576) {
 		if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 ||
 		    bus_format == MEDIA_BUS_FMT_YUV10_1X30)
 			return true;

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:00 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:00 +0200
Subject: [PATCH v17 13/28] drm/rockchip: vop2: Recognise 10-bit YUV422 as
 YUV format
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-13-35739b5782cc@collabora.com>

The Rockchip VOP2 video output driver has a "is_yuv_output" function,
which returns true when a given bus format is a YUV format, and false
otherwise.

This switch statement is lacking the bus format used for YUV422 10-bit.

Add the two component orderings of the YUV422 10-bit bus formats to the
switch statement.

Fixes: 604be85547ce ("drm/rockchip: Add VOP2 driver")
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 6230735bbabc..3fad79fe2d89 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -352,6 +352,8 @@ static bool is_yuv_output(u32 bus_format)
 	switch (bus_format) {
 	case MEDIA_BUS_FMT_YUV8_1X24:
 	case MEDIA_BUS_FMT_YUV10_1X30:
+	case MEDIA_BUS_FMT_YUYV10_1X20:
+	case MEDIA_BUS_FMT_UYVY10_1X20:
 	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
 	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
 	case MEDIA_BUS_FMT_YUYV8_2X8:

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:01 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:01 +0200
Subject: [PATCH v17 14/28] drm/rockchip: vop2: Set correct output format
 for RK3576 YUV422
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-14-35739b5782cc@collabora.com>

For RK3576 to be able to output YUV422 signals, it first needs to be
able to pick the right output mode in the display controller to do so.

The RK3576 hardware specifies different output formats depending on the
used display protocol.

Adjust the written register value based on the SoC and connector, so
other users of vcstate->output_mode don't have to care about this.

Reviewed-by: Andy Yan <andyshrk at 163.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 3fad79fe2d89..4cce3e336f5b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -1824,6 +1824,22 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
 	if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA &&
 	    !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT))
 		out_mode = ROCKCHIP_OUT_MODE_P888;
+	else if (vcstate->output_mode == ROCKCHIP_OUT_MODE_YUV422 &&
+		 vop2->version == VOP_VERSION_RK3576)
+		switch (vcstate->output_type) {
+		case DRM_MODE_CONNECTOR_DisplayPort:
+		case DRM_MODE_CONNECTOR_eDP:
+			out_mode = ROCKCHIP_OUT_MODE_YUV422_RK3576_DP;
+			break;
+		case DRM_MODE_CONNECTOR_HDMIA:
+			out_mode = ROCKCHIP_OUT_MODE_YUV422_RK3576_HDMI;
+			break;
+		default:
+			drm_err(vop2->drm, "Unknown DRM_MODE_CONNECTOR %d\n",
+				vcstate->output_type);
+			vop2_unlock(vop2);
+			return;
+		}
 	else
 		out_mode = vcstate->output_mode;
 

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:02 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:02 +0200
Subject: [PATCH v17 15/28] drm/bridge: dw-hdmi-qp: Use common HDMI output
 bus fmts helper
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-15-35739b5782cc@collabora.com>

Make use of the common drm_bridge_funcs.atomic_get_output_bus_fmts
helper for HDMI bridge connectors.

This allows dw-hdmi-qp HDMI bridges to participate in recursive bus
format selection in a meaningful way.

Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
index 1c214a8e6dc2..13fddd5ebc82 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
@@ -1190,6 +1190,7 @@ static int dw_hdmi_qp_cec_transmit(struct drm_bridge *bridge, u8 attempts,
 #endif /* CONFIG_DRM_DW_HDMI_QP_CEC */
 
 static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = {
+	.atomic_get_output_bus_fmts = drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
 	.atomic_reset = drm_atomic_helper_bridge_reset,

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:03 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:03 +0200
Subject: [PATCH v17 16/28] drm/rockchip: dw_hdmi_qp: Implement "color
 format" DRM property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-16-35739b5782cc@collabora.com>

Switch between requested color formats by setting the right bus formats,
configuring the VO GRF registers, and setting the right output mode.

To do this, the encoder's atomic_check queries the bus format of the
first bridge, which was determined by the bridge chain recursive format
selection. Pick the input format if it's !FIXED, otherwise, pick the
output format.

The previously unused GRF register color format defines are redone as
well. Both RK3588 and RK3576 use the same defines; it didn't look like
this as there was a typo in the previously (unused) definition.

Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 107 ++++++++++++++++++++++---
 1 file changed, 98 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index f35484715c2d..b77ef92ae954 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -11,6 +11,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/hw_bitfield.h>
 #include <linux/mfd/syscon.h>
+#include <linux/media-bus-format.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/phy/phy.h>
@@ -44,10 +45,6 @@
 #define RK3576_8BPC			0x0
 #define RK3576_10BPC			0x6
 #define RK3576_COLOR_FORMAT_MASK	GENMASK(7, 4)
-#define RK3576_RGB			0x9
-#define RK3576_YUV422			0x1
-#define RK3576_YUV444			0x2
-#define RK3576_YUV420			0x3
 #define RK3576_CECIN_MASK		BIT(3)
 
 #define RK3576_VO0_GRF_SOC_CON14	0x0038
@@ -75,8 +72,6 @@
 #define RK3588_8BPC			0x0
 #define RK3588_10BPC			0x6
 #define RK3588_COLOR_FORMAT_MASK	GENMASK(3, 0)
-#define RK3588_RGB			0x0
-#define RK3588_YUV420			0x3
 #define RK3588_SCLIN_MASK		BIT(9)
 #define RK3588_SDAIN_MASK		BIT(10)
 #define RK3588_MODE_MASK		BIT(11)
@@ -88,6 +83,11 @@
 #define HOTPLUG_DEBOUNCE_MS		150
 #define MAX_HDMI_PORT_NUM		2
 
+#define RK_COLOR_FMT_RGB		0x0
+#define RK_COLOR_FMT_YUV422		0x1
+#define RK_COLOR_FMT_YUV444		0x2
+#define RK_COLOR_FMT_YUV420		0x3
+
 struct rockchip_hdmi_qp {
 	struct device *dev;
 	struct regmap *regmap;
@@ -116,6 +116,33 @@ static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder)
 	return container_of(rkencoder, struct rockchip_hdmi_qp, encoder);
 }
 
+/**
+ * dw_hdmi_qp_rockchip_bus_fmt_to_reg - converts a bus format to a GRF reg value
+ * @bus_fmt: One of the MEDIA_BUS_FMT_s allowed by this driver's atomic_check
+ *
+ * Returns: an unshifted value to be written to the COLOR_FORMAT GRF register
+ * on success, or %-EINVAL if the bus format is not supported.
+ */
+static int __pure dw_hdmi_qp_rockchip_bus_fmt_to_reg(u32 bus_fmt)
+{
+	switch (bus_fmt) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+		return RK_COLOR_FMT_RGB;
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+	case MEDIA_BUS_FMT_UYVY10_1X20:
+		return RK_COLOR_FMT_YUV422;
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+		return RK_COLOR_FMT_YUV444;
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+		return RK_COLOR_FMT_YUV420;
+	}
+
+	return -EINVAL;
+}
+
 static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
 {
 	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
@@ -131,29 +158,83 @@ static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder)
 		hdmi->ctrl_ops->enc_init(hdmi, to_rockchip_crtc_state(crtc->state));
 }
 
+/**
+ * dw_hdmi_qp_rockchip_get_vop_format - get the bus format VOP should output
+ * @encoder: pointer to a &struct drm_encoder
+ * @conn_state: pointer to the current atomic &struct drm_connector_state
+ *
+ * Determines which bus format the Rockchip video processor should output as
+ * to feed into the bridge chain.
+ *
+ * Returns a MEDIA_BUS_FMT_* on success, or negative errno on error.
+ */
+static int dw_hdmi_qp_rockchip_get_vop_format(struct drm_encoder *encoder,
+					      struct drm_connector_state *conn_state)
+{
+	struct drm_bridge *bridge __free(drm_bridge_put) = NULL;
+	struct drm_bridge_state *bstate;
+
+	bridge = drm_bridge_chain_get_first_bridge(encoder);
+	if (!bridge)
+		return -ENODEV;
+
+	bstate = drm_atomic_get_bridge_state(conn_state->state, bridge);
+	if (IS_ERR(bstate))
+		return PTR_ERR(bstate);
+
+	if (bstate->input_bus_cfg.format != MEDIA_BUS_FMT_FIXED)
+		return bstate->input_bus_cfg.format;
+
+	return bstate->output_bus_cfg.format;
+}
+
 static int
 dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder,
 					 struct drm_crtc_state *crtc_state,
 					 struct drm_connector_state *conn_state)
 {
-	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+	struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder);
 	union phy_configure_opts phy_cfg = {};
+	int ingest_fmt;
 	int ret;
 
+	ingest_fmt = dw_hdmi_qp_rockchip_get_vop_format(encoder, conn_state);
+	if (ingest_fmt < 0)
+		return -EINVAL;
+
 	if (hdmi->tmds_char_rate == conn_state->hdmi.tmds_char_rate &&
-	    s->output_bpc == conn_state->hdmi.output_bpc)
+	    s->output_bpc == conn_state->hdmi.output_bpc &&
+	    s->bus_format == ingest_fmt)
 		return 0;
 
+	switch (ingest_fmt) {
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB101010_1X30:
+	case MEDIA_BUS_FMT_YUV8_1X24:
+	case MEDIA_BUS_FMT_YUV10_1X30:
+		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+		break;
+	case MEDIA_BUS_FMT_UYVY8_1X16:
+		s->output_mode = ROCKCHIP_OUT_MODE_YUV422;
+		break;
+	case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+	case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+		s->output_mode = ROCKCHIP_OUT_MODE_YUV420;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	phy_cfg.hdmi.tmds_char_rate = conn_state->hdmi.tmds_char_rate;
 	phy_cfg.hdmi.bpc = conn_state->hdmi.output_bpc;
 
 	ret = phy_configure(hdmi->phy, &phy_cfg);
 	if (!ret) {
 		hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate;
-		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
 		s->output_type = DRM_MODE_CONNECTOR_HDMIA;
 		s->output_bpc = conn_state->hdmi.output_bpc;
+		s->bus_format = ingest_fmt;
 	} else {
 		dev_err(hdmi->dev, "Failed to configure phy: %d\n", ret);
 	}
@@ -383,6 +464,7 @@ static void dw_hdmi_qp_rk3588_io_init(struct rockchip_hdmi_qp *hdmi)
 static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
 				       struct rockchip_crtc_state *state)
 {
+	int color = dw_hdmi_qp_rockchip_bus_fmt_to_reg(state->bus_format);
 	u32 val;
 
 	if (state->output_bpc == 10)
@@ -390,12 +472,16 @@ static void dw_hdmi_qp_rk3576_enc_init(struct rockchip_hdmi_qp *hdmi,
 	else
 		val = FIELD_PREP_WM16(RK3576_COLOR_DEPTH_MASK, RK3576_8BPC);
 
+	if (likely(color >= 0))
+		val |= FIELD_PREP_WM16(RK3576_COLOR_FORMAT_MASK, color);
+
 	regmap_write(hdmi->vo_regmap, RK3576_VO0_GRF_SOC_CON8, val);
 }
 
 static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
 				       struct rockchip_crtc_state *state)
 {
+	int color = dw_hdmi_qp_rockchip_bus_fmt_to_reg(state->bus_format);
 	u32 val;
 
 	if (state->output_bpc == 10)
@@ -403,6 +489,9 @@ static void dw_hdmi_qp_rk3588_enc_init(struct rockchip_hdmi_qp *hdmi,
 	else
 		val = FIELD_PREP_WM16(RK3588_COLOR_DEPTH_MASK, RK3588_8BPC);
 
+	if (likely(color >= 0))
+		val |= FIELD_PREP_WM16(RK3588_COLOR_FORMAT_MASK, color);
+
 	regmap_write(hdmi->vo_regmap,
 		     hdmi->port_id ? RK3588_GRF_VO1_CON6 : RK3588_GRF_VO1_CON3,
 		     val);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:04 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:04 +0200
Subject: [PATCH v17 17/28] drm/rockchip: dw_hdmi_qp: Set supported_formats
 platdata
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-17-35739b5782cc@collabora.com>

With the introduction of the supported_formats member in the
dw-hdmi-qp platform data struct, drivers that have access to this
information should now set it.

Set it in the rockchip dw_hdmi_qp glue driver.

This allows this information to be passed down to the dw-hdmi-qp core,
which sets it in the bridge it creates, and consequently will allow the
common HDMI bridge code to act on it.

Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
index b77ef92ae954..815f9ea7bcbe 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
@@ -602,6 +602,10 @@ static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master,
 	plat_data.phy_data = hdmi;
 	plat_data.max_bpc = 10;
 
+	plat_data.supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+				      BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+				      BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422);
+
 	encoder = &hdmi->encoder.encoder;
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
 

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:05 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:05 +0200
Subject: [PATCH v17 18/28] drm/connector: Register color format property on
 HDMI connectors
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-18-35739b5782cc@collabora.com>

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>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov at oss.qualcomm.com>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/drm_connector.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 95c65ed18709..26d7449d0feb 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -636,6 +636,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
 	if (max_bpc > 8)
 		drm_connector_attach_hdr_output_metadata_property(connector);
 
+	ret = drm_connector_attach_color_format_property(connector, supported_formats);
+	if (ret)
+		return ret;
+
 	connector->hdmi.funcs = hdmi_funcs;
 
 	return 0;

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:06 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:06 +0200
Subject: [PATCH v17 19/28] drm/tests: hdmi: Add tests for the color_format
 property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-19-35739b5782cc@collabora.com>

Add some KUnit tests to check the color_format property is working as
expected with the HDMI state helper.

Existing tests are extended to also test the
DRM_CONNECTOR_COLOR_FORMAT_AUTO case, in order to avoid duplicating test
cases. For the explicitly selected color format cases, parameterized
tests are added.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 236 +++++++++++++++++++++
 1 file changed, 236 insertions(+)

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 e89e1af7a811..8eaca9b5b0fe 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -60,6 +60,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)
 {
@@ -1547,6 +1564,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_yuv420(struct kunit *test)
  *   RGB/10bpc
  * - The chosen mode has a TMDS character rate lower than the display
  *   supports in YUV422/12bpc.
+ * - The HDMI connector state's color format property is unset (i.e. AUTO)
  *
  * Then we will prefer to keep the RGB format with a lower bpc over
  * picking YUV422.
@@ -1609,6 +1627,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
 
 	conn_state = conn->state;
 	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+	KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
 
 	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 10);
 	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
@@ -1626,6 +1645,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422(struct kunit
  *   RGB/8bpc
  * - The chosen mode has a TMDS character rate lower than the display
  *   supports in YUV420/12bpc.
+ * - The HDMI connector state's color format property is unset (i.e. AUTO)
  *
  * Then we will prefer to keep the RGB format with a lower bpc over
  * picking YUV420.
@@ -1687,6 +1707,7 @@ static void drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420(struct kunit
 
 	conn_state = conn->state;
 	KUNIT_ASSERT_NOT_NULL(test, conn_state);
+	KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
 
 	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_bpc, 8);
 	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
@@ -2198,6 +2219,217 @@ static void drm_test_check_disable_connector(struct kunit *test)
 	drm_modeset_acquire_fini(&ctx);
 }
 
+struct color_format_test_param {
+	enum drm_connector_color_format fmt;
+	enum drm_output_color_format expected;
+	int expected_ret;
+	const char *desc;
+};
+
+/* Test that if:
+ * - an HDMI connector supports RGB, YUV444, YUV422, and YUV420
+ * - the display supports RGB, YUV444, YUV422, and YUV420
+ * - the "color format" property is set
+ * then, for the preferred mode, for a given "color format" option:
+ * - DRM_CONNECTOR_COLOR_FORMAT_AUTO results in an output format of RGB
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR422 results in an output format of YUV422
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 results in an output format of YUV420
+ * - DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 results in an output format of YUV444
+ * - DRM_CONNECTOR_COLOR_FORMAT_RGB results in an HDMI output format of RGB
+ */
+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_modeset_acquire_ctx ctx;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *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(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
+				12,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	KUNIT_ASSERT_TRUE(test, priv->connector.ycbcr_420_allowed);
+
+	info = &priv->connector.display_info;
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+	preferred = find_preferred_mode(&priv->connector);
+	KUNIT_ASSERT_TRUE(test, drm_mode_is_420(info, preferred));
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	conn_state = drm_atomic_get_connector_state(state, &priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	conn_state->color_format = param->fmt;
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, preferred);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_EXPECT_EQ(test, ret, param->expected_ret);
+	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+static const struct color_format_test_param hdmi_color_format_params[] = {
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_AUTO,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+		.expected_ret = 0,
+		.desc = "AUTO -> RGB"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
+		.expected_ret = 0,
+		.desc = "YCBCR422 -> YUV422"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+		.expected_ret = 0,
+		.desc = "YCBCR420 -> YUV420"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
+		.expected_ret = 0,
+		.desc = "YCBCR444 -> YUV444"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+		.expected_ret = 0,
+		.desc = "RGB -> RGB"
+	},
+};
+
+KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format, hdmi_color_format_params, desc);
+
+/* Test that if:
+ * - the HDMI connector supports RGB, YUV422, YUV420, and YUV444
+ * - the display has a YUV420-only mode
+ * - the "color format" property is explicitly set (i.e. !AUTO)
+ * then:
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_RGB444 will fail
+ *   drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 will fail
+ *   drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR422 will fail
+ *   drm_atomic_check_only for the YUV420-only mode with -EINVAL
+ * - color format DRM_CONNECTOR_COLOR_FORMAT_YCBCR420 passes
+ *   drm_atomic_check_only for the YUV420-only mode
+ */
+static void drm_test_check_hdmi_color_format_420_only(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_modeset_acquire_ctx ctx;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *dank;
+	int ret;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420) |
+				BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
+				12,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	dank = find_420_only_mode(&priv->connector);
+	KUNIT_ASSERT_NOT_NULL(test, dank);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+	conn_state = drm_atomic_get_connector_state(state, &priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	conn_state->color_format = param->fmt;
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, dank);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_check_only(state);
+	KUNIT_EXPECT_EQ(test, ret, param->expected_ret);
+	if (!param->expected_ret)
+		KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, param->expected);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+};
+
+static const struct color_format_test_param hdmi_color_format_420_only_params[] = {
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_RGB444,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_RGB444,
+		.expected_ret = -EINVAL,
+		.desc = "RGB should fail"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
+		.expected_ret = -EINVAL,
+		.desc = "YUV444 should fail"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
+		.expected_ret = -EINVAL,
+		.desc = "YUV422 should fail"
+	},
+	{
+		.fmt = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420,
+		.expected = DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
+		.expected_ret = 0,
+		.desc = "YUV420 should work"
+	},
+};
+
+KUNIT_ARRAY_PARAM_DESC(check_hdmi_color_format_420_only,
+		       hdmi_color_format_420_only_params, desc);
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
 	KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode),
 	KUNIT_CASE(drm_test_check_broadcast_rgb_auto_cea_mode_vic_1),
@@ -2227,6 +2459,10 @@ static struct kunit_case drm_atomic_helper_connector_hdmi_check_tests[] = {
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_8bpc),
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_10bpc),
 	KUNIT_CASE(drm_test_check_tmds_char_rate_rgb_12bpc),
+	KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format,
+			 check_hdmi_color_format_gen_params),
+	KUNIT_CASE_PARAM(drm_test_check_hdmi_color_format_420_only,
+			 check_hdmi_color_format_420_only_gen_params),
 	/*
 	 * TODO: We should have tests to check that a change in the
 	 * format triggers a CRTC mode change just like we do for the

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:07 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:07 +0200
Subject: [PATCH v17 20/28] drm/tests: hdmi: Add tests for HDMI helper's
 mode_valid
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-20-35739b5782cc@collabora.com>

Add some KUnit tests to verify that the HDMI state helper's mode_valid
implementation does not improperly reject chroma subsampled modes on the
basis of their clock rate not being satisfiable in RGB.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 109 +++++++++++++++++++++
 1 file changed, 109 insertions(+)

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 8eaca9b5b0fe..353a261d42da 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -77,6 +77,23 @@ static struct drm_display_mode *find_420_only_mode(struct drm_connector *connect
 	return NULL;
 }
 
+static struct drm_display_mode *find_420_also_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_also(&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)
 {
@@ -2745,11 +2762,103 @@ static void drm_test_check_mode_valid_reject_max_clock(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, preferred->clock, 25200);
 }
 
+/*
+ * Test that drm_hdmi_connector_mode_valid() will accept modes that require a
+ * 4:2:0 chroma subsampling, even if said mode would violate maximum clock
+ * constraints if it used RGB 4:4:4.
+ */
+static void drm_test_check_mode_valid_yuv420_only_max_clock(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_display_mode *dank;
+	struct drm_connector *conn;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB) |
+				BIT(HDMI_COLORSPACE_YUV420),
+				8,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	conn = &priv->connector;
+	KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+	dank = find_420_only_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, dank);
+	KUNIT_EXPECT_EQ(test, dank->hdisplay, 3840);
+	KUNIT_EXPECT_EQ(test, dank->vdisplay, 2160);
+
+	/*
+	 * Note: The mode's "clock" here is not accurate to the actual TMDS
+	 * clock that HDMI will use for a subsampled mode. Hence, why the mode's
+	 * clock is above the .max_tmds_clock of 200MHz.
+	 */
+	KUNIT_EXPECT_EQ(test, dank->clock, 297000);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will reject modes that require
+ * 4:2:0 chroma subsampling, if the connector does not support 4:2:0.
+ */
+static void
+drm_test_check_mode_valid_reject_yuv420_only_connector(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_display_mode *dank;
+	struct drm_connector *conn;
+
+	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_yuv_4k_yuv420_dc_max_200mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	conn = &priv->connector;
+	KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 200 * 1000);
+
+	dank = find_420_only_mode(conn);
+	KUNIT_EXPECT_NULL(test, dank);
+}
+
+/*
+ * Test that drm_hdmi_connector_mode_valid() will accept modes that allow (among
+ * other color formats) 4:2:0 chroma subsampling, even if the connector does not
+ * support 4:2:0, but the mode's clock works for RGB 4:4:4.
+ */
+static void
+drm_test_check_mode_valid_accept_yuv420_also_connector_rgb(struct kunit *test)
+{
+	struct drm_atomic_helper_connector_hdmi_priv *priv;
+	struct drm_display_mode *mode;
+	struct drm_connector *conn;
+
+	priv = drm_kunit_helper_connector_hdmi_init_with_edid_funcs(test,
+				BIT(HDMI_COLORSPACE_RGB),
+				8,
+				&dummy_connector_hdmi_funcs,
+				test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz);
+	KUNIT_ASSERT_NOT_NULL(test, priv);
+
+	conn = &priv->connector;
+	KUNIT_ASSERT_EQ(test, conn->display_info.max_tmds_clock, 340 * 1000);
+
+	mode = find_420_also_mode(conn);
+	KUNIT_ASSERT_NOT_NULL(test, mode);
+	KUNIT_EXPECT_EQ(test, mode->hdisplay, 3840);
+	KUNIT_EXPECT_EQ(test, mode->vdisplay, 2160);
+	KUNIT_EXPECT_EQ(test, mode->clock, 297000);
+}
+
 static struct kunit_case drm_atomic_helper_connector_hdmi_mode_valid_tests[] = {
 	KUNIT_CASE(drm_test_check_mode_valid),
 	KUNIT_CASE(drm_test_check_mode_valid_reject),
 	KUNIT_CASE(drm_test_check_mode_valid_reject_rate),
 	KUNIT_CASE(drm_test_check_mode_valid_reject_max_clock),
+	KUNIT_CASE(drm_test_check_mode_valid_yuv420_only_max_clock),
+	KUNIT_CASE(drm_test_check_mode_valid_reject_yuv420_only_connector),
+	KUNIT_CASE(drm_test_check_mode_valid_accept_yuv420_also_connector_rgb),
 	{ }
 };
 

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:08 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:08 +0200
Subject: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge
 chain format selection
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-21-35739b5782cc@collabora.com>

With the "color format" property, the bridge chain format selection has
gained increased complexity. Instead of simply finding any sequence of
bus formats that works, the bridge chain format selection needs to pick
a sequence that results in the requested color format.

Add KUnit tests for this new logic. These take the form of some pleasant
preprocessor macros to make it less cumbersome to define test bridges
with a set of possible input and output formats.

The input and output formats are defined for bridges in the form of
tuples, where the first member defines the input format, and the second
member defines the output format that can be produced from this input
format. This means the tests can construct scenarios in which not all
inputs can be converted to all outputs.

Some tests are added to test interesting scenarios to exercise the bus
format selection in the presence of a specific color format request.

Furthermore, tests are added to verify that bridge chains that end in an
HDMI connector will always prefer RGB when the color format is
DRM_CONNECTOR_COLOR_FORMAT_AUTO, as is the behaviour in the HDMI state
helpers.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/tests/drm_bridge_test.c | 787 ++++++++++++++++++++++++++++++++
 1 file changed, 787 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 64b665580a88..92f142ca6695 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -2,15 +2,23 @@
 /*
  * Kunit test for drm_bridge functions
  */
+#include <linux/cleanup.h>
+#include <linux/media-bus-format.h>
+
 #include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
 #include <drm/drm_bridge_helper.h>
+#include <drm/drm_edid.h>
 #include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
 
 #include <kunit/device.h>
 #include <kunit/test.h>
 
+#include "drm_kunit_edid.h"
+
 /*
  * Mimick the typical "private" struct defined by a bridge driver, which
  * embeds a bridge plus other fields.
@@ -37,6 +45,21 @@ struct drm_bridge_init_priv {
 	bool destroyed;
 };
 
+struct drm_bridge_chain_priv {
+	struct drm_device drm;
+	struct drm_encoder encoder;
+	struct drm_plane *plane;
+	struct drm_crtc *crtc;
+	struct drm_connector *connector;
+	unsigned int num_bridges;
+
+	/**
+	 * @test_bridges: array of pointers to &struct drm_bridge_priv entries
+	 *                of which the first @num_bridges entries are valid.
+	 */
+	struct drm_bridge_priv **test_bridges;
+};
+
 static struct drm_bridge_priv *bridge_to_priv(struct drm_bridge *bridge)
 {
 	return container_of(bridge, struct drm_bridge_priv, bridge);
@@ -95,6 +118,229 @@ static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
 	.atomic_reset		= drm_atomic_helper_bridge_reset,
 };
 
+/**
+ * struct fmt_tuple - a tuple of input/output MEDIA_BUS_FMT_*
+ */
+struct fmt_tuple {
+	u32 in_fmt;
+	u32 out_fmt;
+};
+
+/*
+ * Format mapping that only accepts RGB888, and outputs only RGB888
+ */
+static const struct fmt_tuple rgb8_passthrough[] = {
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+/*
+ * Format mapping that only accepts YUV444, and outputs only YUV444
+ */
+static const struct fmt_tuple yuv8_passthrough[] = {
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_YUV8_1X24 },
+};
+
+/*
+ * Format mapping where 8bpc RGB -> 8bpc YUV444, or ID(RGB) or ID(YUV444)
+ */
+static const struct fmt_tuple rgb8_to_yuv8_or_id[] = {
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+};
+
+static const struct fmt_tuple rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420[] = {
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_UYVY8_1X16 },
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_UYYVYY8_0_5X24 },
+};
+
+/*
+ * Format mapping where 8bpc YUV444 -> 8bpc RGB, or ID(YUV444)
+ */
+static const struct fmt_tuple yuv8_to_rgb8_or_id[] = {
+	{ MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+/*
+ * A format mapping that acts like a video processor that generates an RGB signal
+ */
+static const struct fmt_tuple rgb_producer[] = {
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB101010_1X30 },
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB121212_1X36 },
+};
+
+/*
+ * A format mapping that acts like a video processor that generates an 8-bit RGB,
+ * YUV444 or YUV420 signal
+ */
+static const struct fmt_tuple rgb_yuv444_yuv420_producer[] = {
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_UYYVYY8_0_5X24 },
+};
+
+static const struct fmt_tuple rgb8_yuv444_yuv422_passthrough[] = {
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_UYVY8_1X16,  MEDIA_BUS_FMT_UYVY8_1X16 },
+};
+
+static const struct fmt_tuple yuv444_yuv422_rgb8_passthrough[] = {
+	{ MEDIA_BUS_FMT_YUV8_1X24,   MEDIA_BUS_FMT_YUV8_1X24 },
+	{ MEDIA_BUS_FMT_UYVY8_1X16,  MEDIA_BUS_FMT_UYVY8_1X16 },
+	{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+};
+
+static bool fmt_in_list(const u32 fmt, const u32 *out_fmts, const size_t num_fmts)
+{
+	size_t i;
+
+	for (i = 0; i < num_fmts; i++)
+		if (out_fmts[i] == fmt)
+			return true;
+
+	return false;
+}
+
+/**
+ * get_tuples_out_fmts - Get unique output formats of a &struct fmt_tuple list
+ * @fmt_tuples: array of &struct fmt_tuple
+ * @num_fmt_tuples: number of entries in @fmt_tuples
+ * @out_fmts: target array to store the unique output bus formats
+ *
+ * Returns the number of unique output formats, i.e. the number of entries in
+ * @out_fmts that were populated with sensible values.
+ */
+static size_t get_tuples_out_fmts(const struct fmt_tuple *fmt_tuples,
+				  const size_t num_fmt_tuples, u32 *out_fmts)
+{
+	size_t num_unique = 0;
+	size_t i;
+
+	for (i = 0; i < num_fmt_tuples; i++)
+		if (!fmt_in_list(fmt_tuples[i].out_fmt, out_fmts, num_unique))
+			out_fmts[num_unique++] = fmt_tuples[i].out_fmt;
+
+	return num_unique;
+}
+
+#define DEFINE_FMT_FUNCS_FROM_TUPLES(name) \
+static u32 *drm_test_bridge_ ## name ## _out_fmts(struct drm_bridge *bridge,			\
+						  struct drm_bridge_state *bridge_state,	\
+						  struct drm_crtc_state *crtc_state,		\
+						  struct drm_connector_state *conn_state,	\
+						  unsigned int *num_output_fmts)		\
+{												\
+	u32 *out_fmts = kcalloc(ARRAY_SIZE((name)), sizeof(u32), GFP_KERNEL);			\
+												\
+	if (out_fmts)										\
+		*num_output_fmts = get_tuples_out_fmts((name), ARRAY_SIZE((name)), out_fmts);	\
+	else											\
+		*num_output_fmts = 0;								\
+												\
+	return out_fmts;									\
+}												\
+												\
+static u32 *drm_test_bridge_ ## name ## _in_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 *in_fmts = kcalloc(ARRAY_SIZE((name)), sizeof(u32), GFP_KERNEL);			\
+	unsigned int num_fmts = 0;								\
+	size_t i;										\
+												\
+	if (!in_fmts) {										\
+		*num_input_fmts = 0;								\
+		return NULL;									\
+	}											\
+												\
+	for (i = 0; i < ARRAY_SIZE((name)); i++)						\
+		if ((name)[i].out_fmt == output_fmt)						\
+			in_fmts[num_fmts++] = (name)[i].in_fmt;					\
+												\
+	*num_input_fmts = num_fmts;								\
+												\
+	return in_fmts;										\
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(ident, input_fmts_func, output_fmts_func,	\
+						 hdmi_write_infoframe_func,			\
+						 hdmi_clear_infoframe_func)			\
+static const struct drm_bridge_funcs (ident) = {						\
+	.atomic_enable			= drm_test_bridge_atomic_enable,			\
+	.atomic_disable			= drm_test_bridge_atomic_disable,			\
+	.atomic_destroy_state		= drm_atomic_helper_bridge_destroy_state,		\
+	.atomic_duplicate_state		= drm_atomic_helper_bridge_duplicate_state,		\
+	.atomic_reset			= drm_atomic_helper_bridge_reset,			\
+	.atomic_get_input_bus_fmts	= (input_fmts_func),					\
+	.atomic_get_output_bus_fmts	= (output_fmts_func),					\
+	.hdmi_write_avi_infoframe	= (hdmi_write_infoframe_func),				\
+	.hdmi_clear_avi_infoframe	= (hdmi_clear_infoframe_func),				\
+	.hdmi_write_hdmi_infoframe	= (hdmi_write_infoframe_func),				\
+	.hdmi_clear_hdmi_infoframe	= (hdmi_clear_infoframe_func),				\
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_FUNC(ident, input_fmts_func, output_fmts_func)		\
+	DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(ident, input_fmts_func, output_fmts_func,	\
+						 NULL, NULL)
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(_name)						\
+	DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_FUNC(_name ## _funcs,				\
+					    drm_test_bridge_ ## _name ## _in_fmts,	\
+					    drm_test_bridge_ ## _name ## _out_fmts)
+
+static int drm_test_bridge_write_infoframe_stub(struct drm_bridge *bridge,
+						const u8 *buffer, size_t len)
+{
+	return 0;
+}
+
+static int drm_test_bridge_clear_infoframe_stub(struct drm_bridge *bridge)
+{
+	return 0;
+}
+
+#define DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI(_name)						\
+	DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI_FUNC(_name ## _hdmi ## _funcs,			\
+						 drm_test_bridge_ ## _name ## _in_fmts,		\
+						 drm_test_bridge_ ## _name ## _out_fmts,	\
+						 drm_test_bridge_write_infoframe_stub,		\
+						 drm_test_bridge_clear_infoframe_stub)
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv8_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_to_yuv8_or_id)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_to_yuv8_or_id);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv8_to_rgb8_or_id)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv8_to_rgb8_or_id);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb_producer)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb_producer);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb_yuv444_yuv420_producer)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb_yuv444_yuv420_producer);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(rgb8_yuv444_yuv422_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(rgb8_yuv444_yuv422_passthrough);
+
+DEFINE_FMT_FUNCS_FROM_TUPLES(yuv444_yuv422_rgb8_passthrough)
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT(yuv444_yuv422_rgb8_passthrough);
+DRM_BRIDGE_ATOMIC_WITH_BUS_FMT_HDMI(yuv444_yuv422_rgb8_passthrough);
+
 KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
 			    drm_bridge_remove,
 			    struct drm_bridge *);
@@ -178,6 +424,119 @@ drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
 	return priv;
 }
 
+static struct drm_bridge_chain_priv *
+drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
+			   const struct drm_bridge_funcs **funcs)
+{
+	struct drm_bridge_chain_priv *priv;
+	const struct drm_edid *edid;
+	struct drm_bridge *prev;
+	struct drm_encoder *enc;
+	struct drm_bridge *bridge;
+	struct drm_device *drm;
+	bool has_hdmi = false;
+	struct device *dev;
+	unsigned int i;
+	int ret;
+
+	dev = drm_kunit_helper_alloc_device(test);
+	if (IS_ERR(dev))
+		return ERR_CAST(dev);
+
+	priv = drm_kunit_helper_alloc_drm_device(test, dev, struct drm_bridge_chain_priv,
+						 drm, DRIVER_MODESET | DRIVER_ATOMIC);
+	if (IS_ERR(priv))
+		return ERR_CAST(priv);
+
+	drm = &priv->drm;
+
+	priv->test_bridges = drmm_kmalloc_array(drm, num_bridges, sizeof(*priv->test_bridges),
+						GFP_KERNEL);
+	if (!priv->test_bridges)
+		return ERR_PTR(-ENOMEM);
+
+	priv->num_bridges = num_bridges;
+
+	for (i = 0; i < num_bridges; i++) {
+		priv->test_bridges[i] = devm_drm_bridge_alloc(dev, struct drm_bridge_priv,
+							      bridge, funcs[i]);
+		if (IS_ERR(priv->test_bridges[i]))
+			return ERR_CAST(priv->test_bridges[i]);
+
+		priv->test_bridges[i]->data = priv;
+	}
+
+	priv->plane = drm_kunit_helper_create_primary_plane(test, drm, NULL, NULL,
+							    NULL, 0, NULL);
+	if (IS_ERR(priv->plane))
+		return ERR_CAST(priv->plane);
+
+	priv->crtc = drm_kunit_helper_create_crtc(test, drm, priv->plane, NULL,
+						  NULL, NULL);
+	if (IS_ERR(priv->crtc))
+		return ERR_CAST(priv->crtc);
+
+	enc = &priv->encoder;
+	ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	enc->possible_crtcs = drm_crtc_mask(priv->crtc);
+
+	prev = NULL;
+	for (i = 0; i < num_bridges; i++) {
+		bridge = &priv->test_bridges[i]->bridge;
+		bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
+
+		if (bridge->funcs->hdmi_write_hdmi_infoframe) {
+			has_hdmi = true;
+			bridge->ops |= DRM_BRIDGE_OP_HDMI;
+			bridge->type = DRM_MODE_CONNECTOR_HDMIA;
+			bridge->vendor = "LNX";
+			bridge->product = "KUnit";
+			bridge->supported_formats = (BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+						     BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+						     BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
+						     BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420));
+		}
+
+		ret = drm_kunit_bridge_add(test, bridge);
+		if (ret)
+			return ERR_PTR(ret);
+
+		ret = drm_bridge_attach(enc, bridge, prev, 0);
+		if (ret)
+			return ERR_PTR(ret);
+
+		prev = bridge;
+	}
+
+	priv->connector = drm_bridge_connector_init(drm, enc);
+	if (IS_ERR(priv->connector))
+		return ERR_CAST(priv->connector);
+
+	drm_connector_attach_encoder(priv->connector, enc);
+
+	drm_mode_config_reset(drm);
+
+	if (!has_hdmi)
+		return priv;
+
+	scoped_guard(mutex, &drm->mode_config.mutex) {
+		edid = drm_edid_alloc(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz,
+				ARRAY_SIZE(test_edid_hdmi_1080p_rgb_yuv_4k_yuv420_dc_max_200mhz));
+		if (!edid)
+			return ERR_PTR(-EINVAL);
+
+		drm_edid_connector_update(priv->connector, edid);
+		KUNIT_ASSERT_GT(test, drm_edid_connector_add_modes(priv->connector), 0);
+
+		ret = priv->connector->funcs->fill_modes(priv->connector, 4096, 4096);
+	}
+
+	return priv;
+}
+
 /*
  * Test that drm_bridge_get_current_state() returns the last committed
  * state for an atomic bridge.
@@ -506,14 +865,442 @@ static struct kunit_suite drm_bridge_alloc_test_suite = {
 	.test_cases = drm_bridge_alloc_tests,
 };
 
+/**
+ * drm_test_bridge_chain_verify_fmt - Verify bridge chain format selection
+ * @test: pointer to KUnit test object
+ * @priv: pointer to a &struct drm_bridge_chain_priv for this chain
+ * @expected: constant array of &struct fmt_tuple describing the expected
+ *            input and output bus formats
+ * @num_expected: number of entries in @expected
+ *
+ * Runs the KUNIT_EXPECT clauses to verify the bridge chain format selection
+ * resulted in the expected formats. If %0 is given as a format in a
+ * &struct fmt_tuple, then it is understood to mean "any".
+ *
+ * Must be called with the modeset lock held.
+ */
+static void drm_test_bridge_chain_verify_fmt(struct kunit *test,
+					     struct drm_bridge_chain_priv *priv,
+					     const struct fmt_tuple *const expected,
+					     const unsigned int num_expected)
+{
+	struct drm_bridge_state *bstate;
+	unsigned int i = 0;
+
+	drm_for_each_bridge_in_chain_scoped(&priv->encoder, bridge) {
+		KUNIT_ASSERT_LT(test, i, num_expected);
+
+		bstate = drm_bridge_get_current_state(bridge);
+		if (expected[i].in_fmt)
+			KUNIT_EXPECT_EQ(test, bstate->input_bus_cfg.format,
+					expected[i].in_fmt);
+		if (expected[i].out_fmt)
+			KUNIT_EXPECT_EQ(test, bstate->output_bus_cfg.format,
+					expected[i].out_fmt);
+
+		i++;
+	}
+
+	KUNIT_ASSERT_EQ_MSG(test, i, num_expected,
+			    "Fewer bridges (%u) than expected (%u)\n", i, num_expected);
+}
+
+/*
+ * Test that constructs a bridge chain in which an RGB888 producer is chained to
+ * two bridges that will convert from RGB to YUV and from YUV to RGB respectively.
+ *
+ * The test requests an output color_format of RGB using the color_format property,
+ * so to satisfy this request, the bridge chain must take a detour over YUV.
+ */
+static void drm_test_bridge_rgb_yuv_rgb(struct kunit *test)
+{
+	static const struct drm_bridge_funcs *funcs[] = {
+		&rgb_producer_funcs,
+		&rgb8_to_yuv8_or_id_funcs,
+		&yuv8_to_rgb8_or_id_funcs,
+	};
+	static const struct fmt_tuple expected[] = {
+		{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+		{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+		{ MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+	};
+	struct drm_connector_state *conn_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_chain_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	int ret;
+
+	priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	conn_state->color_format = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test in which a bridge capable of producing RGB, YUV444 and YUV420 has to
+ * produce RGB and convert with a downstream bridge in the chain to reach the
+ * requested YUV444 color format, as no direct path exists between its YUV444
+ * and the last bridge.
+ *
+ * The rationale behind this test is to devise a scenario in which naively
+ * assuming any format the video processor can output, and the connector
+ * requests, is the right format to pick, does not work.
+ */
+static void drm_test_bridge_must_convert_to_yuv444(struct kunit *test)
+{
+	static const struct drm_bridge_funcs *funcs[] = {
+		&rgb_yuv444_yuv420_producer_funcs,
+		&rgb8_passthrough_funcs,
+		&rgb8_to_id_yuv8_or_yuv8_to_yuv422_yuv420_funcs,
+		&rgb8_yuv444_yuv422_passthrough_funcs,
+	};
+	static const struct fmt_tuple expected[] = {
+		{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+		{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+		{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+		{ MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+	};
+	struct drm_connector_state *conn_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_chain_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	int ret;
+
+	priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	conn_state->color_format = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that no matter the order of bus formats returned by an
+ * HDMI bridge, RGB is preferred on DRM_CONNECTOR_COLOR_FORMAT_AUTO if it's
+ * available.
+ */
+static void drm_test_bridge_hdmi_auto_rgb(struct kunit *test)
+{
+	static const struct drm_bridge_funcs *funcs[] = {
+		&rgb_yuv444_yuv420_producer_funcs,
+		&yuv444_yuv422_rgb8_passthrough_hdmi_funcs,
+	};
+	static const struct fmt_tuple expected[] = {
+		{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_RGB888_1X24 },
+		{ MEDIA_BUS_FMT_RGB888_1X24, MEDIA_BUS_FMT_RGB888_1X24 },
+	};
+	struct drm_connector_state *conn_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_chain_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	int ret;
+
+	priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	KUNIT_EXPECT_EQ(test, conn_state->hdmi.output_format, DRM_OUTPUT_COLOR_FORMAT_RGB444);
+
+	drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that DRM_CONNECTOR_COLOR_FORMAT_AUTO on non-HDMI connectors
+ * will result in the first bus format on the output to be picked.
+ */
+static void drm_test_bridge_auto_first(struct kunit *test)
+{
+	static const struct drm_bridge_funcs *funcs[] = {
+		&rgb_yuv444_yuv420_producer_funcs,
+		&yuv444_yuv422_rgb8_passthrough_funcs,
+	};
+	static const struct fmt_tuple expected[] = {
+		{ MEDIA_BUS_FMT_FIXED, MEDIA_BUS_FMT_YUV8_1X24 },
+		{ MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_YUV8_1X24 },
+	};
+	struct drm_connector_state *conn_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_chain_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	int ret;
+
+	priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	KUNIT_ASSERT_EQ(test, conn_state->color_format, DRM_CONNECTOR_COLOR_FORMAT_AUTO);
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	drm_test_bridge_chain_verify_fmt(test, priv, expected, ARRAY_SIZE(expected));
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test which checks that in a configuration of bridge chains where an RGB
+ * producer is hooked to a YUV444-only pass-through, the atomic commit fails as
+ * the bridge format selection cannot find a valid sequence of bus formats.
+ */
+static void drm_test_bridge_rgb_yuv_no_path(struct kunit *test)
+{
+	static const struct drm_bridge_funcs *funcs[] = {
+		&rgb_producer_funcs,
+		&yuv8_passthrough_funcs,
+		&rgb8_yuv444_yuv422_passthrough_funcs,
+	};
+	struct drm_connector_state *conn_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_chain_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	int ret;
+
+	priv = drm_test_bridge_chain_init(test, ARRAY_SIZE(funcs), funcs);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_EXPECT_EQ(test, ret, -ENOTSUPP);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+static struct kunit_case drm_bridge_bus_fmt_tests[] = {
+	KUNIT_CASE(drm_test_bridge_rgb_yuv_rgb),
+	KUNIT_CASE(drm_test_bridge_must_convert_to_yuv444),
+	KUNIT_CASE(drm_test_bridge_hdmi_auto_rgb),
+	KUNIT_CASE(drm_test_bridge_auto_first),
+	KUNIT_CASE(drm_test_bridge_rgb_yuv_no_path),
+	{ }
+};
+
+static struct kunit_suite drm_bridge_bus_fmt_test_suite = {
+	.name = "drm_bridge_bus_fmt",
+	.test_cases = drm_bridge_bus_fmt_tests,
+};
+
 kunit_test_suites(
 	&drm_bridge_get_current_state_test_suite,
 	&drm_bridge_helper_reset_crtc_test_suite,
 	&drm_bridge_alloc_test_suite,
+	&drm_bridge_bus_fmt_test_suite,
 );
 
 MODULE_AUTHOR("Maxime Ripard <mripard at kernel.org>");
 MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli at bootlin.com>");
+MODULE_AUTHOR("Nicolas Frattaroli <nicolas.frattaroli at collabora.com>");
 
 MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
 MODULE_LICENSE("GPL");

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:09 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:09 +0200
Subject: [PATCH v17 22/28] drm/tests: bridge: Add test for HDMI output bus
 formats helper
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-22-35739b5782cc@collabora.com>

The common atomic_get_output_bus_fmts helper for HDMI bridge connectors,
called drm_atomic_helper_bridge_get_hdmi_output_bus_fmts, should return
an array of output bus formats depending on the supported formats of the
connector, and the current output BPC.

Add a test to exercise some of this helper.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/tests/drm_bridge_test.c | 184 ++++++++++++++++++++++++++++++++
 1 file changed, 184 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index 92f142ca6695..9d4fbe709df4 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -5,6 +5,7 @@
 #include <linux/cleanup.h>
 #include <linux/media-bus-format.h>
 
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_state_helper.h>
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_bridge.h>
@@ -118,6 +119,28 @@ static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
 	.atomic_reset		= drm_atomic_helper_bridge_reset,
 };
 
+static int dummy_clear_infoframe(struct drm_bridge *bridge)
+{
+	return 0;
+}
+
+static int dummy_write_infoframe(struct drm_bridge *bridge, const u8 *buffer,
+				 size_t len)
+{
+	return 0;
+}
+
+static const struct drm_bridge_funcs drm_test_bridge_bus_fmts_funcs = {
+	.atomic_get_output_bus_fmts	= drm_atomic_helper_bridge_get_hdmi_output_bus_fmts,
+	.atomic_destroy_state		= drm_atomic_helper_bridge_destroy_state,
+	.atomic_duplicate_state		= drm_atomic_helper_bridge_duplicate_state,
+	.atomic_reset			= drm_atomic_helper_bridge_reset,
+	.hdmi_write_avi_infoframe	= dummy_write_infoframe,
+	.hdmi_write_hdmi_infoframe	= dummy_write_infoframe,
+	.hdmi_clear_avi_infoframe	= dummy_clear_infoframe,
+	.hdmi_clear_hdmi_infoframe	= dummy_clear_infoframe,
+};
+
 /**
  * struct fmt_tuple - a tuple of input/output MEDIA_BUS_FMT_*
  */
@@ -537,6 +560,83 @@ drm_test_bridge_chain_init(struct kunit *test, unsigned int num_bridges,
 	return priv;
 }
 
+static struct drm_bridge_init_priv *
+drm_test_bridge_hdmi_init(struct kunit *test, const struct drm_bridge_funcs *funcs,
+			  unsigned int supported_formats, int max_bpc)
+{
+	struct drm_bridge_init_priv *priv;
+	struct drm_encoder *enc;
+	struct drm_bridge *bridge;
+	struct drm_device *drm;
+	struct device *dev;
+	int ret;
+
+	dev = drm_kunit_helper_alloc_device(test);
+	if (IS_ERR(dev))
+		return ERR_CAST(dev);
+
+	priv = drm_kunit_helper_alloc_drm_device(test, dev,
+						 struct drm_bridge_init_priv, drm,
+						 DRIVER_MODESET | DRIVER_ATOMIC);
+	if (IS_ERR(priv))
+		return ERR_CAST(priv);
+
+	priv->test_bridge = devm_drm_bridge_alloc(dev, struct drm_bridge_priv, bridge, funcs);
+	if (IS_ERR(priv->test_bridge))
+		return ERR_CAST(priv->test_bridge);
+
+	priv->test_bridge->data = priv;
+
+	drm = &priv->drm;
+	priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
+							    NULL,
+							    NULL,
+							    NULL, 0,
+							    NULL);
+	if (IS_ERR(priv->plane))
+		return ERR_CAST(priv->plane);
+
+	priv->crtc = drm_kunit_helper_create_crtc(test, drm,
+						  priv->plane, NULL,
+						  NULL,
+						  NULL);
+	if (IS_ERR(priv->crtc))
+		return ERR_CAST(priv->crtc);
+
+	enc = &priv->encoder;
+	ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	enc->possible_crtcs = drm_crtc_mask(priv->crtc);
+
+	bridge = &priv->test_bridge->bridge;
+	bridge->type = DRM_MODE_CONNECTOR_HDMIA;
+	bridge->supported_formats = supported_formats;
+	bridge->max_bpc = max_bpc;
+	bridge->ops |= DRM_BRIDGE_OP_HDMI;
+	bridge->vendor = "LNX";
+	bridge->product = "KUnit";
+
+	ret = drm_kunit_bridge_add(test, bridge);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = drm_bridge_attach(enc, bridge, NULL, 0);
+	if (ret)
+		return ERR_PTR(ret);
+
+	priv->connector = drm_bridge_connector_init(drm, enc);
+	if (IS_ERR(priv->connector))
+		return ERR_CAST(priv->connector);
+
+	drm_connector_attach_encoder(priv->connector, enc);
+
+	drm_mode_config_reset(drm);
+
+	return priv;
+}
+
 /*
  * Test that drm_bridge_get_current_state() returns the last committed
  * state for an atomic bridge.
@@ -784,10 +884,94 @@ static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, bridge_priv->disable_count, 1);
 }
 
+/*
+ * Test that a bridge using the drm_atomic_helper_bridge_get_hdmi_output_bus_fmts()
+ * function for &drm_bridge_funcs.atomic_get_output_bus_fmts behaves as expected
+ * for an HDMI connector bridge. Does so by creating an HDMI bridge connector
+ * with RGB444, YCBCR444, and YCBCR420 (but not YCBCR422) as supported formats,
+ * sets the output depth to 8 bits per component, and then validates the returned
+ * list of bus formats.
+ */
+static void drm_test_drm_bridge_helper_hdmi_output_bus_fmts(struct kunit *test)
+{
+	struct drm_connector_state *conn_state;
+	struct drm_bridge_state *bridge_state;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_bridge_init_priv *priv;
+	struct drm_crtc_state *crtc_state;
+	struct drm_atomic_commit *state;
+	struct drm_display_mode *mode;
+	unsigned int num_output_fmts;
+	struct drm_bridge *bridge;
+	u32 *out_bus_fmts;
+	int ret;
+
+	priv = drm_test_bridge_hdmi_init(test, &drm_test_bridge_bus_fmts_funcs,
+					 BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
+					 BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
+					 BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420),
+					 12);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+	bridge = &priv->test_bridge->bridge;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_kunit_helper_atomic_state_alloc(test, &priv->drm, &ctx);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+	conn_state = drm_atomic_get_connector_state(state, priv->connector);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+	conn_state->hdmi.output_bpc = 8;
+
+	mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+	ret = drm_atomic_set_crtc_for_connector(conn_state, priv->crtc);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state = drm_atomic_get_crtc_state(state, priv->crtc);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+	ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry_commit;
+	}
+	KUNIT_ASSERT_EQ(test, ret, 0);
+
+	crtc_state->enable = true;
+	crtc_state->active = true;
+
+	bridge_state = drm_atomic_get_bridge_state(state, bridge);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
+
+	out_bus_fmts = bridge->funcs->atomic_get_output_bus_fmts(
+		bridge, bridge_state, crtc_state, conn_state, &num_output_fmts);
+	KUNIT_EXPECT_NOT_NULL(test, out_bus_fmts);
+	KUNIT_EXPECT_EQ(test, num_output_fmts, 3);
+
+	KUNIT_EXPECT_EQ(test, out_bus_fmts[0], MEDIA_BUS_FMT_RGB888_1X24);
+	KUNIT_EXPECT_EQ(test, out_bus_fmts[1], MEDIA_BUS_FMT_YUV8_1X24);
+	KUNIT_EXPECT_EQ(test, out_bus_fmts[2], MEDIA_BUS_FMT_UYYVYY8_0_5X24);
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+
+	kfree(out_bus_fmts);
+}
+
 static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
 	KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
+	KUNIT_CASE(drm_test_drm_bridge_helper_hdmi_output_bus_fmts),
 	{ }
 };
 

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:10 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:10 +0200
Subject: [PATCH v17 23/28] drm/bridge: Document bridge chain format
 selection
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-23-35739b5782cc@collabora.com>

The bridge chain format selection behaviour was, until now,
undocumented. With the addition of the "color format" DRM property, it's
not sufficiently complex enough that documentation is warranted,
especially for driver authors trying to do the right thing.

Add a high-level overview of how the process is supposed to work, and
mention what the display driver is supposed to do if it wants to make
use of this functionality.

Reviewed-by: Maxime Ripard <mripard at kernel.org>
Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 Documentation/gpu/drm-kms-helpers.rst |  6 ++++++
 drivers/gpu/drm/drm_bridge.c          | 40 +++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 80453dda33b8..94cfc26acecc 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -171,6 +171,12 @@ Bridge Operations
 .. kernel-doc:: drivers/gpu/drm/drm_bridge.c
    :doc: bridge operations
 
+Bridge Chain Format Selection
+-----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :doc: bridge chain format selection
+
 Bridge Connector Helper
 -----------------------
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 9d6fcf986022..1daac8a7f4c9 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -198,6 +198,46 @@
  * driver.
  */
 
+/**
+ * DOC: bridge chain format selection
+ *
+ * A bridge chain, from display output processor to connector, may contain
+ * bridges capable of converting between bus formats on their inputs, and
+ * output formats on their outputs. For example, a bridge may be able to convert
+ * from RGB to YCbCr 4:4:4, and pass through YCbCr 4:2:0 as-is, but not convert
+ * from RGB to YCbCr 4:2:0. This means not all input formats map to all output
+ * formats.
+ *
+ * Further adding to this, a desired output color format, as specified with the
+ * "color format" DRM property, might not correspond 1:1 to what the display
+ * driver should set at its output. The bridge chain it feeds into may only be
+ * able to reach the desired output format, if a conversion from a different
+ * starting format is performed.
+ *
+ * To deal with this complexity, the recursive bridge chain bus format selection
+ * logic starts with the last bridge in the chain, usually the connector, and
+ * then recursively walks the chain of bridges backwards to the first bridge,
+ * trying to find a path.
+ *
+ * For a display driver to work in such a scenario, it should read the first
+ * bridge's bridge state to figure out which bus format the chain resolved to.
+ * If the first bridge's input format resolved to %MEDIA_BUS_FMT_FIXED, then its
+ * output format should be used.
+ *
+ * Special handling is done for HDMI as it relates to format selection. Instead
+ * of directly using the "color format" DRM property for bridge chains that end
+ * in HDMI bridges, the bridge chain format selection logic will trust the logic
+ * that set the HDMI output format. For the common HDMI state helper
+ * functionality, this means that %DRM_CONNECTOR_COLOR_FORMAT_AUTO will allow
+ * fallbacks to YCBCr 4:2:0 if the bandwidth requirements would otherwise be too
+ * high but the mode and connector allow it.
+ *
+ * For bridge chains that do not end in an HDMI bridge,
+ * %DRM_CONNECTOR_COLOR_FORMAT_AUTO will be satisfied with the first output
+ * format on the last bridge for which it can find a path back to the first
+ * bridge.
+ */
+
 /* Protect bridge_list and bridge_lingering_list */
 static DEFINE_MUTEX(bridge_lock);
 static LIST_HEAD(bridge_list);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:11 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:11 +0200
Subject: [PATCH v17 24/28] drm/connector: Update docs of "colorspace" for
 color format prop
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-24-35739b5782cc@collabora.com>

The colorspace property's documentation states that BT2020_RGB and
BT2020_YCC are equivalent, and the output format depends on the driver.

Now that there is a "color format" property that userspace can use to
explicitly set a format, update the colorspace docs to mention this.

The behaviour here is not changed for userspace that doesn't know about
the color format property yet, as the color format property defaults to
"AUTO", where the choice of output format is left up to drivers.

Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/drm_connector.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 26d7449d0feb..cbb067d02cb9 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -2582,7 +2582,8 @@ EXPORT_SYMBOL(drm_mode_create_aspect_ratio_property);
  *		conversion matrix and convert to the appropriate quantization
  *		range.
  *		The variants BT2020_RGB and BT2020_YCC are equivalent and the
- *		driver chooses between RGB and YCbCr on its own.
+ *		driver chooses between RGB and YCbCr based on the color format
+ *		property.
  *
  *	SMPTE_170M_YCC:
  *	BT709_YCC:

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:12 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:12 +0200
Subject: [PATCH v17 25/28] drm/i915/hdmi: Add YCBCR444 handling for sink
 formats
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-25-35739b5782cc@collabora.com>

In anticipation of userspace being able to explicitly select supported
sink formats, add handling of the YCBCR444 sink format. The AUTO path
does not choose this format, but with explicit format selection added to
the driver, it becomes a possibility.

Check for YCBCR444 support on the sink in sink_bpc_possible, and on the
source and sink in sink_format_valid.

Acked-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 9076c2b176ec..6c6a3a0677fe 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -1966,6 +1966,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
 
 		if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
 			return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36;
+		else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+			return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36;
 		else
 			return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36;
 	case 10:
@@ -1974,6 +1976,8 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *_connector,
 
 		if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR420)
 			return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30;
+		else if (sink_format == INTEL_OUTPUT_FORMAT_YCBCR444)
+			return info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30;
 		else
 			return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30;
 	case 8:
@@ -2021,6 +2025,17 @@ intel_hdmi_mode_clock_valid(struct drm_connector *_connector, int clock,
 	return status;
 }
 
+static bool
+intel_hdmi_can_ycbcr444(struct intel_connector *connector)
+{
+	const struct intel_display *display = to_intel_display(connector);
+
+	if (!HAS_GMCH(display))
+		return true;
+
+	return false;
+}
+
 static enum drm_mode_status
 intel_hdmi_sink_format_valid(struct intel_connector *connector,
 			     const struct drm_display_mode *mode,
@@ -2036,6 +2051,15 @@ intel_hdmi_sink_format_valid(struct intel_connector *connector,
 		    !drm_mode_is_420(info, mode))
 			return MODE_NO_420;
 
+		return MODE_OK;
+	case INTEL_OUTPUT_FORMAT_YCBCR444:
+		if (!has_hdmi_sink)
+			return MODE_BAD;
+		if (!intel_hdmi_can_ycbcr444(connector))
+			return MODE_BAD;
+		if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
+			return MODE_BAD;
+
 		return MODE_OK;
 	case INTEL_OUTPUT_FORMAT_RGB:
 		return MODE_OK;

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:13 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:13 +0200
Subject: [PATCH v17 26/28] drm/i915/dp: Add YCBCR444 handling for sink
 formats
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-26-35739b5782cc@collabora.com>

In anticipation of userspace being able to explicitly select supported
sink formats, add handling of the YCBCR444 sink format. The AUTO path
does not choose this format, but with explicit format selection added to
the driver, it becomes a possibility.

Check for both source and sink support of YCBCR444 in
intel_dp_sink_format_valid.

Acked-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index f01a6eed3839..7c69d3badf9f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1344,6 +1344,16 @@ intel_dp_mode_valid_downstream(struct intel_connector *connector,
 					 8, sink_format, true);
 }
 
+static bool
+intel_dp_can_ycbcr444(struct intel_dp *intel_dp)
+{
+	if (source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444) &&
+	    !drm_dp_is_branch(intel_dp->dpcd))
+		return true;
+
+	return false;
+}
+
 static enum drm_mode_status
 intel_dp_sink_format_valid(struct intel_connector *connector,
 			   const struct drm_display_mode *mode,
@@ -1362,6 +1372,16 @@ intel_dp_sink_format_valid(struct intel_connector *connector,
 		    !drm_mode_is_420(info, mode))
 			return MODE_NO_420;
 
+		return MODE_OK;
+	case INTEL_OUTPUT_FORMAT_YCBCR444:
+		if (intel_dp->dfp.min_tmds_clock &&
+		    !intel_dp_has_hdmi_sink(intel_dp))
+			return MODE_BAD;
+		if (!intel_dp_can_ycbcr444(intel_dp))
+			return MODE_BAD;
+		if (!(info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)))
+			return MODE_BAD;
+
 		return MODE_OK;
 	case INTEL_OUTPUT_FORMAT_RGB:
 		return MODE_OK;

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:14 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:14 +0200
Subject: [PATCH v17 27/28] drm/i915/hdmi: Implement "color format" DRM
 property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-27-35739b5782cc@collabora.com>

Implement the "color format" DRM property for HDMI. The values of the
property include RGB, YCbCr420, YCbCr444 and Auto. Auto will pick RGB,
with a fallback to YCbCr420.

The mask of supported formats by the source exposed by the property is
an optimistic scenario, as specific DFP-related caveats can't be
established before an EDID is present.

Should the explicitly requested color format not be supported by the
sink (or by the source in combination with the sink), then an error is
returned to userspace, so that it can make a better choice.

Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/i915/display/intel_hdmi.c | 52 ++++++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c
index 6c6a3a0677fe..9e5d88f07262 100644
--- a/drivers/gpu/drm/i915/display/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/display/intel_hdmi.c
@@ -2322,10 +2322,10 @@ static int intel_hdmi_compute_output_format(struct intel_encoder *encoder,
 	return intel_hdmi_compute_clock(encoder, crtc_state, respect_downstream_limits);
 }
 
-static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
-				      struct intel_crtc_state *crtc_state,
-				      const struct drm_connector_state *conn_state,
-				      bool respect_downstream_limits)
+static int intel_hdmi_compute_formats_auto(struct intel_encoder *encoder,
+					   struct intel_crtc_state *crtc_state,
+					   const struct drm_connector_state *conn_state,
+					   bool respect_downstream_limits)
 {
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
@@ -2360,6 +2360,35 @@ static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
 	return ret;
 }
 
+static int intel_hdmi_compute_formats(struct intel_encoder *encoder,
+				      struct intel_crtc_state *crtc_state,
+				      const struct drm_connector_state *conn_state,
+				      bool respect_downstream_limits)
+{
+	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+
+	switch (conn_state->color_format) {
+	case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+		return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+							respect_downstream_limits,
+							INTEL_OUTPUT_FORMAT_RGB);
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+		return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+							respect_downstream_limits,
+							INTEL_OUTPUT_FORMAT_YCBCR444);
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+		return intel_hdmi_compute_output_format(encoder, crtc_state, connector,
+							respect_downstream_limits,
+							INTEL_OUTPUT_FORMAT_YCBCR420);
+	case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+		return intel_hdmi_compute_formats_auto(encoder, crtc_state, conn_state,
+						       respect_downstream_limits);
+	default:
+		MISSING_CASE(conn_state->color_format);
+		return -EINVAL;
+	}
+}
+
 static bool intel_hdmi_is_cloned(const struct intel_crtc_state *crtc_state)
 {
 	return crtc_state->uapi.encoder_mask &&
@@ -2732,6 +2761,20 @@ static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs
 	.atomic_check = intel_hdmi_connector_atomic_check,
 };
 
+static void
+intel_hdmi_attach_color_format_property(struct intel_connector *connector)
+{
+	unsigned long fmts = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
+
+	if (connector->base.ycbcr_420_allowed)
+		fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+	if (intel_hdmi_can_ycbcr444(connector))
+		fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+
+	drm_connector_attach_color_format_property(&connector->base, fmts);
+}
+
 static void
 intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_connector)
 {
@@ -2744,6 +2787,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_
 
 	intel_attach_hdmi_colorspace_property(&connector->base);
 	drm_connector_attach_content_type_property(&connector->base);
+	intel_hdmi_attach_color_format_property(connector);
 
 	if (DISPLAY_VER(display) >= 10)
 		drm_connector_attach_hdr_output_metadata_property(&connector->base);

-- 
2.54.0



From nicolas.frattaroli at collabora.com  Tue Jun  9 05:44:15 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Tue, 09 Jun 2026 14:44:15 +0200
Subject: [PATCH v17 28/28] drm/i915/dp: Implement "color format" DRM
 property
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <20260609-color-format-v17-28-35739b5782cc@collabora.com>

Implement the "color format" DRM property for DP. The values of the
property include RGB, YCbCr420, YCbCr444 and Auto. Auto will pick RGB,
with a fallback to YCbCr420.

The mask of supported formats by the source exposed by the property is
an optimistic scenario, as specific DFP-related caveats can't be
established before an EDID is present.

Should the explicitly requested color format not be supported by the
sink (or by the source in combination with the sink), then an error is
returned to userspace, so that it can make a better choice.

Reviewed-by: Daniel Stone <daniel at fooishbar.org>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli at collabora.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 61 ++++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7c69d3badf9f..8c189e784adb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3434,10 +3434,10 @@ intel_dp_compute_output_format(struct intel_encoder *encoder,
 }
 
 static int
-intel_dp_compute_formats(struct intel_encoder *encoder,
-			 struct intel_crtc_state *crtc_state,
-			 struct drm_connector_state *conn_state,
-			 bool respect_downstream_limits)
+intel_dp_compute_formats_auto(struct intel_encoder *encoder,
+			      struct intel_crtc_state *crtc_state,
+			      struct drm_connector_state *conn_state,
+			      bool respect_downstream_limits)
 {
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -3473,6 +3473,34 @@ intel_dp_compute_formats(struct intel_encoder *encoder,
 	return ret;
 }
 
+static int
+intel_dp_compute_formats(struct intel_encoder *encoder,
+			 struct intel_crtc_state *crtc_state,
+			 struct drm_connector_state *conn_state,
+			 bool respect_downstream_limits)
+{
+	switch (conn_state->color_format) {
+	case DRM_CONNECTOR_COLOR_FORMAT_RGB444:
+		return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+						      respect_downstream_limits,
+						      INTEL_OUTPUT_FORMAT_RGB);
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444:
+		return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+						      respect_downstream_limits,
+						      INTEL_OUTPUT_FORMAT_YCBCR444);
+	case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420:
+		return intel_dp_compute_output_format(encoder, crtc_state, conn_state,
+						      respect_downstream_limits,
+						      INTEL_OUTPUT_FORMAT_YCBCR420);
+	case DRM_CONNECTOR_COLOR_FORMAT_AUTO:
+		return intel_dp_compute_formats_auto(encoder, crtc_state, conn_state,
+						     respect_downstream_limits);
+	default:
+		MISSING_CASE(conn_state->color_format);
+		return -EINVAL;
+	}
+}
+
 void
 intel_dp_audio_compute_config(struct intel_encoder *encoder,
 			      struct intel_crtc_state *pipe_config,
@@ -7027,6 +7055,29 @@ intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder)
 	return false;
 }
 
+static void
+intel_dp_attach_color_format_property(struct intel_dp *intel_dp)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	unsigned long fmts = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444);
+	bool has_pcon = false;
+
+	if (!connector)
+		return;
+
+	if (dig_port && intel_bios_encoder_is_lspcon(dig_port->base.devdata))
+		has_pcon = true;
+
+	if (has_pcon || source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR420))
+		fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
+
+	if (has_pcon || source_can_output(intel_dp, INTEL_OUTPUT_FORMAT_YCBCR444))
+		fmts |= BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444);
+
+	drm_connector_attach_color_format_property(&connector->base, fmts);
+}
+
 static void
 intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *_connector)
 {
@@ -7059,6 +7110,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *_connec
 
 	if (HAS_VRR(display))
 		drm_connector_attach_vrr_capable_property(&connector->base);
+
+	intel_dp_attach_color_format_property(intel_dp);
 }
 
 static void

-- 
2.54.0



From jonas at kwiboo.se  Tue Jun  9 08:41:21 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Tue,  9 Jun 2026 15:41:21 +0000
Subject: [PATCH 0/2] rockchip: Fix devices suspend freeze on RK3568/RK3566
Message-ID: <20260609154124.445182-1-jonas@kwiboo.se>

This series fixes a system freeze during suspend in ohci_suspend() due
to clk_usbphy1_480m not being enabled when EHCI/OHCI registers are
accessed on e.g. a Raxa ROCK 3C board.

Following pm_test modes work on my ROCK 3C with the missing usbphy clk
refs added:

  echo N > /sys/module/printk/parameters/console_suspend

  echo devices > /sys/power/pm_test
  echo platform > /sys/power/pm_test
  echo processors > /sys/power/pm_test
  echo core > /sys/power/pm_test

  echo mem > /sys/power/state

Jonas Karlman (2):
  dt-bindings: usb: Add Rockchip RK3568 compatible for EHCI and OHCI
  arm64: dts: rockchip: Fix devices suspend freeze on RK3568/RK3566

 .../devicetree/bindings/usb/generic-ehci.yaml    | 10 ++++++++++
 .../devicetree/bindings/usb/generic-ohci.yaml    |  5 ++++-
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi    | 16 ++++++++--------
 3 files changed, 22 insertions(+), 9 deletions(-)

-- 
2.54.0



From jonas at kwiboo.se  Tue Jun  9 08:41:22 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Tue,  9 Jun 2026 15:41:22 +0000
Subject: [PATCH 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible for EHCI and OHCI
In-Reply-To: <20260609154124.445182-1-jonas@kwiboo.se>
References: <20260609154124.445182-1-jonas@kwiboo.se>
Message-ID: <20260609154124.445182-2-jonas@kwiboo.se>

The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
being enabled, or the system may freeze when registers are accessed.

Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
constraint as RK3588.

Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
next patch make use of these new compatibles and adds the missing
clk_usbphy1_480m clock references.
---
 .../devicetree/bindings/usb/generic-ehci.yaml          | 10 ++++++++++
 .../devicetree/bindings/usb/generic-ohci.yaml          |  5 ++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
index 55a5aa7d7a54..c49a1bbc8cfd 100644
--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
@@ -52,6 +52,7 @@ properties:
               - ibm,476gtr-ehci
               - nxp,lpc1850-ehci
               - qca,ar7100-ehci
+              - rockchip,rk3568-ehci
               - rockchip,rk3588-ehci
               - snps,hsdk-v1.0-ehci
               - socionext,uniphier-ehci
@@ -186,6 +187,15 @@ allOf:
       required:
         - clocks
         - clock-names
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: rockchip,rk3568-ehci
+    then:
+      properties:
+        clocks:
+          minItems: 4
 
 unevaluatedProperties: false
 
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
index d42f448fa204..5f1b4d2bff89 100644
--- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
@@ -47,6 +47,7 @@ properties:
               - hpe,gxp-ohci
               - ibm,476gtr-ohci
               - ingenic,jz4740-ohci
+              - rockchip,rk3568-ohci
               - rockchip,rk3588-ohci
               - snps,hsdk-v1.0-ohci
           - const: generic-ohci
@@ -198,7 +199,9 @@ allOf:
       properties:
         compatible:
           contains:
-            const: rockchip,rk3588-ohci
+            enum:
+              - rockchip,rk3568-ohci
+              - rockchip,rk3588-ohci
     then:
       properties:
         clocks:
-- 
2.54.0



From jonas at kwiboo.se  Tue Jun  9 08:41:23 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Tue,  9 Jun 2026 15:41:23 +0000
Subject: [PATCH 2/2] arm64: dts: rockchip: Fix devices suspend freeze on RK3568/RK3566
In-Reply-To: <20260609154124.445182-1-jonas@kwiboo.se>
References: <20260609154124.445182-1-jonas@kwiboo.se>
Message-ID: <20260609154124.445182-3-jonas@kwiboo.se>

The EHCI/OHCI controller depends on clk_usbphy1_480m being enabled, or
the system may freeze when registers are accessed, i.e. during suspend
in ohci_suspend().

Add the missing clk_usbphy1_480m clocks reference to EHCI/OHCI
controllers to ensure the clock is enabled when ECHI/OHCI registers are
accessed to prevent a system freeze.

Fixes suspend pm_test issue with EHCI/OHCI devices due to the missing
clk_usbphy1_480m reference and makes following pm_test modes work:

  echo N > /sys/module/printk/parameters/console_suspend

  echo devices > /sys/power/pm_test
  echo platform > /sys/power/pm_test
  echo processors > /sys/power/pm_test
  echo core > /sys/power/pm_test

  echo mem > /sys/power/state

Fixes: 91c4c3e06a25 ("arm64: dts: rockchip: add usb2 nodes to rk3568 device tree")
Fixes: 78f7186095db ("arm64: dts: rockchip: rename and sort the rk356x usb2 phy handles")
Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index a5832895bd39..c930a6fd6ea0 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -321,44 +321,44 @@ its: msi-controller at fd440000 {
 	};
 
 	usb_host0_ehci: usb at fd800000 {
-		compatible = "generic-ehci";
+		compatible = "rockchip,rk3568-ehci", "generic-ehci";
 		reg = <0x0 0xfd800000 0x0 0x40000>;
 		interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
-			 <&cru PCLK_USB>;
+			 <&cru PCLK_USB>, <&usb2phy1>;
 		phys = <&usb2phy1_otg>;
 		phy-names = "usb";
 		status = "disabled";
 	};
 
 	usb_host0_ohci: usb at fd840000 {
-		compatible = "generic-ohci";
+		compatible = "rockchip,rk3568-ohci", "generic-ohci";
 		reg = <0x0 0xfd840000 0x0 0x40000>;
 		interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
-			 <&cru PCLK_USB>;
+			 <&cru PCLK_USB>, <&usb2phy1>;
 		phys = <&usb2phy1_otg>;
 		phy-names = "usb";
 		status = "disabled";
 	};
 
 	usb_host1_ehci: usb at fd880000 {
-		compatible = "generic-ehci";
+		compatible = "rockchip,rk3568-ehci", "generic-ehci";
 		reg = <0x0 0xfd880000 0x0 0x40000>;
 		interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
-			 <&cru PCLK_USB>;
+			 <&cru PCLK_USB>, <&usb2phy1>;
 		phys = <&usb2phy1_host>;
 		phy-names = "usb";
 		status = "disabled";
 	};
 
 	usb_host1_ohci: usb at fd8c0000 {
-		compatible = "generic-ohci";
+		compatible = "rockchip,rk3568-ohci", "generic-ohci";
 		reg = <0x0 0xfd8c0000 0x0 0x40000>;
 		interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
-			 <&cru PCLK_USB>;
+			 <&cru PCLK_USB>, <&usb2phy1>;
 		phys = <&usb2phy1_host>;
 		phy-names = "usb";
 		status = "disabled";
-- 
2.54.0



From conor at kernel.org  Tue Jun  9 08:56:36 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 16:56:36 +0100
Subject: [PATCH 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible for
 EHCI and OHCI
In-Reply-To: <20260609154124.445182-2-jonas@kwiboo.se>
References: <20260609154124.445182-1-jonas@kwiboo.se>
 <20260609154124.445182-2-jonas@kwiboo.se>
Message-ID: <20260609-subsidize-saturate-051fb051536d@spud>

On Tue, Jun 09, 2026 at 03:41:22PM +0000, Jonas Karlman wrote:
> The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
> being enabled, or the system may freeze when registers are accessed.
> 
> Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
> constraint as RK3588.
> 
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
> ---
> Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
> next patch make use of these new compatibles and adds the missing
> clk_usbphy1_480m clock references.

Reasonable complaint here from Sashiko.
pw-bot: changes-requested

Cheers,
Conor.
-------------- 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-rockchip/attachments/20260609/141f8509/attachment.sig>

From conor at kernel.org  Tue Jun  9 09:28:21 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 17:28:21 +0100
Subject: [PATCH v3 2/3] dt-bindings: mfd: syscon: Drop custom select for
 older dtschema
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-2-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
 <20260608-n-dt-bindings-simple-bus-syscon-v3-2-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <20260609-vertical-antarctic-e18a7ec91685@spud>

On Mon, Jun 08, 2026 at 10:44:25PM +0200, Krzysztof Kozlowski wrote:
> Older dtschema <2024.02 required custom select to avoid applying this
> binding to anything having "syscon" compatible.  That's not the case
> anymore and this additional select has two headaches:
> 
> 1. Duplicates all the compatibles listed in the schema.
> 
> 2. Is error-prone, because it requires contributor to add the compatible
>    in two places, otherwise the schema will be silently ignored.
>    The select list already misses mentioning compatibles:
>    mediatek,mt8365-infracfg-nao and renesas,r9a08g046-lvds-cmn (with the
>    latter being reverted for different reasons).
> 
> This requires bumping minimum dtschema requirement to v2024.04, which
> feels old enough to be a safe requirement.

I agree, seems reasonable enough given it's a jump from 2023.09 and not
some large jump.
The diff is nice too!
I assume Rob will be taking it, but just in case..
Acked-by: Conor Dooley <conor.dooley at microchip.com>

Cheers,
Conor.

> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> ---
> 
> Changes in v3:
> 1. Bump dtschema requirement
> 
> Changes in v2:
> 1. New patch
> ---
>  Documentation/devicetree/bindings/Makefile        |   2 +-
>  Documentation/devicetree/bindings/mfd/syscon.yaml | 116 ----------------------
>  2 files changed, 1 insertion(+), 117 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile
> index 7b668f7fd400..40c2094f47c2 100644
> --- a/Documentation/devicetree/bindings/Makefile
> +++ b/Documentation/devicetree/bindings/Makefile
> @@ -6,7 +6,7 @@ DT_MK_SCHEMA ?= dt-mk-schema
>  DT_SCHEMA_LINT = $(shell which yamllint || \
>    echo "warning: python package 'yamllint' not installed, skipping" >&2)
>  
> -DT_SCHEMA_MIN_VERSION = 2023.9
> +DT_SCHEMA_MIN_VERSION = 2024.4
>  
>  PHONY += check_dtschema_version
>  check_dtschema_version:
> diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
> index 9c81010d5a74..b70018bf1bcf 100644
> --- a/Documentation/devicetree/bindings/mfd/syscon.yaml
> +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
> @@ -19,122 +19,6 @@ description: |
>  maintainers:
>    - Lee Jones <lee at kernel.org>
>  
> -# Need a select with all compatibles listed for compatibility with older
> -# dtschema (<2024.02), so this will not be selected for other schemas having
> -# syscon fallback.
> -select:
> -  properties:
> -    compatible:
> -      contains:
> -        enum:
> -          - airoha,en7581-pbus-csr
> -          - al,alpine-sysfabric-service
> -          - allwinner,sun8i-a83t-system-controller
> -          - allwinner,sun8i-h3-system-controller
> -          - allwinner,sun8i-v3s-system-controller
> -          - allwinner,sun50i-a64-system-controller
> -          - altr,l3regs
> -          - altr,sdr-ctl
> -          - amd,pensando-elba-syscon
> -          - amlogic,meson-mx-assist
> -          - amlogic,meson-mx-bootrom
> -          - amlogic,meson8-analog-top
> -          - amlogic,meson8b-analog-top
> -          - amlogic,meson8-pmu
> -          - amlogic,meson8b-pmu
> -          - apm,merlin-poweroff-mailbox
> -          - apm,mustang-poweroff-mailbox
> -          - apm,xgene-csw
> -          - apm,xgene-efuse
> -          - apm,xgene-mcb
> -          - apm,xgene-rb
> -          - apm,xgene-scu
> -          - atmel,sama5d2-sfrbu
> -          - atmel,sama5d3-nfc-io
> -          - atmel,sama5d3-sfrbu
> -          - atmel,sama5d4-sfrbu
> -          - axis,artpec6-syscon
> -          - brcm,cru-clkset
> -          - brcm,sr-cdru
> -          - brcm,sr-mhb
> -          - cirrus,ep7209-syscon1
> -          - cirrus,ep7209-syscon2
> -          - cirrus,ep7209-syscon3
> -          - cnxt,cx92755-uc
> -          - econet,en751221-chip-scu
> -          - freecom,fsg-cs2-system-controller
> -          - fsl,imx93-aonmix-ns-syscfg
> -          - fsl,imx93-wakeupmix-syscfg
> -          - fsl,ls1088a-reset
> -          - fsl,vf610-anatop
> -          - fsl,vf610-mscm-cpucfg
> -          - hisilicon,dsa-subctrl
> -          - hisilicon,hi6220-sramctrl
> -          - hisilicon,hip04-ppe
> -          - hisilicon,pcie-sas-subctrl
> -          - hisilicon,peri-subctrl
> -          - hpe,gxp-sysreg
> -          - loongson,ls1b-syscon
> -          - loongson,ls1c-syscon
> -          - lsi,axxia-syscon
> -          - marvell,armada-3700-cpu-misc
> -          - marvell,armada-3700-nb-pm
> -          - marvell,armada-3700-avs
> -          - marvell,armada-3700-usb2-host-device-misc
> -          - marvell,armada-3700-usb2-host-misc
> -          - marvell,dove-global-config
> -          - mediatek,mt2701-pctl-a-syscfg
> -          - mediatek,mt2712-pctl-a-syscfg
> -          - mediatek,mt6397-pctl-pmic-syscfg
> -          - mediatek,mt7981-topmisc
> -          - mediatek,mt7988-topmisc
> -          - mediatek,mt8135-pctl-a-syscfg
> -          - mediatek,mt8135-pctl-b-syscfg
> -          - mediatek,mt8173-pctl-a-syscfg
> -          - mediatek,mt8365-syscfg
> -          - microchip,lan966x-cpu-syscon
> -          - microchip,mpfs-control-scb
> -          - microchip,mpfs-sysreg-scb
> -          - microchip,sam9x60-sfr
> -          - microchip,sama7d65-ddr3phy
> -          - microchip,sama7d65-sfrbu
> -          - microchip,sama7g5-ddr3phy
> -          - mscc,ocelot-cpu-syscon
> -          - mstar,msc313-pmsleep
> -          - nuvoton,ma35d1-sys
> -          - nuvoton,wpcm450-shm
> -          - nxp,s32g2-gpr
> -          - nxp,s32g3-gpr
> -          - qcom,apq8064-mmss-sfpb
> -          - qcom,apq8064-sps-sic
> -          - rockchip,px30-qos
> -          - rockchip,rk3036-qos
> -          - rockchip,rk3066-qos
> -          - rockchip,rk3128-qos
> -          - rockchip,rk3228-qos
> -          - rockchip,rk3288-qos
> -          - rockchip,rk3368-qos
> -          - rockchip,rk3399-qos
> -          - rockchip,rk3528-qos
> -          - rockchip,rk3562-qos
> -          - rockchip,rk3568-qos
> -          - rockchip,rk3576-qos
> -          - rockchip,rk3588-qos
> -          - rockchip,rv1126-qos
> -          - st,spear1340-misc
> -          - stericsson,nomadik-pmu
> -          - starfive,jh7100-sysmain
> -          - ti,am62-opp-efuse-table
> -          - ti,am62-usb-phy-ctrl
> -          - ti,am625-dss-oldi-io-ctrl
> -          - ti,am62p-cpsw-mac-efuse
> -          - ti,am654-dss-oldi-io-ctrl
> -          - ti,j784s4-acspcie-proxy-ctrl
> -          - ti,j784s4-pcie-ctrl
> -          - ti,keystone-pllctrl
> -  required:
> -    - compatible
> -
>  properties:
>    compatible:
>      oneOf:
> 
> -- 
> 2.53.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-rockchip/attachments/20260609/d21c3fa9/attachment-0001.sig>

From diederik at cknow-tech.com  Tue Jun  9 09:32:16 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Tue, 09 Jun 2026 18:32:16 +0200
Subject: [PATCH 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible
 for EHCI and OHCI
In-Reply-To: <20260609154124.445182-2-jonas@kwiboo.se>
References: <20260609154124.445182-1-jonas@kwiboo.se>
 <20260609154124.445182-2-jonas@kwiboo.se>
Message-ID: <DJ4NVA328NUV.LSPMVBFE0PD8@cknow-tech.com>

Hi Jonas,

On Tue Jun 9, 2026 at 5:41 PM CEST, Jonas Karlman wrote:
> The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
> being enabled, or the system may freeze when registers are accessed.
>
> Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
> constraint as RK3588.
>
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
> ---
> Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
> next patch make use of these new compatibles and adds the missing
> clk_usbphy1_480m clock references.
> ---
>  .../devicetree/bindings/usb/generic-ehci.yaml          | 10 ++++++++++
>  .../devicetree/bindings/usb/generic-ohci.yaml          |  5 ++++-
>  2 files changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
> index 55a5aa7d7a54..c49a1bbc8cfd 100644
> --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
> +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
> @@ -52,6 +52,7 @@ properties:
>                - ibm,476gtr-ehci
>                - nxp,lpc1850-ehci
>                - qca,ar7100-ehci
> +              - rockchip,rk3568-ehci
>                - rockchip,rk3588-ehci
>                - snps,hsdk-v1.0-ehci
>                - socionext,uniphier-ehci
> @@ -186,6 +187,15 @@ allOf:
>        required:
>          - clocks
>          - clock-names
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: rockchip,rk3568-ehci
> +    then:
> +      properties:
> +        clocks:
> +          minItems: 4

I think that the constraint for rk3588 is this:
- minItems: 1
- maxItems: 4

Like ~ every other compatible; there's no 'branch' for rk3588-ehci.

That's different from what you add for rk3568. Is that deliberate?
Because from the commit message I assumed they should be the same.

>  unevaluatedProperties: false
>  
> diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
> index d42f448fa204..5f1b4d2bff89 100644
> --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
> +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
> @@ -47,6 +47,7 @@ properties:
>                - hpe,gxp-ohci
>                - ibm,476gtr-ohci
>                - ingenic,jz4740-ohci
> +              - rockchip,rk3568-ohci
>                - rockchip,rk3588-ohci
>                - snps,hsdk-v1.0-ohci
>            - const: generic-ohci
> @@ -198,7 +199,9 @@ allOf:
>        properties:
>          compatible:
>            contains:
> -            const: rockchip,rk3588-ohci
> +            enum:
> +              - rockchip,rk3568-ohci
> +              - rockchip,rk3588-ohci

Here they clearly do have the same constraint.

Cheers,
  Diederik

>      then:
>        properties:
>          clocks:



From conor at kernel.org  Tue Jun  9 09:32:49 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 17:32:49 +0100
Subject: [PATCH V6 1/6] dt-bindings: power: supply: sgm41542: document
 sgm41542
In-Reply-To: <20260608175521.67449-2-macroalpha82@gmail.com>
References: <20260608175521.67449-1-macroalpha82@gmail.com>
 <20260608175521.67449-2-macroalpha82@gmail.com>
Message-ID: <20260609-excusable-overall-197cc08d4e43@spud>

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-rockchip/attachments/20260609/45a1431e/attachment.sig>

From conor at kernel.org  Tue Jun  9 09:34:21 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 17:34:21 +0100
Subject: [PATCH v3 3/3] ARM: dts: ti: Add specific compatibles for SCM
 conf nodes
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-3-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
 <20260608-n-dt-bindings-simple-bus-syscon-v3-3-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <20260609-riverbank-buffalo-ae12ae1317c6@spud>

Reviewed-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-rockchip/attachments/20260609/a929591e/attachment.sig>

From jonas at kwiboo.se  Tue Jun  9 11:06:17 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Tue, 9 Jun 2026 20:06:17 +0200
Subject: [PATCH 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible for
 EHCI and OHCI
In-Reply-To: <DJ4NVA328NUV.LSPMVBFE0PD8@cknow-tech.com>
References: <20260609154124.445182-1-jonas@kwiboo.se>
 <20260609154124.445182-2-jonas@kwiboo.se>
 <DJ4NVA328NUV.LSPMVBFE0PD8@cknow-tech.com>
Message-ID: <9e8f806d-72ec-4eb4-8967-3f82eb0e7dd4@kwiboo.se>

Hi Diederik,

On 6/9/2026 6:32 PM, Diederik de Haas wrote:
> Hi Jonas,
> 
> On Tue Jun 9, 2026 at 5:41 PM CEST, Jonas Karlman wrote:
>> The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
>> being enabled, or the system may freeze when registers are accessed.
>>
>> Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
>> constraint as RK3588.
>>
>> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
>> ---
>> Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
>> next patch make use of these new compatibles and adds the missing
>> clk_usbphy1_480m clock references.
>> ---
>>  .../devicetree/bindings/usb/generic-ehci.yaml          | 10 ++++++++++
>>  .../devicetree/bindings/usb/generic-ohci.yaml          |  5 ++++-
>>  2 files changed, 14 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>> index 55a5aa7d7a54..c49a1bbc8cfd 100644
>> --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>> +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>> @@ -52,6 +52,7 @@ properties:
>>                - ibm,476gtr-ehci
>>                - nxp,lpc1850-ehci
>>                - qca,ar7100-ehci
>> +              - rockchip,rk3568-ehci
>>                - rockchip,rk3588-ehci
>>                - snps,hsdk-v1.0-ehci
>>                - socionext,uniphier-ehci
>> @@ -186,6 +187,15 @@ allOf:
>>        required:
>>          - clocks
>>          - clock-names
>> +  - if:
>> +      properties:
>> +        compatible:
>> +          contains:
>> +            const: rockchip,rk3568-ehci
>> +    then:
>> +      properties:
>> +        clocks:
>> +          minItems: 4
> 
> I think that the constraint for rk3588 is this:
> - minItems: 1
> - maxItems: 4
> 
> Like ~ every other compatible; there's no 'branch' for rk3588-ehci.
> 
> That's different from what you add for rk3568. Is that deliberate?
> Because from the commit message I assumed they should be the same.

It was deliberate, the intention is to use min/maxItems: 4 for rk3568
for both EHCI and OHCI. I left out anything related to k3588 to keep
existing behavior and avoid any possible breakage, and why I used
'similar' and not 'same' in the commit message ;-)

Did a check and the rk3588 variant also uses 4 clocks so I will add same
constraint for the rk3588 variant and address Sashiko's concern in v2.

Regards,
Jonas

> 
>>  unevaluatedProperties: false
>>  
>> diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>> index d42f448fa204..5f1b4d2bff89 100644
>> --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>> +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>> @@ -47,6 +47,7 @@ properties:
>>                - hpe,gxp-ohci
>>                - ibm,476gtr-ohci
>>                - ingenic,jz4740-ohci
>> +              - rockchip,rk3568-ohci
>>                - rockchip,rk3588-ohci
>>                - snps,hsdk-v1.0-ohci
>>            - const: generic-ohci
>> @@ -198,7 +199,9 @@ allOf:
>>        properties:
>>          compatible:
>>            contains:
>> -            const: rockchip,rk3588-ohci
>> +            enum:
>> +              - rockchip,rk3568-ohci
>> +              - rockchip,rk3588-ohci
> 
> Here they clearly do have the same constraint.
> 
> Cheers,
>   Diederik
> 
>>      then:
>>        properties:
>>          clocks:
> 



From andriy.shevchenko at intel.com  Tue Jun  9 11:57:55 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Tue, 9 Jun 2026 21:57:55 +0300
Subject: [PATCH V10 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <PH0PR19MB99733851DADB0671AE5F76B788A51C2@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
 <20260604201832.60656-4-macroalpha82@gmail.com>
 <aiL0g8d0Y_JeAC5c@ashevche-desk.local>
 <PH0PR19MB99733851DADB0671AE5F76B788A51C2@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <aihiM5Ao-vuAsUyh@ashevche-desk.local>

On Mon, Jun 08, 2026 at 03:52:38PM -0500, Chris Morgan wrote:
> On Fri, Jun 05, 2026 at 07:08:35PM +0300, Andy Shevchenko wrote:
> > On Thu, Jun 04, 2026 at 03:18:25PM -0500, Chris Morgan wrote:

...

> > > +struct inv_icm42607_sensor_conf {
> > > +	int mode;
> > > +	int fs;
> > > +	int odr;
> > > +	int filter;
> > 
> > All of them are supposed to be signed? Why?

> > > +};
> 
> A later commit will use -1 for invalid values.

Okay, perhaps add a comment on top that negative values will mean invalid case?

...

> > > +#include <linux/delay.h>
> > > +#include <linux/dev_printk.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/iio/iio.h>
> > > +#include <linux/module.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/property.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/regulator/consumer.h>
> > 
> > IWYU, please.
> 
> This may sound like a dumb question, but what's the best way to invoke
> iwyu for a kernel? None of the readmes or man pages seem to be getting
> me anywhere...

In this list we (I mean community related to IIO) discussed iwyu tool and
its best configuration. Yep, it's barely good and far from ideal, but that's
what we have currently. Otherwise `git grep ...` and cscope are your friends
to answer this. Also doing review on regular basis makes this knowledge
developed better.

...

> It will get extended, so I'll keep this for now if that's okay.

It's okay.

-- 
With Best Regards,
Andy Shevchenko




From macromorgan at hotmail.com  Tue Jun  9 12:51:09 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Tue, 9 Jun 2026 14:51:09 -0500
Subject: [PATCH V10 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <aihiM5Ao-vuAsUyh@ashevche-desk.local>
References: <20260604201832.60656-1-macroalpha82@gmail.com>
 <20260604201832.60656-4-macroalpha82@gmail.com>
 <aiL0g8d0Y_JeAC5c@ashevche-desk.local>
 <PH0PR19MB99733851DADB0671AE5F76B788A51C2@PH0PR19MB997338.namprd19.prod.outlook.com>
 <aihiM5Ao-vuAsUyh@ashevche-desk.local>
Message-ID: <PH0PR19MB99733822F73EF61B82CC16C616A51D2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Tue, Jun 09, 2026 at 09:57:55PM +0300, Andy Shevchenko wrote:
> On Mon, Jun 08, 2026 at 03:52:38PM -0500, Chris Morgan wrote:
> > On Fri, Jun 05, 2026 at 07:08:35PM +0300, Andy Shevchenko wrote:
> > > On Thu, Jun 04, 2026 at 03:18:25PM -0500, Chris Morgan wrote:
> 
> ...
> 
> > > > +struct inv_icm42607_sensor_conf {
> > > > +	int mode;
> > > > +	int fs;
> > > > +	int odr;
> > > > +	int filter;
> > > 
> > > All of them are supposed to be signed? Why?
> 
> > > > +};
> > 
> > A later commit will use -1 for invalid values.
> 
> Okay, perhaps add a comment on top that negative values will mean invalid case?

Will do.

> 
> ...
> 
> > > > +#include <linux/delay.h>
> > > > +#include <linux/dev_printk.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/iio/iio.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/mutex.h>
> > > > +#include <linux/property.h>
> > > > +#include <linux/regmap.h>
> > > > +#include <linux/regulator/consumer.h>
> > > 
> > > IWYU, please.
> > 
> > This may sound like a dumb question, but what's the best way to invoke
> > iwyu for a kernel? None of the readmes or man pages seem to be getting
> > me anywhere...
> 
> In this list we (I mean community related to IIO) discussed iwyu tool and
> its best configuration. Yep, it's barely good and far from ideal, but that's
> what we have currently. Otherwise `git grep ...` and cscope are your friends
> to answer this. Also doing review on regular basis makes this knowledge
> developed better.
> 

Since git grep (and elixir.bootlin.com) are the tools I know best, I'll
try to sensibly pare down the includes where I can. I do see that the
interrupt include isn't needed anymore so I can drop that one. If
anything else jumps out let me know and I'll exclude it too. There's a
few other things I'm going to pare out since sashiko.dev bot correctly
pointed out some of my code is now dead since I removed buffers support
(because I don't have an interrupt on this device).

> ...
> 
> > It will get extended, so I'll keep this for now if that's okay.
> 
> It's okay.
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you,
Chris


From diederik at cknow-tech.com  Tue Jun  9 12:51:58 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Tue, 09 Jun 2026 21:51:58 +0200
Subject: [PATCH 1/2] dt-bindings: usb: Add Rockchip RK3568 compatible
 for EHCI and OHCI
In-Reply-To: <9e8f806d-72ec-4eb4-8967-3f82eb0e7dd4@kwiboo.se>
References: <20260609154124.445182-1-jonas@kwiboo.se>
 <20260609154124.445182-2-jonas@kwiboo.se>
 <DJ4NVA328NUV.LSPMVBFE0PD8@cknow-tech.com>
 <9e8f806d-72ec-4eb4-8967-3f82eb0e7dd4@kwiboo.se>
Message-ID: <DJ4S46HX0BMK.25LUHCHQY4V7K@cknow-tech.com>

Hi Jonas,

On Tue Jun 9, 2026 at 8:06 PM CEST, Jonas Karlman wrote:
> Hi Diederik,
>
> On 6/9/2026 6:32 PM, Diederik de Haas wrote:
>> Hi Jonas,
>> 
>> On Tue Jun 9, 2026 at 5:41 PM CEST, Jonas Karlman wrote:
>>> The Rockchip RK3568 EHCI/OHCI controller depends on clk_usbphy1_480m
>>> being enabled, or the system may freeze when registers are accessed.
>>>
>>> Add Rockchip RK3568 EHCI and OHCI compatibles with a similar four-clock
>>> constraint as RK3588.
>>>
>>> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
>>> ---
>>> Existing DTs for RK3568 use the plain generic-ehci/ohci compatible,
>>> next patch make use of these new compatibles and adds the missing
>>> clk_usbphy1_480m clock references.
>>> ---
>>>  .../devicetree/bindings/usb/generic-ehci.yaml          | 10 ++++++++++
>>>  .../devicetree/bindings/usb/generic-ohci.yaml          |  5 ++++-
>>>  2 files changed, 14 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>>> index 55a5aa7d7a54..c49a1bbc8cfd 100644
>>> --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>>> +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml
>>> @@ -52,6 +52,7 @@ properties:
>>>                - ibm,476gtr-ehci
>>>                - nxp,lpc1850-ehci
>>>                - qca,ar7100-ehci
>>> +              - rockchip,rk3568-ehci
>>>                - rockchip,rk3588-ehci
>>>                - snps,hsdk-v1.0-ehci
>>>                - socionext,uniphier-ehci
>>> @@ -186,6 +187,15 @@ allOf:
>>>        required:
>>>          - clocks
>>>          - clock-names
>>> +  - if:
>>> +      properties:
>>> +        compatible:
>>> +          contains:
>>> +            const: rockchip,rk3568-ehci
>>> +    then:
>>> +      properties:
>>> +        clocks:
>>> +          minItems: 4
>> 
>> I think that the constraint for rk3588 is this:
>> - minItems: 1
>> - maxItems: 4
>> 
>> Like ~ every other compatible; there's no 'branch' for rk3588-ehci.
>> 
>> That's different from what you add for rk3568. Is that deliberate?
>> Because from the commit message I assumed they should be the same.
>
> It was deliberate, the intention is to use min/maxItems: 4 for rk3568

Thanks :-)

> for both EHCI and OHCI. I left out anything related to k3588 to keep
> existing behavior and avoid any possible breakage, and why I used
> 'similar' and not 'same' in the commit message ;-)
>
> Did a check and the rk3588 variant also uses 4 clocks so I will add same
> constraint for the rk3588 variant and address Sashiko's concern in v2.

FWIW: I would be absolutely fine if you restrict this patch set to just RK3568.
For the same reason you mentioned. All I wanted to know if it was deliberate
and you confirmed that :-)

Cheers,
  Diederik

> Regards,
> Jonas
>
>> 
>>>  unevaluatedProperties: false
>>>  
>>> diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>>> index d42f448fa204..5f1b4d2bff89 100644
>>> --- a/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>>> +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml
>>> @@ -47,6 +47,7 @@ properties:
>>>                - hpe,gxp-ohci
>>>                - ibm,476gtr-ohci
>>>                - ingenic,jz4740-ohci
>>> +              - rockchip,rk3568-ohci
>>>                - rockchip,rk3588-ohci
>>>                - snps,hsdk-v1.0-ohci
>>>            - const: generic-ohci
>>> @@ -198,7 +199,9 @@ allOf:
>>>        properties:
>>>          compatible:
>>>            contains:
>>> -            const: rockchip,rk3588-ohci
>>> +            enum:
>>> +              - rockchip,rk3568-ohci
>>> +              - rockchip,rk3588-ohci
>> 
>> Here they clearly do have the same constraint.
>> 
>> Cheers,
>>   Diederik
>> 
>>>      then:
>>>        properties:
>>>          clocks:
>> 



From daniel at fooishbar.org  Tue Jun  9 13:11:46 2026
From: daniel at fooishbar.org (Daniel Stone)
Date: Tue, 9 Jun 2026 21:11:46 +0100
Subject: [PATCH v17 00/28] Add new general DRM property "color format"
In-Reply-To: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
Message-ID: <CAPj87rNhTViuff5qWeoGkPgyRvP0uOAcUGpcJJPTkPR2b8fJcw@mail.gmail.com>

Hi Nicolas,

On Tue, 9 Jun 2026 at 13:44, Nicolas Frattaroli
<nicolas.frattaroli at collabora.com> wrote:
> this is a follow-up to
> https://lore.kernel.org/all/20250911130739.4936-1-marius.vlad at collabora.com/
> which in of itself is a follow-up to
> https://lore.kernel.org/dri-devel/20240115160554.720247-1-andri at yngvason.is/ where
> a new DRM connector property has been added allowing users to
> force a particular color format.
>
> That in turn was actually also a follow-up from Werner Sembach's posted at
> https://lore.kernel.org/dri-devel/20210630151018.330354-1-wse at tuxedocomputers.com/
>
> As the number of cooks have reached critical mass, I'm hoping I'll be
> the last person to touch this particular series.

Thanks for seeing this through!

I've pushed this now, minus the Intel patches which they can merge
through their own tree. The AMD tree required a pretty trivial
conflict resolution which seems to work OK here.

Cheers,
Daniel


From simon at symple.nz  Tue Jun  9 15:14:01 2026
From: simon at symple.nz (Simon Wright)
Date: Wed, 10 Jun 2026 10:14:01 +1200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
Message-ID: <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>

Hi Piotr,

Thanks - glad it's useful. If your RK3576 H.264 decode shows wrong pixels at the
same horizontal edges (luma rows 4 and 12 within each macroblock row, propagating
through the following P-frames), it's very likely the same bug.

On a PoC for 7.1, good news first: I checked the in-kernel driver, and the whole
drivers/media/platform/rockchip/rkvdec/ directory is byte-identical between 7.0 and
7.1-rc7 (as is the V4L2 stateless control uAPI). So there's nothing 7.1-specific to
do - the same fix covers both.

The less convenient part is that the fix is not a small patch to
rkvdec-vdpu383-h264.c. The root cause is that the BSP runs a one-shot "warmup"
priming decode at every decoder power-up (rk3576_workaround_run) that mainline
omits, and that warmup is driven through the VDPU383's link/CCU register bank.
Mainline's single-shot path doesn't carry that link infrastructure, so the warmup
lives in an out-of-tree file (rkvdec-link.c) that is part of a broader downstream
tree I've been building on top of mainline - link-mode support plus V4L2 stateless
VP9 and AV1 decoders for the VDPU383 (neither is upstream yet). The warmup isn't
self-contained in the H.264 file; it needs that link plumbing around it. So rather
than hand you a fragile micro-diff, the practical way to verify is to build and load
that downstream module, where the warmup is on by default:

    git clone https://github.com/SympleNZ/rkvdec-vdpu383-vp9
    cd rkvdec-vdpu383-vp9
    # against your running kernel's headers/source:
    KBUILD_MODPOST_WARN=1 make -C /lib/modules/$(uname -r)/build M=$PWD/src modules

    sudo rmmod rockchip_vdec 2>/dev/null    # unload the in-tree driver
    sudo insmod src/rockchip-vdec.ko        # warmup is default-on, no params needed

(If rockchip-vdec is built into your kernel rather than a module, you'll need it as
a module - or blacklisted - first. The module name may differ slightly on your
build.)

Then decode your H.264 as usual (v4l2slh264dec) and compare against avdec_h264 - the
rows-4/12 corruption should be gone. That repo is the VP9 work, but its src/ builds
the full VDPU381/383 H.264/H.265/VP9/AV1 driver, so H.264 is included.

One honest caveat for the media-player use case: the warmup fixes correctness (the
wrong pixels), not throughput - and the throughput limit isn't specific to H.264.
It's the mainline single-shot submit model (no link-mode pipelining yet), so it
applies equally to HEVC. (HEVC, incidentally, already decodes correctly on stock
mainline - the deblock bug is H.264-only - but it sits under the same throughput
ceiling.) Mainline decode on RK3576 is still well short of the BSP's rate, so
real-time 1080p/4K playback can still drop frames regardless of codec. This will
tell you whether your corruption is this bug; smooth playback across codecs is a
separate piece of work.

If it builds and runs, I'd be very interested in the result on your three boards -
independent confirmation across more RK3576 hardware would strengthen the report.
Happy to help if the build trips up.

Full write-up (root cause, the register kick sequence, validation):
https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug/blob/master/FIX.md

Regards,
Simon


From chaoyi.chen at rock-chips.com  Tue Jun  9 18:14:02 2026
From: chaoyi.chen at rock-chips.com (Chaoyi Chen)
Date: Wed, 10 Jun 2026 09:14:02 +0800
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
 <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
 <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
 <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
Message-ID: <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com>

Hi Midgy,

On 6/9/2026 7:11 PM, Midgy Balon wrote:
> Hello Chaoyi,
> 
> You were right - building rocket as a module fixes it. Thanks for the pointer.
> 
> I rebuilt with CONFIG_DRM_ACCEL_ROCKET=m (everything else the same:
> need_regulator on
> the RK3568 NPU power domain via a DOMAIN_M_R variant, domain-supply =
> <&vdd_npu>, and the
> regulator-always-on workaround dropped). The board now boots cleanly
> and, more importantly,
> an NPU job submit no longer hangs: I ran the test workload five times
> with no RCU stall and
> no freeze.
> 
> So with rocket=m the need_regulator approach works on RK3568, and I'll
> keep it for v4
> (domain-supply + need_regulator, instead of marking vdd_npu
> always-on). rocket=m is the
> normal configuration anyway; my earlier hang came from building it =y
> in a self-contained
> image, so it probed in the initcalls (around 2 s) and the genpd ->
> I2C-PMIC regulator
> transition ran before the system was ready. As a module it loads from
> udev much later
> (~6.8 s here), after the I2C controller and regulator core are fully up.
> 
> On your question of when the device-link error is printed - it is at
> power-domain
> controller probe, not at the rocket probe:
> 
>   [    2.700618] vdd_npu: Bringing 500000uV into 825000-825000uV
>   [    2.749637] rockchip-pm-domain fdd90000.power-management:power-controller:
>                  Failed to create device link (0x180) with supplier 0-0020 for
>                  /power-management at fdd90000/power-controller/power-domain at 6
>   [    2.945955] platform fde40000.npu: Adding to iommu group 3
>   ...
>   [    6.840374] rocket: loading out-of-tree module taints kernel.
>   [    6.877647] [drm] Initialized rocket 0.0.0 for rknn on minor 0
>   [    6.879950] rocket fde40000.npu: Rockchip NPU core 0 version: 0
> 
> So the device-link to the rk809 PMIC (0-0020) fails to form at ~2.75
> s, well before rocket
> loads at ~6.8 s. It is non-fatal here - the vdd_npu rail is brought up
> by the regulator core
> and all jobs run - and there is no "failed to get ack on domain npu"
> NoC warning this boot
> (the always-on kernel had one). The complete boot log is attached.
> 
> Two notes / one question:
> - This boot used fw_devlink=permissive on the command line. Is the
> "Failed to create device
>   link ... supplier 0-0020" at pmdomain probe expected/benign, or is
> there a clean way to make
>   it order correctly (so it also works without permissive, and a =y
> build wouldn't deadlock in
>   the initcalls)?

We encountered the same issue on the RK3588 NPU before. And it was
resolved with the following patch at that time.

https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/

Please compare the differences in NPU pmdomain and DTS configuration
between the RK3568 and RK3588.

> - (The convolution output is still uniform zero-point / the job times
> out - that is the
>   separate NPU compute-completion issue, unrelated to the power-domain
> work. Finley, that is
>   the one I flagged earlier re PVTPLL/NoC.)
> 
> Kind regards,
> Midgy
> 

-- 
Best, 
Chaoyi


From diederik at cknow-tech.com  Wed Jun 10 01:04:05 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 10:04:05 +0200
Subject: [PATCH 1/2] arm64: dts: rockchip: Drop duplicate USB nodes on NanoPC-T6 LTS
In-Reply-To: <20260610081400.758687-1-diederik@cknow-tech.com>
References: <20260610081400.758687-1-diederik@cknow-tech.com>
Message-ID: <20260610081400.758687-2-diederik@cknow-tech.com>

Several USB nodes were enabled/configured on the NanoPC-T6 LTS first. Then
those same nodes were enabled/configured in the NanoPC-T6 dtsi file, but
the ones in the LTS dts file were not removed, so do so now.

Signed-off-by: Diederik de Haas <diederik at cknow-tech.com>
---
 .../boot/dts/rockchip/rk3588-nanopc-t6-lts.dts  | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
index ff855064be08..0ee67ee24f3c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
@@ -38,23 +38,6 @@ usb20_host_pwren: usb20-host-pwren {
 	};
 };
 
-&u2phy1 {
-	status = "okay";
-};
-
-&u2phy1_otg {
-	status = "okay";
-};
-
 &u2phy2_host {
 	phy-supply = <&vcc5v0_usb20_host>;
 };
-
-&usbdp_phy1 {
-	status = "okay";
-};
-
-&usb_host1_xhci {
-	dr_mode = "host";
-	status = "okay";
-};
-- 
2.53.0



From diederik at cknow-tech.com  Wed Jun 10 01:04:06 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 10:04:06 +0200
Subject: [PATCH 2/2] arm64: dts: rockchip: Fix USB hub phy-supply config for NanoPC-T6 LTS
In-Reply-To: <20260610081400.758687-1-diederik@cknow-tech.com>
References: <20260610081400.758687-1-diederik@cknow-tech.com>
Message-ID: <20260610081400.758687-3-diederik@cknow-tech.com>

The MTT USB 2.0 hub is connected to the SoC's USB20 HOST1, so the phy-supply
belongs to u2phy3_host, not u2phy2_host as that is for USB20 HOST0.

Fixes: db1dcbe5f752 ("arm64: dts: rockchip: add NanoPC-T6 LTS")
Cc: stable at vger.kernel.org
Signed-off-by: Diederik de Haas <diederik at cknow-tech.com>
---
 arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
index 0ee67ee24f3c..0e15a2e1f2ff 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6-lts.dts
@@ -38,6 +38,6 @@ usb20_host_pwren: usb20-host-pwren {
 	};
 };
 
-&u2phy2_host {
+&u2phy3_host {
 	phy-supply = <&vcc5v0_usb20_host>;
 };
-- 
2.53.0



From diederik at cknow-tech.com  Wed Jun 10 01:04:04 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 10:04:04 +0200
Subject: [PATCH 0/2] Cleanup and fix for NanoPC-T6 Plus
Message-ID: <20260610081400.758687-1-diederik@cknow-tech.com>

Several nodes were enabled/configured when support for the NanoPC-T6 Plus was
added, but later those same nodes got enabled/configured in the dtsi file,
making those in the dts file superfluous, so remove them.

The MTT USB 2.0 Hub is connected to USB20 HOST1, so the phy-supply belongs to
u2phy3_host, not u2phy2_host as that is for USB20 HOST0.

Diederik de Haas (2):
  arm64: dts: rockchip: Drop duplicate USB nodes on NanoPC-T6 LTS
  arm64: dts: rockchip: Fix USB hub phy-supply config for NanoPC-T6 LTS

 .../dts/rockchip/rk3588-nanopc-t6-lts.dts     | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

-- 
2.53.0



From krzk at kernel.org  Wed Jun 10 01:46:57 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Wed, 10 Jun 2026 10:46:57 +0200
Subject: [PATCH] ASoC: dt-bindings: everest,es8389: Document audio graph
 port
In-Reply-To: <20260607105913.355966-1-diederik@cknow-tech.com>
References: <20260607105913.355966-1-diederik@cknow-tech.com>
Message-ID: <20260610-shiny-pronghorn-of-piety-8fa3ea@quoll>

On Sun, Jun 07, 2026 at 12:58:49PM +0200, Diederik de Haas wrote:
> Provide an endpoint for binding with the other side of the audio link,
> which is achieved via the 'port' property.
> 
> Signed-off-by: Diederik de Haas <diederik at cknow-tech.com>

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

Best regards,
Krzysztof



From diederik at cknow-tech.com  Wed Jun 10 02:18:22 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 11:18:22 +0200
Subject: [PATCH 0/2] Cleanup and fix for NanoPC-T6 Plus
In-Reply-To: <20260610081400.758687-1-diederik@cknow-tech.com>
References: <20260610081400.758687-1-diederik@cknow-tech.com>
Message-ID: <DJ599LMGW2UX.12U9YA1MOW7O0@cknow-tech.com>

On Wed Jun 10, 2026 at 10:14 AM CEST, Diederik de Haas wrote:
> Several nodes were enabled/configured when support for the NanoPC-T6 Plus was

s/Plus/LTS/ in Subject and here ... 

Still working on a submission for the NanoPC-T6 Plus ;-)

Cheers,
  Diederik

> added, but later those same nodes got enabled/configured in the dtsi file,
> making those in the dts file superfluous, so remove them.
>
> The MTT USB 2.0 Hub is connected to USB20 HOST1, so the phy-supply belongs to
> u2phy3_host, not u2phy2_host as that is for USB20 HOST0.
>
> Diederik de Haas (2):
>   arm64: dts: rockchip: Drop duplicate USB nodes on NanoPC-T6 LTS
>   arm64: dts: rockchip: Fix USB hub phy-supply config for NanoPC-T6 LTS
>
>  .../dts/rockchip/rk3588-nanopc-t6-lts.dts     | 19 +------------------
>  1 file changed, 1 insertion(+), 18 deletions(-)



From regressions at leemhuis.info  Wed Jun 10 02:28:03 2026
From: regressions at leemhuis.info (Thorsten Leemhuis)
Date: Wed, 10 Jun 2026 11:28:03 +0200
Subject: [REGRESSION][BISECTED] wireless networking broken on Pinephone
 Pro
In-Reply-To: <20260607225901.64019-1-oklopfer37@gmail.com>
References: <20260607225901.64019-1-oklopfer37@gmail.com>
Message-ID: <b68dc2ab-ab54-435f-a4e5-05b1b8397505@leemhuis.info>

On 6/8/26 00:59, Oren Klopfer wrote:
> Apologies if this is not formatted properly, this is my first
> submission to the kernel mailing list. WiFi specifications were
> introduced into the Pinephone Pro device tree in
> 096bd8c679185f898cae9933c6a68650fa26ea4f, but this causes complete
> networking failure on some devices. The regression affects all
> versions v6.18-rc1..v7.1-rc6.
> 
> An identical issue was reported for the Pinebook Pro at https://
> lore.kernel.org/all/aUKOlj-RvTYlrpiS at rock.grzadka/; the regression
> was reverted in 29d1f56c4f3001b7f547123e0a307c009ac717f8. The errors
> faced on the Pinephone Pro are exactly the same as were reported for
> the Pinebook Pro regression.
> 
> A previous patch at https://lore.kernel.org/all/20260112-
> ppp_connectivity-v1-3-284d6e83b212 at gmail.com/ attempted to resolve
> this issue but never ended up being merged.
> 
> 096bd8c679185f898cae9933c6a68650fa26ea4f is the first bad commit
> commit 096bd8c679185f898cae9933c6a68650fa26ea4f
> Author: Peter Robinson <pbrobinson at gmail.com>
> Date:   Fri Aug 29 12:38:24 2025 +0100
> 
>     arm64: dts: rockchip: Further describe the WiFi for the Pinephone Pro
> [...]
> 
> Reverting the commit allows wireless connection to function again. I
> am not really familiar with the process of submitting a revert
> patch, but I'd request that this be done on all of 6.18 (LTS), 7.0
> (Stable), 7.1 (Mainline). Thanks!
Thx for the report. Sounds like a revert is the right course of action
here. Could you submit one with a stable tag to ensure backporting? That
might be the fastest way to resolve this, as that makes it easy to
process for the maintainers to process this.

Ciao, Thorsten


From amadeus at jmu.edu.cn  Wed Jun 10 03:00:04 2026
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Wed, 10 Jun 2026 18:00:04 +0800
Subject: [PATCH v2 0/2] arm64: dts: rockchip: Add HINLINK H28K
Message-ID: <20260610100006.366963-1-amadeus@jmu.edu.cn>

The HINLINK H28K is a dual-gigabit SBC based on the RK3528 SoC.

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

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

Changes in v2:
- Add USB 2.0 support
- Remove MangoPi patches
- Improve commit messages

Chukun Pan (2):
  dt-bindings: arm: rockchip: Add HINLINK H28K
  arm64: dts: rockchip: Add HINLINK H28K

 .../devicetree/bindings/arm/rockchip.yaml     |   5 +
 arch/arm64/boot/dts/rockchip/Makefile         |   1 +
 .../boot/dts/rockchip/rk3528-hinlink-h28k.dts | 318 ++++++++++++++++++
 3 files changed, 324 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts

-- 
2.34.1



From amadeus at jmu.edu.cn  Wed Jun 10 03:00:05 2026
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Wed, 10 Jun 2026 18:00:05 +0800
Subject: [PATCH v2 1/2] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <20260610100006.366963-1-amadeus@jmu.edu.cn>
References: <20260610100006.366963-1-amadeus@jmu.edu.cn>
Message-ID: <20260610100006.366963-2-amadeus@jmu.edu.cn>

The HINLINK H28K (also known as LinkStar H28K) is a dual-gigabit SBC
based on the RK3528 SoC. Add devicetree binding documentation for it.

Link: https://wiki.seeedstudio.com/H28K_Datasheet/
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 1a9dde18626d..3952987a2c3c 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -724,6 +724,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.34.1



From amadeus at jmu.edu.cn  Wed Jun 10 03:00:06 2026
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Wed, 10 Jun 2026 18:00:06 +0800
Subject: [PATCH v2 2/2] arm64: dts: rockchip: Add HINLINK H28K
In-Reply-To: <20260610100006.366963-1-amadeus@jmu.edu.cn>
References: <20260610100006.366963-1-amadeus@jmu.edu.cn>
Message-ID: <20260610100006.366963-3-amadeus@jmu.edu.cn>

The HINLINK H28K (LinkStar H28K) is a SBC 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 | 318 ++++++++++++++++++
 2 files changed, 319 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 761d82b4f4f2..a68d07296c9f 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -92,6 +92,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..0ec50e9156eb
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3528-hinlink-h28k.dts
@@ -0,0 +1,318 @@
+// 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";
+};
+
+&usb2phy {
+	status = "okay";
+};
+
+&usb2phy_host {
+	phy-supply = <&vcc5v0_sys>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
-- 
2.34.1



From diederik at cknow-tech.com  Wed Jun 10 03:05:49 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 12:05:49 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
 <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
 <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
 <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
 <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com>
Message-ID: <DJ5A9XL183RZ.20J3ASQ3EWUZ6@cknow-tech.com>

Hi,

On Wed Jun 10, 2026 at 3:14 AM CEST, Chaoyi Chen wrote:
> Hi Midgy,
>
> On 6/9/2026 7:11 PM, Midgy Balon wrote:
>> Hello Chaoyi,
>> 
>> You were right - building rocket as a module fixes it. Thanks for the pointer.
>> 
>> I rebuilt with CONFIG_DRM_ACCEL_ROCKET=m (everything else the same:
>> need_regulator on
>> the RK3568 NPU power domain via a DOMAIN_M_R variant, domain-supply =
>> <&vdd_npu>, and the
>> regulator-always-on workaround dropped). The board now boots cleanly
>> and, more importantly,
>> an NPU job submit no longer hangs: I ran the test workload five times
>> with no RCU stall and
>> no freeze.
>> 
>> So with rocket=m the need_regulator approach works on RK3568, and I'll
>> keep it for v4
>> (domain-supply + need_regulator, instead of marking vdd_npu
>> always-on). rocket=m is the
>> normal configuration anyway; my earlier hang came from building it =y
>> in a self-contained
>> image, so it probed in the initcalls (around 2 s) and the genpd ->
>> I2C-PMIC regulator
>> transition ran before the system was ready. As a module it loads from
>> udev much later
>> (~6.8 s here), after the I2C controller and regulator core are fully up.
>> 
>> On your question of when the device-link error is printed - it is at
>> power-domain
>> controller probe, not at the rocket probe:
>> 
>>   [    2.700618] vdd_npu: Bringing 500000uV into 825000-825000uV
>>   [    2.749637] rockchip-pm-domain fdd90000.power-management:power-controller:
>>                  Failed to create device link (0x180) with supplier 0-0020 for
>>                  /power-management at fdd90000/power-controller/power-domain at 6
>>   [    2.945955] platform fde40000.npu: Adding to iommu group 3
>>   ...
>>   [    6.840374] rocket: loading out-of-tree module taints kernel.
>>   [    6.877647] [drm] Initialized rocket 0.0.0 for rknn on minor 0
>>   [    6.879950] rocket fde40000.npu: Rockchip NPU core 0 version: 0
>> 
>> So the device-link to the rk809 PMIC (0-0020) fails to form at ~2.75
>> s, well before rocket
>> loads at ~6.8 s. It is non-fatal here - the vdd_npu rail is brought up
>> by the regulator core
>> and all jobs run - and there is no "failed to get ack on domain npu"
>> NoC warning this boot
>> (the always-on kernel had one). The complete boot log is attached.
>> 
>> Two notes / one question:
>> - This boot used fw_devlink=permissive on the command line. Is the
>> "Failed to create device
>>   link ... supplier 0-0020" at pmdomain probe expected/benign, or is
>> there a clean way to make
>>   it order correctly (so it also works without permissive, and a =y
>> build wouldn't deadlock in
>>   the initcalls)?
>
> We encountered the same issue on the RK3588 NPU before. And it was
> resolved with the following patch at that time.
>
> https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/
>
> Please compare the differences in NPU pmdomain and DTS configuration
> between the RK3568 and RK3588.

About a month ago on #linux-rockchip we were discussing PM 'stuff':
https://libera.catirclogs.org/linux-rockchip/2026-05-15#39939137;
which references this paste
https://paste.sr.ht/~diederik/89d9f84e22474e837b55286d213b67f03859ce2e
I've since removed the DCDC_REG2 for PineTab2 and the 'fix' should likely
be extended to cover all RK3566/RK3568 devices though.

It's what I made at the time hoping to fix a suspend/resume issue when
trying upstream TF-A. It didn't fix the issue at the time, but may still
be useful/needed and I think it's what Chaoyi hinted at.

Just yesterday, Jonas posted this patch which may be useful/needed too:
https://lore.kernel.org/linux-rockchip/20260609154124.445182-1-jonas at kwiboo.se/

HTH,
  Diederik

>> - (The convolution output is still uniform zero-point / the job times
>> out - that is the
>>   separate NPU compute-completion issue, unrelated to the power-domain
>> work. Finley, that is
>>   the one I flagged earlier re PVTPLL/NoC.)
>> 
>> Kind regards,
>> Midgy
>> 



From heiko at sntech.de  Wed Jun 10 03:21:50 2026
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Wed, 10 Jun 2026 12:21:50 +0200
Subject: [REGRESSION][BISECTED] wireless networking broken on Pinephone Pro
In-Reply-To: <b68dc2ab-ab54-435f-a4e5-05b1b8397505@leemhuis.info>
References: <20260607225901.64019-1-oklopfer37@gmail.com>
 <b68dc2ab-ab54-435f-a4e5-05b1b8397505@leemhuis.info>
Message-ID: <3761289.R56niFO833@diego>

Am Mittwoch, 10. Juni 2026, 11:28:03 Mitteleurop?ische Sommerzeit schrieb Thorsten Leemhuis:
> On 6/8/26 00:59, Oren Klopfer wrote:
> > Apologies if this is not formatted properly, this is my first
> > submission to the kernel mailing list. WiFi specifications were
> > introduced into the Pinephone Pro device tree in
> > 096bd8c679185f898cae9933c6a68650fa26ea4f, but this causes complete
> > networking failure on some devices. The regression affects all
> > versions v6.18-rc1..v7.1-rc6.
> > 
> > An identical issue was reported for the Pinebook Pro at https://
> > lore.kernel.org/all/aUKOlj-RvTYlrpiS at rock.grzadka/; the regression
> > was reverted in 29d1f56c4f3001b7f547123e0a307c009ac717f8. The errors
> > faced on the Pinephone Pro are exactly the same as were reported for
> > the Pinebook Pro regression.
> > 
> > A previous patch at https://lore.kernel.org/all/20260112-
> > ppp_connectivity-v1-3-284d6e83b212 at gmail.com/ attempted to resolve
> > this issue but never ended up being merged.
> > 
> > 096bd8c679185f898cae9933c6a68650fa26ea4f is the first bad commit
> > commit 096bd8c679185f898cae9933c6a68650fa26ea4f
> > Author: Peter Robinson <pbrobinson at gmail.com>
> > Date:   Fri Aug 29 12:38:24 2025 +0100
> > 
> >     arm64: dts: rockchip: Further describe the WiFi for the Pinephone Pro
> > [...]
> > 
> > Reverting the commit allows wireless connection to function again. I
> > am not really familiar with the process of submitting a revert
> > patch, but I'd request that this be done on all of 6.18 (LTS), 7.0
> > (Stable), 7.1 (Mainline). Thanks!
> Thx for the report. Sounds like a revert is the right course of action
> here. Could you submit one with a stable tag to ensure backporting? That
> might be the fastest way to resolve this, as that makes it easy to
> process for the maintainers to process this.

Was confused for like 5 minutes because "didn't we do that just recently",
until realizing, that it's the Pinephone this time, not the Pinebook.

So we'd need a similar one to
https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git/commit/?h=for-next&id=29d1f56c4f3001b7f547123e0a307c009ac717f8


Heiko




From jani.nikula at linux.intel.com  Wed Jun 10 03:32:29 2026
From: jani.nikula at linux.intel.com (Jani Nikula)
Date: Wed, 10 Jun 2026 13:32:29 +0300
Subject: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge
 chain format selection
In-Reply-To: <20260609-color-format-v17-21-35739b5782cc@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
 <20260609-color-format-v17-21-35739b5782cc@collabora.com>
Message-ID: <04ff70850213ae0f75486b1a27a7edb6fb4e71c3@intel.com>

On Tue, 09 Jun 2026, Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:
> diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
> index 64b665580a88..92f142ca6695 100644
> --- a/drivers/gpu/drm/tests/drm_bridge_test.c
> +++ b/drivers/gpu/drm/tests/drm_bridge_test.c
> @@ -2,15 +2,23 @@
>  /*
>   * Kunit test for drm_bridge functions
>   */
> +#include <linux/cleanup.h>
> +#include <linux/media-bus-format.h>
> +
>  #include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
>  #include <drm/drm_bridge.h>
>  #include <drm/drm_bridge_connector.h>
>  #include <drm/drm_bridge_helper.h>
> +#include <drm/drm_edid.h>
>  #include <drm/drm_kunit_helpers.h>
> +#include <drm/drm_managed.h>
>  
>  #include <kunit/device.h>
>  #include <kunit/test.h>
>  
> +#include "drm_kunit_edid.h"

So here's the problem with adding *any* arrays into headers: every
compilation unit that includes them duplicates all the arrays. It's only
really okay for single use.

And, in this case, most of the included arrays are unused, leading to
build failures:

  CC [M]  drivers/gpu/drm/tests/drm_bridge_test.o
In file included from ../drivers/gpu/drm/tests/drm_bridge_test.c:21:
../drivers/gpu/drm/tests/drm_kunit_edid.h:958:28: error: ?test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz? defined but not used [-Werror=unused-const-variable=]
  958 | static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:726:28: error: ?test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz? defined but not used [-Werror=unused-const-variable=]
  726 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:612:28: error: ?test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz? defined but not used [-Werror=unused-const-variable=]
  612 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:498:28: error: ?test_edid_hdmi_1080p_rgb_max_340mhz? defined but not used [-Werror=unused-const-variable=]
  498 | static const unsigned char test_edid_hdmi_1080p_rgb_max_340mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:390:28: error: ?test_edid_hdmi_1080p_rgb_max_200mhz_hdr? defined but not used [-Werror=unused-const-variable=]
  390 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz_hdr[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:271:28: error: ?test_edid_hdmi_1080p_rgb_max_200mhz? defined but not used [-Werror=unused-const-variable=]
  271 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:163:28: error: ?test_edid_hdmi_1080p_rgb_max_100mhz? defined but not used [-Werror=unused-const-variable=]
  163 | static const unsigned char test_edid_hdmi_1080p_rgb_max_100mhz[] = {
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../drivers/gpu/drm/tests/drm_kunit_edid.h:57:28: error: ?test_edid_dvi_1080p? defined but not used [-Werror=unused-const-variable=]
   57 | static const unsigned char test_edid_dvi_1080p[] = {
      |                            ^~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

This breaks the build for me, I don't know how it didn't for any of you.

Reverting these two fixes it:

ce1d0139adac ("drm/tests: bridge: Add test for HDMI output bus formats helper")
082fbc179c01 ("drm/tests: bridge: Add KUnit tests for bridge chain format selection")

I think the proper fix would be to move the arrays into a .c file, and
only have declarations in the headers. But that needs to happen real
soon or the commits need to be reverted.


BR,
Jani.


-- 
Jani Nikula, Intel


From piotr.oniszczuk at gmail.com  Wed Jun 10 03:43:13 2026
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Wed, 10 Jun 2026 12:43:13 +0200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
 <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>
Message-ID: <2CB1844A-3DB7-4973-98E0-0C141DD38B45@gmail.com>

Simon, pls see inline

> Wiadomo?? napisana przez Simon Wright <Simon at symple.nz> w dniu 10 cze 2026, o godz. 00:14:
> 
> 
>    git clone https://github.com/SympleNZ/rkvdec-vdpu383-vp9
>    cd rkvdec-vdpu383-vp9
>    # against your running kernel's headers/source:
>    KBUILD_MODPOST_WARN=1 make -C /lib/modules/$(uname -r)/build M=$PWD/src modules
> 
>    sudo rmmod rockchip_vdec 2>/dev/null    # unload the in-tree driver
>    sudo insmod src/rockchip-vdec.ko        # warmup is default-on, no params needed
> 

Many thx for detailed hints.

I decided to go with alternative path: I incorporated Your code directly into in-tree on 7.1 mainline, recompiled and give test run on rock4d.  
I think I'm getting Your code running as in dmesg I see: https://gist.github.com/warpme/51bce9532baa37ccb59e1c69a5c2ef43

Unfortunately mine rk3576 h264 issues still happens (approx 5-40% failure rate; only on 3576; only on h264) 
Visually issue is like this: https://ibb.co/gZT6vMZD

Interesting is: mine issue symptoms are imho similar to yours:
1. approx. 5-20% failure rate (but varies per board)
2. only on 3576
3. only on h264

Ad1: some boards have quite low rate: nanopi is few % while rock4d is really high (20-40%)

Ad2: i have single appliance image for >40 boards and only 3576 has this issue

Ad3: on 3576 issue happens only on h264. HEVC, vp9, etc are ok. 


> (If rockchip-vdec is built into your kernel rather than a module, you'll need it as
> a module - or blacklisted - first. The module name may differ slightly on your
> build.)
> 
> Then decode your H.264 as usual (v4l2slh264dec) and compare against avdec_h264 - the
> rows-4/12 corruption should be gone. That repo is the VP9 work, but its src/ builds
> the full VDPU381/383 H.264/H.265/VP9/AV1 driver, so H.264 is included.

Should I collect stats on mine hw or rather maybe I should test the solution (when we will have it)?  

> 
> One honest caveat for the media-player use case: the warmup fixes correctness (the
> wrong pixels), not throughput - and the throughput limit isn't specific to H.264.

Indeed - I see also issue with throughput on 3576.
Iirc 3588 can go with 300mbps samples while 3576 starts to drop on 13...15mbps 




From nicolas.frattaroli at collabora.com  Wed Jun 10 04:42:35 2026
From: nicolas.frattaroli at collabora.com (Nicolas Frattaroli)
Date: Wed, 10 Jun 2026 13:42:35 +0200
Subject: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge chain
 format selection
In-Reply-To: <04ff70850213ae0f75486b1a27a7edb6fb4e71c3@intel.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
 <20260609-color-format-v17-21-35739b5782cc@collabora.com>
 <04ff70850213ae0f75486b1a27a7edb6fb4e71c3@intel.com>
Message-ID: <gnicb4WkT1S4aQIC2G_naw@collabora.com>

On Wednesday, 10 June 2026 12:32:29 Central European Summer Time Jani Nikula wrote:
> On Tue, 09 Jun 2026, Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:
> > diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
> > index 64b665580a88..92f142ca6695 100644
> > --- a/drivers/gpu/drm/tests/drm_bridge_test.c
> > +++ b/drivers/gpu/drm/tests/drm_bridge_test.c
> > @@ -2,15 +2,23 @@
> >  /*
> >   * Kunit test for drm_bridge functions
> >   */
> > +#include <linux/cleanup.h>
> > +#include <linux/media-bus-format.h>
> > +
> >  #include <drm/drm_atomic_state_helper.h>
> > +#include <drm/drm_atomic_uapi.h>
> >  #include <drm/drm_bridge.h>
> >  #include <drm/drm_bridge_connector.h>
> >  #include <drm/drm_bridge_helper.h>
> > +#include <drm/drm_edid.h>
> >  #include <drm/drm_kunit_helpers.h>
> > +#include <drm/drm_managed.h>
> >  
> >  #include <kunit/device.h>
> >  #include <kunit/test.h>
> >  
> > +#include "drm_kunit_edid.h"
> 
> So here's the problem with adding *any* arrays into headers: every
> compilation unit that includes them duplicates all the arrays. It's only
> really okay for single use.
> 
> And, in this case, most of the included arrays are unused, leading to
> build failures:
> 
>   CC [M]  drivers/gpu/drm/tests/drm_bridge_test.o
> In file included from ../drivers/gpu/drm/tests/drm_bridge_test.c:21:
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:958:28: error: ?test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz? defined but not used [-Werror=unused-const-variable=]
>   958 | static const unsigned char test_edid_hdmi_4k_rgb_yuv420_dc_max_340mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:726:28: error: ?test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz? defined but not used [-Werror=unused-const-variable=]
>   726 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_340mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:612:28: error: ?test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz? defined but not used [-Werror=unused-const-variable=]
>   612 | static const unsigned char test_edid_hdmi_1080p_rgb_yuv_dc_max_200mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:498:28: error: ?test_edid_hdmi_1080p_rgb_max_340mhz? defined but not used [-Werror=unused-const-variable=]
>   498 | static const unsigned char test_edid_hdmi_1080p_rgb_max_340mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:390:28: error: ?test_edid_hdmi_1080p_rgb_max_200mhz_hdr? defined but not used [-Werror=unused-const-variable=]
>   390 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz_hdr[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:271:28: error: ?test_edid_hdmi_1080p_rgb_max_200mhz? defined but not used [-Werror=unused-const-variable=]
>   271 | static const unsigned char test_edid_hdmi_1080p_rgb_max_200mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:163:28: error: ?test_edid_hdmi_1080p_rgb_max_100mhz? defined but not used [-Werror=unused-const-variable=]
>   163 | static const unsigned char test_edid_hdmi_1080p_rgb_max_100mhz[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../drivers/gpu/drm/tests/drm_kunit_edid.h:57:28: error: ?test_edid_dvi_1080p? defined but not used [-Werror=unused-const-variable=]
>    57 | static const unsigned char test_edid_dvi_1080p[] = {
>       |                            ^~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
> 
> This breaks the build for me, I don't know how it didn't for any of you.

It broke the build for me in the past[1], but then I couldn't repro
it anymore when challenged on my fix[2].

> 
> Reverting these two fixes it:
> 
> ce1d0139adac ("drm/tests: bridge: Add test for HDMI output bus formats helper")
> 082fbc179c01 ("drm/tests: bridge: Add KUnit tests for bridge chain format selection")
> 
> I think the proper fix would be to move the arrays into a .c file, and
> only have declarations in the headers. But that needs to happen real
> soon or the commits need to be reverted.

If you don't want __maybe_unused, then sure, I'll move them into a new
.c file. Though I think the two are roughly equivalent in that I don't
think anyone is really trying to minimise the size of their KUnit
binaries.

I'll send a patch to move them to a .c

[1]: https://lore.kernel.org/dri-devel/20260121-color-format-v7-20-ef790dae780c at collabora.com/
[2]: https://lore.kernel.org/dri-devel/20260210-didactic-okapi-of-modernism-ff00d9 at houat/

Kind regards,
Nicolas Frattaroli

> 
> BR,
> Jani.
> 
> 
> 






From jani.nikula at linux.intel.com  Wed Jun 10 04:54:29 2026
From: jani.nikula at linux.intel.com (Jani Nikula)
Date: Wed, 10 Jun 2026 14:54:29 +0300
Subject: [PATCH v17 21/28] drm/tests: bridge: Add KUnit tests for bridge
 chain format selection
In-Reply-To: <gnicb4WkT1S4aQIC2G_naw@collabora.com>
References: <20260609-color-format-v17-0-35739b5782cc@collabora.com>
 <20260609-color-format-v17-21-35739b5782cc@collabora.com>
 <04ff70850213ae0f75486b1a27a7edb6fb4e71c3@intel.com>
 <gnicb4WkT1S4aQIC2G_naw@collabora.com>
Message-ID: <596f0f063d6ef2ffb4c6640e3df5ed89d95b11dd@intel.com>

On Wed, 10 Jun 2026, Nicolas Frattaroli <nicolas.frattaroli at collabora.com> wrote:
> If you don't want __maybe_unused, then sure, I'll move them into a new
> .c file. Though I think the two are roughly equivalent in that I don't
> think anyone is really trying to minimise the size of their KUnit
> binaries.

I think placing arrays in headers is bad practice, and we shouldn't set
that example, kunit or not.

> I'll send a patch to move them to a .c

Thanks.

BR,
Jani.


-- 
Jani Nikula, Intel


From midgy971 at gmail.com  Wed Jun 10 06:38:24 2026
From: midgy971 at gmail.com (Midgy Balon)
Date: Wed, 10 Jun 2026 15:38:24 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <DJ5A9XL183RZ.20J3ASQ3EWUZ6@cknow-tech.com>
References: <20260604135255.62682-1-midgy971@gmail.com> <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com> <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
 <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com> <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
 <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com> <DJ5A9XL183RZ.20J3ASQ3EWUZ6@cknow-tech.com>
Message-ID: <CA+GS1Y1xAq-9eMyMmoVE6NG9KLG7XRxgPoSr5RkW=6fT5D820g@mail.gmail.com>

Hello Chaoyi & Diederik,

I compared the RK3568 and RK3588 NPU power-domain + DTS as you
suggested, and it lines up
exactly with what you described.

The difference is the `need_regulator` capability. RK3588's NPU domain is
`DOMAIN_RK3588("npu", ?, false, true)` ? the trailing `true` is
`regulator`/`need_regulator`.
The mainline RK3568 macro `DOMAIN_RK3568(name, pwr, req, wakeup)` has
no regulator parameter at
all, so `RK3568_PD_NPU` can't be marked need_regulator. My v4 adds
that: a regulator-capable
RK3568 NPU domain (need_regulator = true) plus `domain-supply =
<&vdd_npu>` on the NPU node ?
i.e. the same shape as RK3588.

And the fix you referenced (Frank Zhang's "pmdomain: rockchip: Fix init genpd as
GENPD_STATE_ON before regulator ready", plus "quiet regulator error on
-EPROBE_DEFER") is
already in my base (v7.1-rc6), so the `if (need_regulator)
rockchip_pd_power(pd, false)`
default-off path is in effect. That's what resolves the actual problem
for me: with rocket
built as a module (the normal config), need_regulator on the NPU
domain, and those pmdomain
patches in place, the board boots cleanly and NPU jobs run with no RCU
stall / no deadlock. My
earlier hang was an artifact of a self-contained rocket=y image
probing in the initcalls before
the I2C regulator core was up ? as a module it loads ~6.8 s in, well
after, so it's gone.

I also went back and checked the `fw_devlink=permissive` question
myself ? and good news, it
turns out it is NOT needed. I rebooted the exact same kernel with
permissive removed from the
cmdline (strict fw_devlink, the default), and the board boots cleanly,
the NPU probes
(`rocket fde40000.npu: Rockchip NPU core 0 version: 0`), and NPU jobs
submit and run five times
in a row with no deadlock and no RCU stall. So strict fw_devlink
resolves the NPU/PMIC ordering
fine via deferred probe.

The one remaining thing is cosmetic: at power-domain-controller probe
(~2.94 s) I still get,
in BOTH modes (with or without permissive):

  rockchip-pm-domain ?: Failed to create device link (0x180) with
supplier 0-0020 ?power-domain at 6

i.e. genpd can't form the link to the rk809 (the I2C PMIC supplying
vdd_npu) because the PMIC
isn't registered yet at that point. It's non-fatal ? the domain
defaults off (Frank's patch),
the rail comes up via the regulator core, the NPU probes a few seconds
later, and all jobs run.

One question: on RK3588 with need_regulator, do you also see that
"Failed to create device
link ? supplier <pmic>" line at pmdomain probe, or does it order
cleanly? If RK3588 is clean,
is there a DTS detail (e.g. the regulator's bus/probe order) I should
mirror on RK3568 to make
the link form in time ? or is this line just expected/harmless and
best left as-is?

@Diederik ? thanks; the DCDC_REG2 change and Jonas's USB-suspend
series look like generally
useful RK356x robustness fixes, though for this specific NPU
device-link the need_regulator +
Frank's pmdomain patches seem to be the relevant piece. I'll keep them
in mind for suspend.

The convolution-output / compute-completion issue is still separate
and open (@Finley ? that's
the PVTPLL/NoC one); the power-domain side is in good shape for v4.

Thanks y'all for your help :)

Kind regards,
Midgy

Le mer. 10 juin 2026 ? 12:05, Diederik de Haas
<diederik at cknow-tech.com> a ?crit :
>
> Hi,
>
> On Wed Jun 10, 2026 at 3:14 AM CEST, Chaoyi Chen wrote:
> > Hi Midgy,
> >
> > On 6/9/2026 7:11 PM, Midgy Balon wrote:
> >> Hello Chaoyi,
> >>
> >> You were right - building rocket as a module fixes it. Thanks for the pointer.
> >>
> >> I rebuilt with CONFIG_DRM_ACCEL_ROCKET=m (everything else the same:
> >> need_regulator on
> >> the RK3568 NPU power domain via a DOMAIN_M_R variant, domain-supply =
> >> <&vdd_npu>, and the
> >> regulator-always-on workaround dropped). The board now boots cleanly
> >> and, more importantly,
> >> an NPU job submit no longer hangs: I ran the test workload five times
> >> with no RCU stall and
> >> no freeze.
> >>
> >> So with rocket=m the need_regulator approach works on RK3568, and I'll
> >> keep it for v4
> >> (domain-supply + need_regulator, instead of marking vdd_npu
> >> always-on). rocket=m is the
> >> normal configuration anyway; my earlier hang came from building it =y
> >> in a self-contained
> >> image, so it probed in the initcalls (around 2 s) and the genpd ->
> >> I2C-PMIC regulator
> >> transition ran before the system was ready. As a module it loads from
> >> udev much later
> >> (~6.8 s here), after the I2C controller and regulator core are fully up.
> >>
> >> On your question of when the device-link error is printed - it is at
> >> power-domain
> >> controller probe, not at the rocket probe:
> >>
> >>   [    2.700618] vdd_npu: Bringing 500000uV into 825000-825000uV
> >>   [    2.749637] rockchip-pm-domain fdd90000.power-management:power-controller:
> >>                  Failed to create device link (0x180) with supplier 0-0020 for
> >>                  /power-management at fdd90000/power-controller/power-domain at 6
> >>   [    2.945955] platform fde40000.npu: Adding to iommu group 3
> >>   ...
> >>   [    6.840374] rocket: loading out-of-tree module taints kernel.
> >>   [    6.877647] [drm] Initialized rocket 0.0.0 for rknn on minor 0
> >>   [    6.879950] rocket fde40000.npu: Rockchip NPU core 0 version: 0
> >>
> >> So the device-link to the rk809 PMIC (0-0020) fails to form at ~2.75
> >> s, well before rocket
> >> loads at ~6.8 s. It is non-fatal here - the vdd_npu rail is brought up
> >> by the regulator core
> >> and all jobs run - and there is no "failed to get ack on domain npu"
> >> NoC warning this boot
> >> (the always-on kernel had one). The complete boot log is attached.
> >>
> >> Two notes / one question:
> >> - This boot used fw_devlink=permissive on the command line. Is the
> >> "Failed to create device
> >>   link ... supplier 0-0020" at pmdomain probe expected/benign, or is
> >> there a clean way to make
> >>   it order correctly (so it also works without permissive, and a =y
> >> build wouldn't deadlock in
> >>   the initcalls)?
> >
> > We encountered the same issue on the RK3588 NPU before. And it was
> > resolved with the following patch at that time.
> >
> > https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/
> >
> > Please compare the differences in NPU pmdomain and DTS configuration
> > between the RK3568 and RK3588.
>
> About a month ago on #linux-rockchip we were discussing PM 'stuff':
> https://libera.catirclogs.org/linux-rockchip/2026-05-15#39939137;
> which references this paste
> https://paste.sr.ht/~diederik/89d9f84e22474e837b55286d213b67f03859ce2e
> I've since removed the DCDC_REG2 for PineTab2 and the 'fix' should likely
> be extended to cover all RK3566/RK3568 devices though.
>
> It's what I made at the time hoping to fix a suspend/resume issue when
> trying upstream TF-A. It didn't fix the issue at the time, but may still
> be useful/needed and I think it's what Chaoyi hinted at.
>
> Just yesterday, Jonas posted this patch which may be useful/needed too:
> https://lore.kernel.org/linux-rockchip/20260609154124.445182-1-jonas at kwiboo.se/
>
> HTH,
>   Diederik
>
> >> - (The convolution output is still uniform zero-point / the job times
> >> out - that is the
> >>   separate NPU compute-completion issue, unrelated to the power-domain
> >> work. Finley, that is
> >>   the one I flagged earlier re PVTPLL/NoC.)
> >>
> >> Kind regards,
> >> Midgy
> >>
>


From hello at superkali.me  Wed Jun 10 06:58:58 2026
From: hello at superkali.me (Daniele Briguglio)
Date: Wed, 10 Jun 2026 15:58:58 +0200
Subject: [PATCH 1/3] dt-bindings: vendor-prefixes: Add youyeetoo
In-Reply-To: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
References: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
Message-ID: <20260610-yy3588-board-v1-1-4bb7176b6826@superkali.me>

Youyeetoo is the single board computer brand of Hong Kong Cybodev
Tech Limited.

Link: https://www.youyeetoo.com
Signed-off-by: Daniele Briguglio <hello at superkali.me>
---
 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 28784d66a..c0d05ba73 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1915,6 +1915,8 @@ patternProperties:
     description: YSH & ATIL
   "^yones-toptech,.*":
     description: Yones Toptech Co., Ltd.
+  "^youyeetoo,.*":
+    description: Hong Kong Cybodev Tech Limited (youyeetoo)
   "^ys,.*":
     description: Shenzhen Yashi Changhua Intelligent Technology Co., Ltd.
   "^ysoft,.*":

-- 
2.47.3



From hello at superkali.me  Wed Jun 10 06:58:59 2026
From: hello at superkali.me (Daniele Briguglio)
Date: Wed, 10 Jun 2026 15:58:59 +0200
Subject: [PATCH 2/3] dt-bindings: arm: rockchip: Add Youyeetoo YY3588
In-Reply-To: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
References: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
Message-ID: <20260610-yy3588-board-v1-2-4bb7176b6826@superkali.me>

The YY3588 is a single board computer based on the Rockchip RK3588.
Add devicetree binding documentation for it.

Signed-off-by: Daniele Briguglio <hello at superkali.me>
---
 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 1a9dde186..e7894d2b8 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -1347,6 +1347,11 @@ properties:
           - const: xunlong,orangepi-cm5
           - const: rockchip,rk3588s
 
+      - description: Youyeetoo YY3588
+        items:
+          - const: youyeetoo,yy3588
+          - const: rockchip,rk3588
+
       - description: Zkmagic A95X Z2
         items:
           - const: zkmagic,a95x-z2

-- 
2.47.3



From hello at superkali.me  Wed Jun 10 06:58:57 2026
From: hello at superkali.me (Daniele Briguglio)
Date: Wed, 10 Jun 2026 15:58:57 +0200
Subject: [PATCH 0/3] arm64: dts: rockchip: Add Youyeetoo YY3588
Message-ID: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>

This series adds support for the Youyeetoo YY3588, a single board
computer built around the Rockchip RK3588.

Both Ethernet ports, eMMC, SD card, USB, Type-C, HDMI output, WiFi on
the Mini PCIe slot, audio, the recovery key and the fan have been
tested on the board.

Board documentation: https://wiki.youyeetoo.com/YY3588

Signed-off-by: Daniele Briguglio <hello at superkali.me>
---
Daniele Briguglio (3):
      dt-bindings: vendor-prefixes: Add youyeetoo
      dt-bindings: arm: rockchip: Add Youyeetoo YY3588
      arm64: dts: rockchip: Add Youyeetoo YY3588

 .../devicetree/bindings/arm/rockchip.yaml          |    5 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 arch/arm64/boot/dts/rockchip/Makefile              |    1 +
 .../boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts  | 1190 ++++++++++++++++++++
 4 files changed, 1198 insertions(+)
---
base-commit: 8545eda00fdf3d7e17933ce0f706d005b1bad42d
change-id: 20260610-yy3588-board-ecc20882cae7

Best regards,
--  
Daniele Briguglio <hello at superkali.me>



From hello at superkali.me  Wed Jun 10 06:59:00 2026
From: hello at superkali.me (Daniele Briguglio)
Date: Wed, 10 Jun 2026 15:59:00 +0200
Subject: [PATCH 3/3] arm64: dts: rockchip: Add Youyeetoo YY3588
In-Reply-To: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
References: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
Message-ID: <20260610-yy3588-board-v1-3-4bb7176b6826@superkali.me>

The YY3588 is a single board computer built around the Rockchip RK3588.

Specification:
- Rockchip RK3588 SoC
- 4/8/16/32 GB LPDDR4/4x
- up to 256 GB eMMC
- microSD card slot
- 1x 1000Base-T (Realtek RTL8211F) and 1x 2500Base-T (Realtek RTL8125)
- HDMI 2.1 output
- HDMI input
- 4x USB 3.0 Type-A via onboard hub, 1x USB 2.0 Type-A
- USB Type-C with USB 3.0
- M.2 M-key with PCIe 3.0 x4
- Mini PCIe slot for WiFi/BT or 4G modules
- SATA 3.0
- ES8388 audio codec with headphone jack and onboard microphone
- fan connector, RTC, recovery key
- 12 V DC input

Both Ethernet ports, eMMC, SD card, USB, Type-C, HDMI output, WiFi
on the Mini PCIe slot, audio, the recovery key and the fan have been
tested on the board.

Link: https://wiki.youyeetoo.com/YY3588
Signed-off-by: Daniele Briguglio <hello at superkali.me>
---
 arch/arm64/boot/dts/rockchip/Makefile              |    1 +
 .../boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts  | 1190 ++++++++++++++++++++
 2 files changed, 1191 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index 761d82b4f..6cab03c9c 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -213,6 +213,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-tiger-haikou-video-demo.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-toybrick-x0.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-youyeetoo-yy3588.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-evb1-v10.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-gameforce-ace.dtb
diff --git a/arch/arm64/boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts b/arch/arm64/boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts
new file mode 100644
index 000000000..28d8790a2
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3588-youyeetoo-yy3588.dts
@@ -0,0 +1,1190 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2024 Youyeetoo
+ * Copyright (c) 2026 Daniele Briguglio <hello at superkali.me>
+ */
+
+/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/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+#include "rk3588.dtsi"
+
+/ {
+	model = "Youyeetoo YY3588";
+	compatible = "youyeetoo,yy3588", "rockchip,rk3588";
+
+	aliases {
+		ethernet0 = &gmac1;
+		ethernet1 = &r8125;
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+	};
+
+	adc-keys {
+		compatible = "adc-keys";
+		io-channels = <&saradc 1>;
+		io-channel-names = "buttons";
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <100>;
+
+		button-recovery {
+			label = "Recovery";
+			linux,code = <KEY_VENDOR>;
+			press-threshold-microvolt = <17000>;
+		};
+	};
+
+	analog-sound {
+		compatible = "simple-audio-card";
+		pinctrl-names = "default";
+		pinctrl-0 = <&hp_det>;
+		simple-audio-card,name = "rockchip-es8388";
+		simple-audio-card,aux-devs = <&speaker_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio1 RK_PC4 GPIO_ACTIVE_LOW>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,pin-switches = "Headphones", "Speaker";
+		simple-audio-card,routing =
+			"Headphones", "LOUT2",
+			"Headphones", "ROUT2",
+			"Speaker Amp INL", "LOUT1",
+			"Speaker Amp INR", "ROUT1",
+			"Speaker", "Speaker Amp OUTL",
+			"Speaker", "Speaker Amp OUTR",
+			"LINPUT1", "Microphone Jack",
+			"RINPUT1", "Microphone Jack",
+			"LINPUT2", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone";
+		simple-audio-card,widgets =
+			"Microphone", "Microphone Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Speaker";
+
+		simple-audio-card,cpu {
+			sound-dai = <&i2s0_8ch>;
+		};
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+
+	hdmi0-con {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi0_con_in: endpoint {
+				remote-endpoint = <&hdmi0_out_con>;
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		led-0 {
+			color = <LED_COLOR_ID_BLUE>;
+			function = LED_FUNCTION_STATUS;
+			gpios = <&gpio1 RK_PD6 GPIO_ACTIVE_HIGH>;
+		};
+
+		led-1 {
+			function = LED_FUNCTION_HEARTBEAT;
+			gpios = <&gpio1 RK_PD7 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+
+	/* PI6C557-05BLE PCIe 3.0 reference clock generator */
+	pcie30_port0_refclk: pcie-oscillator {
+		compatible = "gated-fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <100000000>;
+		clock-output-names = "pcie30_refclk";
+		vdd-supply = <&vcc3v3_pi6c_05>;
+	};
+
+	fan: pwm-fan {
+		compatible = "pwm-fan";
+		#cooling-cells = <2>;
+		cooling-levels = <0 50 100 150 200 255>;
+		fan-supply = <&vcc12v_dcin>;
+		pwms = <&pwm2 0 50000 0>;
+	};
+
+	pcie20_avdd0v85: regulator-pcie20-avdd0v85 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd0v85";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <850000>;
+		regulator-max-microvolt = <850000>;
+		vin-supply = <&vdd_0v85_s0>;
+	};
+
+	pcie20_avdd1v8: regulator-pcie20-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie20_avdd1v8";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	pcie30_avdd0v75: regulator-pcie30-avdd0v75 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd0v75";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <750000>;
+		regulator-max-microvolt = <750000>;
+		vin-supply = <&avdd_0v75_s0>;
+	};
+
+	pcie30_avdd1v8: regulator-pcie30-avdd1v8 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie30_avdd1v8";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1800000>;
+		regulator-max-microvolt = <1800000>;
+		vin-supply = <&avcc_1v8_s0>;
+	};
+
+	vbus5v0_typec: regulator-vbus5v0-typec {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio4 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&typec5v_pwren>;
+		regulator-name = "vbus5v0_typec";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_1v1_nldo_s3";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <1100000>;
+		regulator-max-microvolt = <1100000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc12v_dcin: regulator-vcc12v-dcin {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc12v_dcin";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <12000000>;
+		regulator-max-microvolt = <12000000>;
+	};
+
+	vcc3v3_pi6c_05: regulator-vcc3v3-pi6c-05 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpios = <&gpio2 RK_PC5 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pi6c_05_pwren>;
+		regulator-name = "vcc3v3_pi6c_05";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		startup-delay-us = <5000>;
+		vin-supply = <&vcc5v0_sys>;
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc3v3_sys>;
+	};
+
+	vcc3v3_sys: regulator-vcc3v3-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc3v3_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	vcc5v0_sys: regulator-vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		vin-supply = <&vcc12v_dcin>;
+	};
+
+	speaker_amp: speaker-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&spk_en>;
+		sound-name-prefix = "Speaker Amp";
+		VCC-supply = <&vcc5v0_sys>;
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&combphy1_ps {
+	status = "okay";
+};
+
+&combphy2_psu {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big0_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big1_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&gmac1 {
+	clock_in_out = "input";
+	phy-handle = <&rgmii_phy>;
+	/* RX delay is added by the PHY, TX delay by the GMAC */
+	phy-mode = "rgmii-rxid";
+	pinctrl-names = "default";
+	pinctrl-0 = <&gmac1_miim
+		     &gmac1_tx_bus2
+		     &gmac1_rx_bus2
+		     &gmac1_rgmii_clk
+		     &gmac1_rgmii_bus
+		     &gmac1_clkinout>;
+	tx_delay = <0x43>;
+	status = "okay";
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi0 {
+	frl-enable-gpios = <&gpio4 RK_PB1 GPIO_ACTIVE_LOW>;
+	status = "okay";
+};
+
+&hdmi0_in {
+	hdmi0_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi0>;
+	};
+};
+
+&hdmi0_out {
+	hdmi0_out_con: endpoint {
+		remote-endpoint = <&hdmi0_con_in>;
+	};
+};
+
+&hdmi0_sound {
+	status = "okay";
+};
+
+&hdmi_receiver_cma {
+	status = "okay";
+};
+
+&hdmi_receiver {
+	hpd-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_5v_det>;
+	status = "okay";
+};
+
+&hdptxphy0 {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0m2_xfer>;
+	status = "okay";
+
+	vdd_cpu_big0_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_cpu_big0_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vdd_cpu_big1_s0: regulator at 43 {
+		compatible = "rockchip,rk8603", "rockchip,rk8602";
+		reg = <0x43>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_cpu_big1_s0";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <1050000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1m2_xfer>;
+	status = "okay";
+
+	vdd_npu_s0: regulator at 42 {
+		compatible = "rockchip,rk8602";
+		reg = <0x42>;
+		fcs,suspend-voltage-selector = <1>;
+		regulator-name = "vdd_npu_s0";
+		regulator-boot-on;
+		regulator-min-microvolt = <550000>;
+		regulator-max-microvolt = <950000>;
+		regulator-ramp-delay = <2300>;
+		vin-supply = <&vcc5v0_sys>;
+
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&i2c6 {
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c6m0_xfer>;
+	status = "okay";
+
+	usbc0: usb-typec at 22 {
+		compatible = "fcs,fusb302";
+		reg = <0x22>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD3 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbc0_int>;
+		vbus-supply = <&vbus5v0_typec>;
+
+		usb_con: connector {
+			compatible = "usb-c-connector";
+			data-role = "dual";
+			label = "USB-C";
+			power-role = "source";
+			source-pdos = <PDO_FIXED(5000, 1500, PDO_FIXED_USB_COMM)>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+
+					usbc0_hs: endpoint {
+						remote-endpoint = <&usb_host0_xhci_drd_sw>;
+					};
+				};
+
+				port at 1 {
+					reg = <1>;
+
+					usbc0_ss: endpoint {
+						remote-endpoint = <&usbdp_phy0_typec_ss>;
+					};
+				};
+
+				port at 2 {
+					reg = <2>;
+
+					usbc0_sbu: endpoint {
+						remote-endpoint = <&usbdp_phy0_typec_sbu>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+	};
+};
+
+&i2c7 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c7m0_xfer>;
+	status = "okay";
+
+	es8388: audio-codec at 11 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x11>;
+		assigned-clocks = <&cru I2S0_8CH_MCLKOUT>;
+		assigned-clock-rates = <12288000>;
+		clocks = <&cru I2S0_8CH_MCLKOUT>;
+		AVDD-supply = <&vcc3v3_sys>;
+		DVDD-supply = <&vcc_1v8_s3>;
+		HPVDD-supply = <&vcc3v3_sys>;
+		PVDD-supply = <&vcc_1v8_s3>;
+		#sound-dai-cells = <0>;
+	};
+};
+
+&i2s0_8ch {
+	pinctrl-0 = <&i2s0_lrck
+		     &i2s0_mclk
+		     &i2s0_sclk
+		     &i2s0_sdi0
+		     &i2s0_sdo0>;
+	status = "okay";
+};
+
+&i2s5_8ch {
+	status = "okay";
+};
+
+&i2s7_8ch {
+	status = "okay";
+};
+
+&mdio1 {
+	rgmii_phy: ethernet-phy at 1 {
+		/* RTL8211F */
+		compatible = "ethernet-phy-id001c.c916";
+		reg = <0x1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&rtl8211f_rst>;
+		reset-assert-us = <20000>;
+		reset-deassert-us = <100000>;
+		reset-gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+	};
+};
+
+&package_thermal {
+	polling-delay = <1000>;
+
+	trips {
+		package_fan0: package-fan0 {
+			temperature = <55000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+
+		package_fan1: package-fan1 {
+			temperature = <65000>;
+			hysteresis = <2000>;
+			type = "active";
+		};
+	};
+
+	cooling-maps {
+		map0 {
+			trip = <&package_fan0>;
+			cooling-device = <&fan THERMAL_NO_LIMIT 1>;
+		};
+
+		map1 {
+			trip = <&package_fan1>;
+			cooling-device = <&fan 2 THERMAL_NO_LIMIT>;
+		};
+	};
+};
+
+&pcie2x1l0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_0_rst>;
+	reset-gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_sys>;
+	status = "okay";
+};
+
+&pcie2x1l1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_1_rst>;
+	reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_sys>;
+	status = "okay";
+
+	pcie at 0,0 {
+		reg = <0x300000 0 0 0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		ranges;
+		device_type = "pci";
+		bus-range = <0x30 0x3f>;
+
+		r8125: ethernet at 0,0 {
+			reg = <0x310000 0 0 0 0>;
+		};
+	};
+};
+
+&pcie30phy {
+	status = "okay";
+};
+
+&pcie3x4 {
+	clocks = <&cru ACLK_PCIE_4L_MSTR>, <&cru ACLK_PCIE_4L_SLV>,
+		 <&cru ACLK_PCIE_4L_DBI>, <&cru PCLK_PCIE_4L>,
+		 <&cru CLK_PCIE_AUX0>, <&cru CLK_PCIE4L_PIPE>,
+		 <&pcie30_port0_refclk>;
+	clock-names = "aclk_mst", "aclk_slv",
+		      "aclk_dbi", "pclk",
+		      "aux", "pipe",
+		      "ref";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie3x4_perstn>;
+	reset-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc3v3_sys>;
+	status = "okay";
+};
+
+&pinctrl {
+	hdmirx {
+		hdmirx_5v_det: hdmirx-5v-det {
+			rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	leds {
+		led_pins: led-pins {
+			rockchip,pins = <1 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>,
+					<1 RK_PD7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		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>;
+		};
+
+		pi6c_05_pwren: pi6c-05-pwren {
+			rockchip,pins = <2 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		pcie3x4_perstn: pcie3x4-perstn {
+			rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtl8211f {
+		rtl8211f_rst: rtl8211f-rst {
+			rockchip,pins = <3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	sound {
+		hp_det: hp-det {
+			rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		spk_en: spk-en {
+			rockchip,pins = <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	usb {
+		typec5v_pwren: typec5v-pwren {
+			rockchip,pins = <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		usbc0_int: usbc0-int {
+			rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
+
+&pwm2 {
+	pinctrl-0 = <&pwm2m2_pins>;
+	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";
+};
+
+&sata0 {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	no-sd;
+	no-sdio;
+	non-removable;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi2 {
+	assigned-clocks = <&cru CLK_SPI2>;
+	assigned-clock-rates = <200000000>;
+	num-cs = <1>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>;
+	status = "okay";
+
+	pmic at 0 {
+		compatible = "rockchip,rk806";
+		reg = <0x0>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>,
+			    <&rk806_dvs2_null>, <&rk806_dvs3_null>;
+		spi-max-frequency = <1000000>;
+		system-power-controller;
+
+		vcc1-supply = <&vcc5v0_sys>;
+		vcc2-supply = <&vcc5v0_sys>;
+		vcc3-supply = <&vcc5v0_sys>;
+		vcc4-supply = <&vcc5v0_sys>;
+		vcc5-supply = <&vcc5v0_sys>;
+		vcc6-supply = <&vcc5v0_sys>;
+		vcc7-supply = <&vcc5v0_sys>;
+		vcc8-supply = <&vcc5v0_sys>;
+		vcc9-supply = <&vcc5v0_sys>;
+		vcc10-supply = <&vcc5v0_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc5v0_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc5v0_sys>;
+
+		gpio-controller;
+		#gpio-cells = <2>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		regulators {
+			vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 {
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-enable-ramp-delay = <400>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_cpu_lit_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_log_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <750000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_log_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_vdenc_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <675000>;
+				regulator-max-microvolt = <900000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcc_2v0_pldo_s3: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <2000000>;
+				regulator-max-microvolt = <2000000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vdd_2v0_pldo_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <2000000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avcc_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "avcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vcc_1v8_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			avdd_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "avdd_1v2_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vcc_3v3_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-ramp-delay = <12500>;
+				regulator-name = "vccio_sd_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "pldo6_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdd_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_ddr_pll_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			avdd_0v75_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "avdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdd_0v85_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s0";
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&tsadc {
+	status = "okay";
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&u2phy1 {
+	status = "okay";
+};
+
+&u2phy1_otg {
+	status = "okay";
+};
+
+&u2phy2 {
+	status = "okay";
+};
+
+&u2phy2_host {
+	phy-supply = <&vcc5v0_sys>;
+	status = "okay";
+};
+
+&u2phy3 {
+	status = "okay";
+};
+
+&u2phy3_host {
+	phy-supply = <&vcc5v0_sys>;
+	status = "okay";
+};
+
+&uart1 {
+	pinctrl-0 = <&uart1m0_xfer>;
+	status = "okay";
+};
+
+&uart2 {
+	pinctrl-0 = <&uart2m0_xfer>;
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m0_xfer>;
+	status = "okay";
+};
+
+&uart7 {
+	pinctrl-0 = <&uart7m0_xfer>;
+	status = "okay";
+};
+
+&uart9 {
+	pinctrl-0 = <&uart9m0_xfer>;
+	status = "okay";
+};
+
+&usb_host0_ehci {
+	status = "okay";
+};
+
+&usb_host0_ohci {
+	status = "okay";
+};
+
+&usb_host0_xhci {
+	usb-role-switch;
+	status = "okay";
+
+	port {
+		usb_host0_xhci_drd_sw: endpoint {
+			remote-endpoint = <&usbc0_hs>;
+		};
+	};
+};
+
+&usb_host1_ehci {
+	status = "okay";
+};
+
+&usb_host1_ohci {
+	status = "okay";
+};
+
+&usb_host1_xhci {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&usbdp_phy0 {
+	mode-switch;
+	orientation-switch;
+	sbu1-dc-gpios = <&gpio4 RK_PA6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		usbdp_phy0_typec_ss: endpoint at 0 {
+			reg = <0>;
+			remote-endpoint = <&usbc0_ss>;
+		};
+
+		usbdp_phy0_typec_sbu: endpoint at 1 {
+			reg = <1>;
+			remote-endpoint = <&usbc0_sbu>;
+		};
+	};
+};
+
+&usbdp_phy1 {
+	status = "okay";
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi0: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi0_in_vp0>;
+	};
+};

-- 
2.47.3



From diederik at cknow-tech.com  Wed Jun 10 07:28:17 2026
From: diederik at cknow-tech.com (Diederik de Haas)
Date: Wed, 10 Jun 2026 16:28:17 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <CA+GS1Y1xAq-9eMyMmoVE6NG9KLG7XRxgPoSr5RkW=6fT5D820g@mail.gmail.com>
References: <20260604135255.62682-1-midgy971@gmail.com>
 <3d99569e-9c3a-49d1-93fb-1335382523e9@rock-chips.com>
 <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
 <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
 <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
 <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
 <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com>
 <DJ5A9XL183RZ.20J3ASQ3EWUZ6@cknow-tech.com>
 <CA+GS1Y1xAq-9eMyMmoVE6NG9KLG7XRxgPoSr5RkW=6fT5D820g@mail.gmail.com>
Message-ID: <DJ5FUW50YM2N.6ZTY4WK27ZP5@cknow-tech.com>

On Wed Jun 10, 2026 at 3:36 PM CEST, Midgy Balon wrote:
> Hello Chaoyi & Diederik,
>
> I compared the RK3568 and RK3588 NPU power-domain + DTS as you
> suggested, and it lines up
> exactly with what you described.
>
> The difference is the `need_regulator` capability. RK3588's NPU domain is
> `DOMAIN_RK3588("npu", ?, false, true)` ? the trailing `true` is
> `regulator`/`need_regulator`.
> The mainline RK3568 macro `DOMAIN_RK3568(name, pwr, req, wakeup)` has
> no regulator parameter at
> all, so `RK3568_PD_NPU` can't be marked need_regulator. My v4 adds
> that: a regulator-capable
> RK3568 NPU domain (need_regulator = true) plus `domain-supply =
> <&vdd_npu>` on the NPU node ?
> i.e. the same shape as RK3588.
>
> And the fix you referenced (Frank Zhang's "pmdomain: rockchip: Fix init genpd as
> GENPD_STATE_ON before regulator ready", plus "quiet regulator error on
> -EPROBE_DEFER") is
> already in my base (v7.1-rc6), so the `if (need_regulator)
> rockchip_pd_power(pd, false)`
> default-off path is in effect. That's what resolves the actual problem
> for me: with rocket
> built as a module (the normal config), need_regulator on the NPU
> domain, and those pmdomain
> patches in place, the board boots cleanly and NPU jobs run with no RCU
> stall / no deadlock. My
> earlier hang was an artifact of a self-contained rocket=y image
> probing in the initcalls before
> the I2C regulator core was up ? as a module it loads ~6.8 s in, well
> after, so it's gone.
>
> I also went back and checked the `fw_devlink=permissive` question
> myself ? and good news, it
> turns out it is NOT needed. I rebooted the exact same kernel with
> permissive removed from the
> cmdline (strict fw_devlink, the default), and the board boots cleanly,
> the NPU probes
> (`rocket fde40000.npu: Rockchip NPU core 0 version: 0`), and NPU jobs
> submit and run five times
> in a row with no deadlock and no RCU stall. So strict fw_devlink
> resolves the NPU/PMIC ordering
> fine via deferred probe.
>
> The one remaining thing is cosmetic: at power-domain-controller probe
> (~2.94 s) I still get,
> in BOTH modes (with or without permissive):
>
>   rockchip-pm-domain ?: Failed to create device link (0x180) with
> supplier 0-0020 ?power-domain at 6
>
> i.e. genpd can't form the link to the rk809 (the I2C PMIC supplying
> vdd_npu) because the PMIC
> isn't registered yet at that point. It's non-fatal ? the domain
> defaults off (Frank's patch),
> the rail comes up via the regulator core, the NPU probes a few seconds
> later, and all jobs run.
>
> One question: on RK3588 with need_regulator, do you also see that
> "Failed to create device
> link ? supplier <pmic>" line at pmdomain probe, or does it order
> cleanly? If RK3588 is clean,
> is there a DTS detail (e.g. the regulator's bus/probe order) I should
> mirror on RK3568 to make
> the link form in time ? or is this line just expected/harmless and
> best left as-is?

[    2.110935] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management at fd8d8000/power-controller/power-domain at 8
[    2.557459] sdhci-dwcmshc fe2e0000.mmc: Can't reduce the clock below 52MHz in HS200/HS400 mode
[    2.647174] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management at fd8d8000/power-controller/power-domain at 8
[    2.945089] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier spi2.0 for /power-management at fd8d8000/power-controller/power-domain at 12

8 = NPU; 12 = GPU

on both nanopc-t6-lts and nanopc-t6-plus (both RK3588).
And on a 6.18 dmesg output I have for Rock 5B, I see the ~ same, but then
it's 1-0042 instead of 2-0042. 

I don't know if it's bad or harmless, but it is consistent.

HTH,
  Diederik

> @Diederik ? thanks; the DCDC_REG2 change and Jonas's USB-suspend
> series look like generally
> useful RK356x robustness fixes, though for this specific NPU
> device-link the need_regulator +
> Frank's pmdomain patches seem to be the relevant piece. I'll keep them
> in mind for suspend.
>
> The convolution-output / compute-completion issue is still separate
> and open (@Finley ? that's
> the PVTPLL/NoC one); the power-domain side is in good shape for v4.
>
> Thanks y'all for your help :)
>
> Kind regards,
> Midgy
>
> Le mer. 10 juin 2026 ? 12:05, Diederik de Haas
> <diederik at cknow-tech.com> a ?crit :
>>
>> Hi,
>>
>> On Wed Jun 10, 2026 at 3:14 AM CEST, Chaoyi Chen wrote:
>> > Hi Midgy,
>> >
>> > On 6/9/2026 7:11 PM, Midgy Balon wrote:
>> >> Hello Chaoyi,
>> >>
>> >> You were right - building rocket as a module fixes it. Thanks for the pointer.
>> >>
>> >> I rebuilt with CONFIG_DRM_ACCEL_ROCKET=m (everything else the same:
>> >> need_regulator on
>> >> the RK3568 NPU power domain via a DOMAIN_M_R variant, domain-supply =
>> >> <&vdd_npu>, and the
>> >> regulator-always-on workaround dropped). The board now boots cleanly
>> >> and, more importantly,
>> >> an NPU job submit no longer hangs: I ran the test workload five times
>> >> with no RCU stall and
>> >> no freeze.
>> >>
>> >> So with rocket=m the need_regulator approach works on RK3568, and I'll
>> >> keep it for v4
>> >> (domain-supply + need_regulator, instead of marking vdd_npu
>> >> always-on). rocket=m is the
>> >> normal configuration anyway; my earlier hang came from building it =y
>> >> in a self-contained
>> >> image, so it probed in the initcalls (around 2 s) and the genpd ->
>> >> I2C-PMIC regulator
>> >> transition ran before the system was ready. As a module it loads from
>> >> udev much later
>> >> (~6.8 s here), after the I2C controller and regulator core are fully up.
>> >>
>> >> On your question of when the device-link error is printed - it is at
>> >> power-domain
>> >> controller probe, not at the rocket probe:
>> >>
>> >>   [    2.700618] vdd_npu: Bringing 500000uV into 825000-825000uV
>> >>   [    2.749637] rockchip-pm-domain fdd90000.power-management:power-controller:
>> >>                  Failed to create device link (0x180) with supplier 0-0020 for
>> >>                  /power-management at fdd90000/power-controller/power-domain at 6
>> >>   [    2.945955] platform fde40000.npu: Adding to iommu group 3
>> >>   ...
>> >>   [    6.840374] rocket: loading out-of-tree module taints kernel.
>> >>   [    6.877647] [drm] Initialized rocket 0.0.0 for rknn on minor 0
>> >>   [    6.879950] rocket fde40000.npu: Rockchip NPU core 0 version: 0
>> >>
>> >> So the device-link to the rk809 PMIC (0-0020) fails to form at ~2.75
>> >> s, well before rocket
>> >> loads at ~6.8 s. It is non-fatal here - the vdd_npu rail is brought up
>> >> by the regulator core
>> >> and all jobs run - and there is no "failed to get ack on domain npu"
>> >> NoC warning this boot
>> >> (the always-on kernel had one). The complete boot log is attached.
>> >>
>> >> Two notes / one question:
>> >> - This boot used fw_devlink=permissive on the command line. Is the
>> >> "Failed to create device
>> >>   link ... supplier 0-0020" at pmdomain probe expected/benign, or is
>> >> there a clean way to make
>> >>   it order correctly (so it also works without permissive, and a =y
>> >> build wouldn't deadlock in
>> >>   the initcalls)?
>> >
>> > We encountered the same issue on the RK3588 NPU before. And it was
>> > resolved with the following patch at that time.
>> >
>> > https://lore.kernel.org/all/20251216055247.13150-1-rmxpzlb at gmail.com/
>> >
>> > Please compare the differences in NPU pmdomain and DTS configuration
>> > between the RK3568 and RK3588.
>>
>> About a month ago on #linux-rockchip we were discussing PM 'stuff':
>> https://libera.catirclogs.org/linux-rockchip/2026-05-15#39939137;
>> which references this paste
>> https://paste.sr.ht/~diederik/89d9f84e22474e837b55286d213b67f03859ce2e
>> I've since removed the DCDC_REG2 for PineTab2 and the 'fix' should likely
>> be extended to cover all RK3566/RK3568 devices though.
>>
>> It's what I made at the time hoping to fix a suspend/resume issue when
>> trying upstream TF-A. It didn't fix the issue at the time, but may still
>> be useful/needed and I think it's what Chaoyi hinted at.
>>
>> Just yesterday, Jonas posted this patch which may be useful/needed too:
>> https://lore.kernel.org/linux-rockchip/20260609154124.445182-1-jonas at kwiboo.se/
>>
>> HTH,
>>   Diederik
>>
>> >> - (The convolution output is still uniform zero-point / the job times
>> >> out - that is the
>> >>   separate NPU compute-completion issue, unrelated to the power-domain
>> >> work. Finley, that is
>> >>   the one I flagged earlier re PVTPLL/NoC.)
>> >>
>> >> Kind regards,
>> >> Midgy
>> >>
>>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip



From detlev.casanova at collabora.com  Wed Jun 10 07:33:30 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:30 -0400
Subject: [PATCH v2 0/9] v4l2: Add tracing for stateless codecs
Message-ID: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>

Hi !

This patchset aims to improve codec event tracing in v4l2.

The traces added in visl by Daniel Almeida are moved to the global trace
events.
They are adapted to trace each each field separately and not just the
whole struct so that userspace can filter on different fields and
libraries like libtracefs and libtraceevent can be used to list the
fields instead of parsing the trace printk's.

The trace event templates are also reworked to avoid long lines, but
quoted string splits are kept as they don't cut words.

To each trace event are also added a tgid and fd fields, helping
userspace track different decoding sessions (contexts) based on the given
file descriptor used by the given process id.

Also for better tracking, stream on and stream off events are added as
well as HW run and HW done events to track decoder core usage.

The main focus is to be able to generate perfetto traces to show VPU usage,
a perfetto producer using this can be found at [1] (it will be renamed to
match the more generic approach than hantro).
Other controls can be traced later as well, this patch set only focuses on
mem2mem type drivers.

[1]:
https://gitlab.collabora.com/detlev/hantro-perf/-/tree/hantro-improved-info

Changes since v1:
- Don't modify the printk format
- Trace all fields of the structs instead of the whole struct as a buffer
- Remove fdinfo patches (they will come in another patch set)
- Fix long lines
- Rename v4l2_requests.h trace header to v4l2_controls.h
- Add basic documentation

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
Detlev Casanova (9):
      media: Move visl traces to v4l2-core
      media: Map each struct field to its own trace field
      media: Add tgid and fd fields in v4l2_fh struct
      media: Add tgid and fd to the v4l2-requests trace fields
      media: Add missing types to v4l2_ctrl_ptr
      media: Trace the stateless controls when set in v4l2-ctrls-core.c
      media: Add stream on/off traces and run them in the ioctl
      media: Add HW run/done trace events
      media: hantro: Add v4l2_hw run/done traces

 drivers/media/platform/verisilicon/hantro.h        |    1 +
 drivers/media/platform/verisilicon/hantro_drv.c    |   10 +
 .../platform/verisilicon/rockchip_vpu981_regs.h    |    1 +
 .../media/platform/verisilicon/rockchip_vpu_hw.c   |    4 +
 drivers/media/test-drivers/visl/Makefile           |    2 +-
 drivers/media/test-drivers/visl/visl-dec.c         |   76 -
 drivers/media/test-drivers/visl/visl-trace-av1.h   |  314 ---
 drivers/media/test-drivers/visl/visl-trace-fwht.h  |   66 -
 drivers/media/test-drivers/visl/visl-trace-h264.h  |  349 ---
 drivers/media/test-drivers/visl/visl-trace-hevc.h  |  464 ----
 drivers/media/test-drivers/visl/visl-trace-mpeg2.h |   99 -
 .../media/test-drivers/visl/visl-trace-points.c    |   11 -
 drivers/media/test-drivers/visl/visl-trace-vp8.h   |  156 --
 drivers/media/test-drivers/visl/visl-trace-vp9.h   |  292 ---
 drivers/media/v4l2-core/v4l2-ctrls-api.c           |   10 +
 drivers/media/v4l2-core/v4l2-ctrls-core.c          |  114 +
 drivers/media/v4l2-core/v4l2-fh.c                  |    1 +
 drivers/media/v4l2-core/v4l2-ioctl.c               |   37 +-
 drivers/media/v4l2-core/v4l2-trace.c               |   48 +
 include/media/v4l2-ctrls.h                         |   19 +
 include/media/v4l2-fh.h                            |    4 +
 include/trace/events/v4l2.h                        |   77 +
 include/trace/events/v4l2_controls.h               | 2708 ++++++++++++++++++++
 23 files changed, 3033 insertions(+), 1830 deletions(-)
---
base-commit: acb7500801e98639f6d8c2d796ed9f64cba83d3a
change-id: 20260608-v4l2-add-ftrace-aec6e7f60a6c

Best regards,
--  
Detlev Casanova <detlev.casanova at collabora.com>



From detlev.casanova at collabora.com  Wed Jun 10 07:33:31 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:31 -0400
Subject: [PATCH v2 1/9] media: Move visl traces to v4l2-core
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-1-9756edf72ac1@collabora.com>

The visl driver defines traces for all stateless controls.
Move those definition to a new v4l2_requests.h file and expose them for
all drivers to use.

As each event can be enabled individually in userspace, group them all in
the same v4l2_requests event folder.

Later, it can also be used by v4l2-core to trace controls as they are
being set.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/test-drivers/visl/Makefile           |    2 +-
 drivers/media/test-drivers/visl/visl-dec.c         |    8 +-
 drivers/media/test-drivers/visl/visl-trace-av1.h   |  314 ----
 drivers/media/test-drivers/visl/visl-trace-fwht.h  |   66 -
 drivers/media/test-drivers/visl/visl-trace-h264.h  |  349 -----
 drivers/media/test-drivers/visl/visl-trace-hevc.h  |  464 ------
 drivers/media/test-drivers/visl/visl-trace-mpeg2.h |   99 --
 .../media/test-drivers/visl/visl-trace-points.c    |   11 -
 drivers/media/test-drivers/visl/visl-trace-vp8.h   |  156 --
 drivers/media/test-drivers/visl/visl-trace-vp9.h   |  292 ----
 drivers/media/v4l2-core/v4l2-trace.c               |   45 +
 include/trace/events/v4l2_controls.h               | 1645 ++++++++++++++++++++
 12 files changed, 1692 insertions(+), 1759 deletions(-)

diff --git a/drivers/media/test-drivers/visl/Makefile b/drivers/media/test-drivers/visl/Makefile
index fb4d5ae1b17f..a5049e2af844 100644
--- a/drivers/media/test-drivers/visl/Makefile
+++ b/drivers/media/test-drivers/visl/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0+
-visl-y := visl-core.o visl-video.o visl-dec.o visl-trace-points.o
+visl-y := visl-core.o visl-video.o visl-dec.o
 
 ifeq ($(CONFIG_VISL_DEBUGFS),y)
   visl-y += visl-debugfs.o
diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index 6bbf93757047..1c66a1b8d78f 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -7,18 +7,12 @@
 #include "visl.h"
 #include "visl-debugfs.h"
 #include "visl-dec.h"
-#include "visl-trace-fwht.h"
-#include "visl-trace-mpeg2.h"
-#include "visl-trace-vp8.h"
-#include "visl-trace-vp9.h"
-#include "visl-trace-h264.h"
-#include "visl-trace-hevc.h"
-#include "visl-trace-av1.h"
 
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/tpg/v4l2-tpg.h>
+#include <trace/events/v4l2_controls.h>
 
 #define LAST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
 #define LAST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
diff --git a/drivers/media/test-drivers/visl/visl-trace-av1.h b/drivers/media/test-drivers/visl/visl-trace-av1.h
deleted file mode 100644
index 09f205de53df..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-av1.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_AV1_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_AV1_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_av1_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_sequence, s)),
-	TP_fast_assign(__entry->s = *s;),
-	TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
-		  "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n",
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"},
-		  {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA, "ENABLE_FILTER_INTRA"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER, "ENABLE_INTRA_EDGE_FILTER"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND, "ENABLE_INTERINTRA_COMPOUND"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND, "ENABLE_MASKED_COMPOUND"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION, "ENABLE_WARPED_MOTION"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER, "ENABLE_DUAL_FILTER"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT, "ENABLE_ORDER_HINT"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP, "ENABLE_JNT_COMP"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS, "ENABLE_REF_FRAME_MVS"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES, "ENABLE_SUPERRES"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF, "ENABLE_CDEF"},
-		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION, "ENABLE_RESTORATION"},
-		  {V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME, "MONO_CHROME"},
-		  {V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE, "COLOR_RANGE"},
-		  {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X, "SUBSAMPLING_X"},
-		  {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y, "SUBSAMPLING_Y"},
-		  {V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT, "FILM_GRAIN_PARAMS_PRESENT"},
-		  {V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q, "SEPARATE_UV_DELTA_Q"}),
-		  __entry->s.seq_profile,
-		  __entry->s.order_hint_bits,
-		  __entry->s.bit_depth,
-		  __entry->s.max_frame_width_minus_1,
-		  __entry->s.max_frame_height_minus_1
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
-	TP_ARGS(t),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_tile_group_entry, t)),
-	TP_fast_assign(__entry->t = *t;),
-	TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
-		  __entry->t.tile_offset,
-		  __entry->t.tile_size,
-		  __entry->t.tile_row,
-		  __entry->t.tile_col
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
-	TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
-		  "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n"
-		  "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n"
-		  "tile_info.width_in_sbs_minus_1: %s\ntile_info.height_in_sbs_minus_1: %s\n"
-		  "tile_info.tile_size_bytes: %u\nquantization.flags: %s\n"
-		  "quantization.base_q_idx: %u\nquantization.delta_q_y_dc: %d\n"
-		  "quantization.delta_q_u_dc: %d\nquantization.delta_q_u_ac: %d\n"
-		  "quantization.delta_q_v_dc: %d\nquantization.delta_q_v_ac: %d\n"
-		  "quantization.qm_y: %u\nquantization.qm_u: %u\nquantization.qm_v: %u\n"
-		  "quantization.delta_q_res: %u\nsuperres_denom: %u\nsegmentation.flags: %s\n"
-		  "segmentation.last_active_seg_id: %u\nsegmentation.feature_enabled:%s\n"
-		  "loop_filter.flags: %s\nloop_filter.level: %s\nloop_filter.sharpness: %u\n"
-		  "loop_filter.ref_deltas: %s\nloop_filter.mode_deltas: %s\n"
-		  "loop_filter.delta_lf_res: %u\ncdef.damping_minus_3: %u\ncdef.bits: %u\n"
-		  "cdef.y_pri_strength: %s\ncdef.y_sec_strength: %s\n"
-		  "cdef.uv_pri_strength: %s\ncdef.uv_sec_strength:%s\nskip_mode_frame: %s\n"
-		  "primary_ref_frame: %u\nloop_restoration.flags: %s\n"
-		  "loop_restoration.lr_unit_shift: %u\nloop_restoration.lr_uv_shift: %u\n"
-		  "loop_restoration.frame_restoration_type: %s\n"
-		  "loop_restoration.loop_restoration_size: %s\nflags: %s\norder_hint: %u\n"
-		  "upscaled_width: %u\nframe_width_minus_1: %u\nframe_height_minus_1: %u\n"
-		  "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n"
-		  "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n"
-		  "ref_frame_idx: %s\nrefresh_frame_flags: %u\n",
-		  __print_flags(__entry->f.tile_info.flags, "|",
-		  {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}),
-		  __entry->f.tile_info.context_update_tile_id,
-		  __entry->f.tile_info.tile_cols,
-		  __entry->f.tile_info.tile_rows,
-		  __print_array(__entry->f.tile_info.mi_col_starts,
-				ARRAY_SIZE(__entry->f.tile_info.mi_col_starts),
-				sizeof(__entry->f.tile_info.mi_col_starts[0])),
-		  __print_array(__entry->f.tile_info.mi_row_starts,
-				ARRAY_SIZE(__entry->f.tile_info.mi_row_starts),
-				sizeof(__entry->f.tile_info.mi_row_starts[0])),
-		  __print_array(__entry->f.tile_info.width_in_sbs_minus_1,
-				ARRAY_SIZE(__entry->f.tile_info.width_in_sbs_minus_1),
-				sizeof(__entry->f.tile_info.width_in_sbs_minus_1[0])),
-		  __print_array(__entry->f.tile_info.height_in_sbs_minus_1,
-				ARRAY_SIZE(__entry->f.tile_info.height_in_sbs_minus_1),
-				sizeof(__entry->f.tile_info.height_in_sbs_minus_1[0])),
-		  __entry->f.tile_info.tile_size_bytes,
-		  __print_flags(__entry->f.quantization.flags, "|",
-		  {V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA, "DIFF_UV_DELTA"},
-		  {V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX, "USING_QMATRIX"},
-		  {V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT, "DELTA_Q_PRESENT"}),
-		  __entry->f.quantization.base_q_idx,
-		  __entry->f.quantization.delta_q_y_dc,
-		  __entry->f.quantization.delta_q_u_dc,
-		  __entry->f.quantization.delta_q_u_ac,
-		  __entry->f.quantization.delta_q_v_dc,
-		  __entry->f.quantization.delta_q_v_ac,
-		  __entry->f.quantization.qm_y,
-		  __entry->f.quantization.qm_u,
-		  __entry->f.quantization.qm_v,
-		  __entry->f.quantization.delta_q_res,
-		  __entry->f.superres_denom,
-		  __print_flags(__entry->f.segmentation.flags, "|",
-		  {V4L2_AV1_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
-		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
-		  {V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
-		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
-		  {V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP, "SEG_ID_PRE_SKIP"}),
-		  __entry->f.segmentation.last_active_seg_id,
-		  __print_array(__entry->f.segmentation.feature_enabled,
-				ARRAY_SIZE(__entry->f.segmentation.feature_enabled),
-				sizeof(__entry->f.segmentation.feature_enabled[0])),
-		  __print_flags(__entry->f.loop_filter.flags, "|",
-		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
-		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"},
-		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT, "DELTA_LF_PRESENT"},
-		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI, "DELTA_LF_MULTI"}),
-		  __print_array(__entry->f.loop_filter.level,
-				ARRAY_SIZE(__entry->f.loop_filter.level),
-				sizeof(__entry->f.loop_filter.level[0])),
-		  __entry->f.loop_filter.sharpness,
-		  __print_array(__entry->f.loop_filter.ref_deltas,
-				ARRAY_SIZE(__entry->f.loop_filter.ref_deltas),
-				sizeof(__entry->f.loop_filter.ref_deltas[0])),
-		  __print_array(__entry->f.loop_filter.mode_deltas,
-				ARRAY_SIZE(__entry->f.loop_filter.mode_deltas),
-				sizeof(__entry->f.loop_filter.mode_deltas[0])),
-		  __entry->f.loop_filter.delta_lf_res,
-		  __entry->f.cdef.damping_minus_3,
-		  __entry->f.cdef.bits,
-		  __print_array(__entry->f.cdef.y_pri_strength,
-				ARRAY_SIZE(__entry->f.cdef.y_pri_strength),
-				sizeof(__entry->f.cdef.y_pri_strength[0])),
-		  __print_array(__entry->f.cdef.y_sec_strength,
-				ARRAY_SIZE(__entry->f.cdef.y_sec_strength),
-				sizeof(__entry->f.cdef.y_sec_strength[0])),
-		  __print_array(__entry->f.cdef.uv_pri_strength,
-				ARRAY_SIZE(__entry->f.cdef.uv_pri_strength),
-				sizeof(__entry->f.cdef.uv_pri_strength[0])),
-		  __print_array(__entry->f.cdef.uv_sec_strength,
-				ARRAY_SIZE(__entry->f.cdef.uv_sec_strength),
-				sizeof(__entry->f.cdef.uv_sec_strength[0])),
-		  __print_array(__entry->f.skip_mode_frame,
-				ARRAY_SIZE(__entry->f.skip_mode_frame),
-				sizeof(__entry->f.skip_mode_frame[0])),
-		  __entry->f.primary_ref_frame,
-		  __print_flags(__entry->f.loop_restoration.flags, "|",
-		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR, "USES_LR"},
-		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR, "USES_CHROMA_LR"}),
-		  __entry->f.loop_restoration.lr_unit_shift,
-		  __entry->f.loop_restoration.lr_uv_shift,
-		  __print_array(__entry->f.loop_restoration.frame_restoration_type,
-				ARRAY_SIZE(__entry->f.loop_restoration.frame_restoration_type),
-				sizeof(__entry->f.loop_restoration.frame_restoration_type[0])),
-		  __print_array(__entry->f.loop_restoration.loop_restoration_size,
-				ARRAY_SIZE(__entry->f.loop_restoration.loop_restoration_size),
-				sizeof(__entry->f.loop_restoration.loop_restoration_size[0])),
-		  __print_flags(__entry->f.flags, "|",
-		  {V4L2_AV1_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
-		  {V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME, "SHOWABLE_FRAME"},
-		  {V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE, "ERROR_RESILIENT_MODE"},
-		  {V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE, "DISABLE_CDF_UPDATE"},
-		  {V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS, "ALLOW_SCREEN_CONTENT_TOOLS"},
-		  {V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV, "FORCE_INTEGER_MV"},
-		  {V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC, "ALLOW_INTRABC"},
-		  {V4L2_AV1_FRAME_FLAG_USE_SUPERRES, "USE_SUPERRES"},
-		  {V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV, "ALLOW_HIGH_PRECISION_MV"},
-		  {V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE, "IS_MOTION_MODE_SWITCHABLE"},
-		  {V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS, "USE_REF_FRAME_MVS"},
-		  {V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF,
-		   "DISABLE_FRAME_END_UPDATE_CDF"},
-		  {V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION, "ALLOW_WARPED_MOTION"},
-		  {V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT, "REFERENCE_SELECT"},
-		  {V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET, "REDUCED_TX_SET"},
-		  {V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED, "SKIP_MODE_ALLOWED"},
-		  {V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT, "SKIP_MODE_PRESENT"},
-		  {V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE, "FRAME_SIZE_OVERRIDE"},
-		  {V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT, "BUFFER_REMOVAL_TIME_PRESENT"},
-		  {V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING, "FRAME_REFS_SHORT_SIGNALING"}),
-		  __entry->f.order_hint,
-		  __entry->f.upscaled_width,
-		  __entry->f.frame_width_minus_1,
-		  __entry->f.frame_height_minus_1,
-		  __entry->f.render_width_minus_1,
-		  __entry->f.render_height_minus_1,
-		  __entry->f.current_frame_id,
-		  __print_array(__entry->f.buffer_removal_time,
-				ARRAY_SIZE(__entry->f.buffer_removal_time),
-				sizeof(__entry->f.buffer_removal_time[0])),
-		  __print_array(__entry->f.order_hints,
-				ARRAY_SIZE(__entry->f.order_hints),
-				sizeof(__entry->f.order_hints[0])),
-		  __print_array(__entry->f.reference_frame_ts,
-				ARRAY_SIZE(__entry->f.reference_frame_ts),
-				sizeof(__entry->f.reference_frame_ts[0])),
-		  __print_array(__entry->f.ref_frame_idx,
-				ARRAY_SIZE(__entry->f.ref_frame_idx),
-				sizeof(__entry->f.ref_frame_idx[0])),
-		  __entry->f.refresh_frame_flags
-	)
-);
-
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_film_grain, f)),
-	TP_fast_assign(__entry->f = *f;),
-	TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
-		  "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n"
-		  "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n"
-		  "point_cb_scaling: %s\nnum_cr_points: %u\npoint_cr_value: %s\n"
-		  "point_cr_scaling: %s\ngrain_scaling_minus_8: %u\nar_coeff_lag: %u\n"
-		  "ar_coeffs_y_plus_128: %s\nar_coeffs_cb_plus_128: %s\n"
-		  "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n"
-		  "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n"
-		  "cb_offset: %u\ncr_offset: %u\n",
-		  __print_flags(__entry->f.flags, "|",
-		  {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"},
-		  {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"},
-		  {V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA, "CHROMA_SCALING_FROM_LUMA"},
-		  {V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP, "OVERLAP"},
-		  {V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE, "CLIP_TO_RESTRICTED_RANGE"}),
-		  __entry->f.cr_mult,
-		  __entry->f.grain_seed,
-		  __entry->f.film_grain_params_ref_idx,
-		  __entry->f.num_y_points,
-		  __print_array(__entry->f.point_y_value,
-				ARRAY_SIZE(__entry->f.point_y_value),
-				sizeof(__entry->f.point_y_value[0])),
-		  __print_array(__entry->f.point_y_scaling,
-				ARRAY_SIZE(__entry->f.point_y_scaling),
-				sizeof(__entry->f.point_y_scaling[0])),
-		  __entry->f.num_cb_points,
-		  __print_array(__entry->f.point_cb_value,
-				ARRAY_SIZE(__entry->f.point_cb_value),
-				sizeof(__entry->f.point_cb_value[0])),
-		  __print_array(__entry->f.point_cb_scaling,
-				ARRAY_SIZE(__entry->f.point_cb_scaling),
-				sizeof(__entry->f.point_cb_scaling[0])),
-		  __entry->f.num_cr_points,
-		  __print_array(__entry->f.point_cr_value,
-				ARRAY_SIZE(__entry->f.point_cr_value),
-				sizeof(__entry->f.point_cr_value[0])),
-		  __print_array(__entry->f.point_cr_scaling,
-				ARRAY_SIZE(__entry->f.point_cr_scaling),
-				sizeof(__entry->f.point_cr_scaling[0])),
-		  __entry->f.grain_scaling_minus_8,
-		  __entry->f.ar_coeff_lag,
-		  __print_array(__entry->f.ar_coeffs_y_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_y_plus_128),
-				sizeof(__entry->f.ar_coeffs_y_plus_128[0])),
-		  __print_array(__entry->f.ar_coeffs_cb_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_cb_plus_128),
-				sizeof(__entry->f.ar_coeffs_cb_plus_128[0])),
-		  __print_array(__entry->f.ar_coeffs_cr_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_cr_plus_128),
-				sizeof(__entry->f.ar_coeffs_cr_plus_128[0])),
-		  __entry->f.ar_coeff_shift_minus_6,
-		  __entry->f.grain_scale_shift,
-		  __entry->f.cb_mult,
-		  __entry->f.cb_luma_mult,
-		  __entry->f.cr_luma_mult,
-		  __entry->f.cb_offset,
-		  __entry->f.cr_offset
-	)
-)
-
-DEFINE_EVENT(v4l2_ctrl_av1_seq_tmpl, v4l2_ctrl_av1_sequence,
-	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_av1_frame_tmpl, v4l2_ctrl_av1_frame,
-	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
-	TP_ARGS(f)
-);
-
-DEFINE_EVENT(v4l2_ctrl_av1_tge_tmpl, v4l2_ctrl_av1_tile_group_entry,
-	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
-	TP_ARGS(t)
-);
-
-DEFINE_EVENT(v4l2_ctrl_av1_film_grain_tmpl, v4l2_ctrl_av1_film_grain,
-	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
-	TP_ARGS(f)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-av1
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-fwht.h b/drivers/media/test-drivers/visl/visl-trace-fwht.h
deleted file mode 100644
index 54b119359ff5..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-fwht.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_FWHT_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_FWHT_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_fwht_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(
-			 __field(u64, backward_ref_ts)
-			 __field(u32, version)
-			 __field(u32, width)
-			 __field(u32, height)
-			 __field(u32, flags)
-			 __field(u32, colorspace)
-			 __field(u32, xfer_func)
-			 __field(u32, ycbcr_enc)
-			 __field(u32, quantization)
-			 ),
-	TP_fast_assign(
-		       __entry->backward_ref_ts = p->backward_ref_ts;
-		       __entry->version = p->version;
-		       __entry->width = p->width;
-		       __entry->height = p->height;
-		       __entry->flags = p->flags;
-		       __entry->colorspace = p->colorspace;
-		       __entry->xfer_func = p->xfer_func;
-		       __entry->ycbcr_enc = p->ycbcr_enc;
-		       __entry->quantization = p->quantization;
-		       ),
-	TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u xfer_func %u ycbcr_enc %u quantization %u",
-		  __entry->backward_ref_ts, __entry->version, __entry->width, __entry->height,
-		  __print_flags(__entry->flags, "|",
-		  {V4L2_FWHT_FL_IS_INTERLACED, "IS_INTERLACED"},
-		  {V4L2_FWHT_FL_IS_BOTTOM_FIRST, "IS_BOTTOM_FIRST"},
-		  {V4L2_FWHT_FL_IS_ALTERNATE, "IS_ALTERNATE"},
-		  {V4L2_FWHT_FL_IS_BOTTOM_FIELD, "IS_BOTTOM_FIELD"},
-		  {V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED, "LUMA_IS_UNCOMPRESSED"},
-		  {V4L2_FWHT_FL_CB_IS_UNCOMPRESSED, "CB_IS_UNCOMPRESSED"},
-		  {V4L2_FWHT_FL_CR_IS_UNCOMPRESSED, "CR_IS_UNCOMPRESSED"},
-		  {V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED, "ALPHA_IS_UNCOMPRESSED"},
-		  {V4L2_FWHT_FL_I_FRAME, "I_FRAME"},
-		  {V4L2_FWHT_FL_PIXENC_HSV, "PIXENC_HSV"},
-		  {V4L2_FWHT_FL_PIXENC_RGB, "PIXENC_RGB"},
-		  {V4L2_FWHT_FL_PIXENC_YUV, "PIXENC_YUV"}),
-		  __entry->colorspace, __entry->xfer_func, __entry->ycbcr_enc,
-		  __entry->quantization)
-);
-
-DEFINE_EVENT(v4l2_ctrl_fwht_params_tmpl, v4l2_ctrl_fwht_params,
-	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
-	TP_ARGS(p)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-fwht
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-h264.h b/drivers/media/test-drivers/visl/visl-trace-h264.h
deleted file mode 100644
index d84296a01deb..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-h264.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_H264_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_H264_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_h264_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_sps, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nprofile_idc %u\n"
-		  "constraint_set_flags %s\n"
-		  "level_idc %u\n"
-		  "seq_parameter_set_id %u\n"
-		  "chroma_format_idc %u\n"
-		  "bit_depth_luma_minus8 %u\n"
-		  "bit_depth_chroma_minus8 %u\n"
-		  "log2_max_frame_num_minus4 %u\n"
-		  "pic_order_cnt_type %u\n"
-		  "log2_max_pic_order_cnt_lsb_minus4 %u\n"
-		  "max_num_ref_frames %u\n"
-		  "num_ref_frames_in_pic_order_cnt_cycle %u\n"
-		  "offset_for_ref_frame %s\n"
-		  "offset_for_non_ref_pic %d\n"
-		  "offset_for_top_to_bottom_field %d\n"
-		  "pic_width_in_mbs_minus1 %u\n"
-		  "pic_height_in_map_units_minus1 %u\n"
-		  "flags %s",
-		  __entry->s.profile_idc,
-		  __print_flags(__entry->s.constraint_set_flags, "|",
-		  {V4L2_H264_SPS_CONSTRAINT_SET0_FLAG, "CONSTRAINT_SET0_FLAG"},
-		  {V4L2_H264_SPS_CONSTRAINT_SET1_FLAG, "CONSTRAINT_SET1_FLAG"},
-		  {V4L2_H264_SPS_CONSTRAINT_SET2_FLAG, "CONSTRAINT_SET2_FLAG"},
-		  {V4L2_H264_SPS_CONSTRAINT_SET3_FLAG, "CONSTRAINT_SET3_FLAG"},
-		  {V4L2_H264_SPS_CONSTRAINT_SET4_FLAG, "CONSTRAINT_SET4_FLAG"},
-		  {V4L2_H264_SPS_CONSTRAINT_SET5_FLAG, "CONSTRAINT_SET5_FLAG"}),
-		  __entry->s.level_idc,
-		  __entry->s.seq_parameter_set_id,
-		  __entry->s.chroma_format_idc,
-		  __entry->s.bit_depth_luma_minus8,
-		  __entry->s.bit_depth_chroma_minus8,
-		  __entry->s.log2_max_frame_num_minus4,
-		  __entry->s.pic_order_cnt_type,
-		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
-		  __entry->s.max_num_ref_frames,
-		  __entry->s.num_ref_frames_in_pic_order_cnt_cycle,
-		  __print_array(__entry->s.offset_for_ref_frame,
-				ARRAY_SIZE(__entry->s.offset_for_ref_frame),
-				sizeof(__entry->s.offset_for_ref_frame[0])),
-		  __entry->s.offset_for_non_ref_pic,
-		  __entry->s.offset_for_top_to_bottom_field,
-		  __entry->s.pic_width_in_mbs_minus1,
-		  __entry->s.pic_height_in_map_units_minus1,
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
-		  {V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS, "QPPRIME_Y_ZERO_TRANSFORM_BYPASS"},
-		  {V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO, "DELTA_PIC_ORDER_ALWAYS_ZERO"},
-		  {V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED, "GAPS_IN_FRAME_NUM_VALUE_ALLOWED"},
-		  {V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY, "FRAME_MBS_ONLY"},
-		  {V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD, "MB_ADAPTIVE_FRAME_FIELD"},
-		  {V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE, "DIRECT_8X8_INFERENCE"}
-		  ))
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pps, p)),
-	TP_fast_assign(__entry->p = *p),
-	TP_printk("\npic_parameter_set_id %u\n"
-		  "seq_parameter_set_id %u\n"
-		  "num_slice_groups_minus1 %u\n"
-		  "num_ref_idx_l0_default_active_minus1 %u\n"
-		  "num_ref_idx_l1_default_active_minus1 %u\n"
-		  "weighted_bipred_idc %u\n"
-		  "pic_init_qp_minus26 %d\n"
-		  "pic_init_qs_minus26 %d\n"
-		  "chroma_qp_index_offset %d\n"
-		  "second_chroma_qp_index_offset %d\n"
-		  "flags %s",
-		  __entry->p.pic_parameter_set_id,
-		  __entry->p.seq_parameter_set_id,
-		  __entry->p.num_slice_groups_minus1,
-		  __entry->p.num_ref_idx_l0_default_active_minus1,
-		  __entry->p.num_ref_idx_l1_default_active_minus1,
-		  __entry->p.weighted_bipred_idc,
-		  __entry->p.pic_init_qp_minus26,
-		  __entry->p.pic_init_qs_minus26,
-		  __entry->p.chroma_qp_index_offset,
-		  __entry->p.second_chroma_qp_index_offset,
-		  __print_flags(__entry->p.flags, "|",
-		  {V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE, "ENTROPY_CODING_MODE"},
-		  {V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT, "BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT"},
-		  {V4L2_H264_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
-		  {V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
-		  {V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
-		  {V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT, "REDUNDANT_PIC_CNT_PRESENT"},
-		  {V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE, "TRANSFORM_8X8_MODE"},
-		  {V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT, "SCALING_MATRIX_PRESENT"}
-		  ))
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_scaling_matrix, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_4x4,
-				   sizeof(__entry->s.scaling_list_4x4),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_8x8,
-				   sizeof(__entry->s.scaling_list_8x8),
-				   false)
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pred_weights, p)),
-	TP_fast_assign(__entry->p = *p),
-	TP_printk("\nluma_log2_weight_denom %u\n"
-		  "chroma_log2_weight_denom %u\n"
-		  "weight_factor[0].luma_weight %s\n"
-		  "weight_factor[0].luma_offset %s\n"
-		  "weight_factor[0].chroma_weight {%s}\n"
-		  "weight_factor[0].chroma_offset {%s}\n"
-		  "weight_factor[1].luma_weight %s\n"
-		  "weight_factor[1].luma_offset %s\n"
-		  "weight_factor[1].chroma_weight {%s}\n"
-		  "weight_factor[1].chroma_offset {%s}\n",
-		  __entry->p.luma_log2_weight_denom,
-		  __entry->p.chroma_log2_weight_denom,
-		  __print_array(__entry->p.weight_factors[0].luma_weight,
-				ARRAY_SIZE(__entry->p.weight_factors[0].luma_weight),
-				sizeof(__entry->p.weight_factors[0].luma_weight[0])),
-		  __print_array(__entry->p.weight_factors[0].luma_offset,
-				ARRAY_SIZE(__entry->p.weight_factors[0].luma_offset),
-				sizeof(__entry->p.weight_factors[0].luma_offset[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[0].chroma_weight,
-				   sizeof(__entry->p.weight_factors[0].chroma_weight),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[0].chroma_offset,
-				   sizeof(__entry->p.weight_factors[0].chroma_offset),
-				   false),
-		  __print_array(__entry->p.weight_factors[1].luma_weight,
-				ARRAY_SIZE(__entry->p.weight_factors[1].luma_weight),
-				sizeof(__entry->p.weight_factors[1].luma_weight[0])),
-		  __print_array(__entry->p.weight_factors[1].luma_offset,
-				ARRAY_SIZE(__entry->p.weight_factors[1].luma_offset),
-				sizeof(__entry->p.weight_factors[1].luma_offset[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[1].chroma_weight,
-				   sizeof(__entry->p.weight_factors[1].chroma_weight),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[1].chroma_offset,
-				   sizeof(__entry->p.weight_factors[1].chroma_offset),
-				   false)
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_slice_params, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nheader_bit_size %u\n"
-		  "first_mb_in_slice %u\n"
-		  "slice_type %s\n"
-		  "colour_plane_id %u\n"
-		  "redundant_pic_cnt %u\n"
-		  "cabac_init_idc %u\n"
-		  "slice_qp_delta %d\n"
-		  "slice_qs_delta %d\n"
-		  "disable_deblocking_filter_idc %u\n"
-		  "slice_alpha_c0_offset_div2 %u\n"
-		  "slice_beta_offset_div2 %u\n"
-		  "num_ref_idx_l0_active_minus1 %u\n"
-		  "num_ref_idx_l1_active_minus1 %u\n"
-		  "flags %s",
-		  __entry->s.header_bit_size,
-		  __entry->s.first_mb_in_slice,
-		  __print_symbolic(__entry->s.slice_type,
-		  {V4L2_H264_SLICE_TYPE_P, "P"},
-		  {V4L2_H264_SLICE_TYPE_B, "B"},
-		  {V4L2_H264_SLICE_TYPE_I, "I"},
-		  {V4L2_H264_SLICE_TYPE_SP, "SP"},
-		  {V4L2_H264_SLICE_TYPE_SI, "SI"}),
-		  __entry->s.colour_plane_id,
-		  __entry->s.redundant_pic_cnt,
-		  __entry->s.cabac_init_idc,
-		  __entry->s.slice_qp_delta,
-		  __entry->s.slice_qs_delta,
-		  __entry->s.disable_deblocking_filter_idc,
-		  __entry->s.slice_alpha_c0_offset_div2,
-		  __entry->s.slice_beta_offset_div2,
-		  __entry->s.num_ref_idx_l0_active_minus1,
-		  __entry->s.num_ref_idx_l1_active_minus1,
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED, "DIRECT_SPATIAL_MV_PRED"},
-		  {V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH, "SP_FOR_SWITCH"})
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i),
-	TP_STRUCT__entry(__field_struct(struct v4l2_h264_reference, r)
-			 __field(int, i)),
-	TP_fast_assign(__entry->r = *r; __entry->i = i;),
-	TP_printk("[%d]: fields %s index %u",
-		  __entry->i,
-		  __print_flags(__entry->r.fields, "|",
-		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
-		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
-		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
-		  __entry->r.index
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
-	TP_ARGS(d),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_decode_params, d)),
-	TP_fast_assign(__entry->d = *d),
-	TP_printk("\nnal_ref_idc %u\n"
-		  "frame_num %u\n"
-		  "top_field_order_cnt %d\n"
-		  "bottom_field_order_cnt %d\n"
-		  "idr_pic_id %u\n"
-		  "pic_order_cnt_lsb %u\n"
-		  "delta_pic_order_cnt_bottom %d\n"
-		  "delta_pic_order_cnt0 %d\n"
-		  "delta_pic_order_cnt1 %d\n"
-		  "dec_ref_pic_marking_bit_size %u\n"
-		  "pic_order_cnt_bit_size %u\n"
-		  "slice_group_change_cycle %u\n"
-		  "flags %s\n",
-		  __entry->d.nal_ref_idc,
-		  __entry->d.frame_num,
-		  __entry->d.top_field_order_cnt,
-		  __entry->d.bottom_field_order_cnt,
-		  __entry->d.idr_pic_id,
-		  __entry->d.pic_order_cnt_lsb,
-		  __entry->d.delta_pic_order_cnt_bottom,
-		  __entry->d.delta_pic_order_cnt0,
-		  __entry->d.delta_pic_order_cnt1,
-		  __entry->d.dec_ref_pic_marking_bit_size,
-		  __entry->d.pic_order_cnt_bit_size,
-		  __entry->d.slice_group_change_cycle,
-		  __print_flags(__entry->d.flags, "|",
-		  {V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
-		  {V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC, "FIELD_PIC"},
-		  {V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD, "BOTTOM_FIELD"},
-		  {V4L2_H264_DECODE_PARAM_FLAG_PFRAME, "PFRAME"},
-		  {V4L2_H264_DECODE_PARAM_FLAG_BFRAME, "BFRAME"})
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
-	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
-	TP_ARGS(e, i),
-	TP_STRUCT__entry(__field_struct(struct v4l2_h264_dpb_entry, e)
-			 __field(int, i)),
-	TP_fast_assign(__entry->e = *e; __entry->i = i;),
-	TP_printk("[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
-		  "top_field_order_cnt %d bottom_field_order_cnt %d flags %s",
-		  __entry->i,
-		  __entry->e.reference_ts,
-		  __entry->e.pic_num,
-		  __entry->e.frame_num,
-		  __print_flags(__entry->e.fields, "|",
-		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
-		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
-		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
-		  __entry->e.top_field_order_cnt,
-		  __entry->e.bottom_field_order_cnt,
-		  __print_flags(__entry->e.flags, "|",
-		  {V4L2_H264_DPB_ENTRY_FLAG_VALID, "VALID"},
-		  {V4L2_H264_DPB_ENTRY_FLAG_ACTIVE, "ACTIVE"},
-		  {V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM, "LONG_TERM"},
-		  {V4L2_H264_DPB_ENTRY_FLAG_FIELD, "FIELD"})
-
-	)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_sps_tmpl, v4l2_ctrl_h264_sps,
-	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_pps_tmpl, v4l2_ctrl_h264_pps,
-	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
-	TP_ARGS(p)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_scaling_matrix_tmpl, v4l2_ctrl_h264_scaling_matrix,
-	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_pred_weights_tmpl, v4l2_ctrl_h264_pred_weights,
-	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
-	TP_ARGS(p)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_slice_params_tmpl, v4l2_ctrl_h264_slice_params,
-	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list0,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i)
-);
-
-DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list1,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i)
-);
-
-DEFINE_EVENT(v4l2_ctrl_h264_decode_params_tmpl, v4l2_ctrl_h264_decode_params,
-	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
-	TP_ARGS(d)
-);
-
-DEFINE_EVENT(v4l2_h264_dpb_entry_tmpl, v4l2_h264_dpb_entry,
-	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
-	TP_ARGS(e, i)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-h264
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-hevc.h b/drivers/media/test-drivers/visl/visl-trace-hevc.h
deleted file mode 100644
index 963914c463db..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-hevc.h
+++ /dev/null
@@ -1,464 +0,0 @@
-/* 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_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_hevc_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_sps, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nvideo_parameter_set_id %u\n"
-		  "seq_parameter_set_id %u\n"
-		  "pic_width_in_luma_samples %u\n"
-		  "pic_height_in_luma_samples %u\n"
-		  "bit_depth_luma_minus8 %u\n"
-		  "bit_depth_chroma_minus8 %u\n"
-		  "log2_max_pic_order_cnt_lsb_minus4 %u\n"
-		  "sps_max_dec_pic_buffering_minus1 %u\n"
-		  "sps_max_num_reorder_pics %u\n"
-		  "sps_max_latency_increase_plus1 %u\n"
-		  "log2_min_luma_coding_block_size_minus3 %u\n"
-		  "log2_diff_max_min_luma_coding_block_size %u\n"
-		  "log2_min_luma_transform_block_size_minus2 %u\n"
-		  "log2_diff_max_min_luma_transform_block_size %u\n"
-		  "max_transform_hierarchy_depth_inter %u\n"
-		  "max_transform_hierarchy_depth_intra %u\n"
-		  "pcm_sample_bit_depth_luma_minus1 %u\n"
-		  "pcm_sample_bit_depth_chroma_minus1 %u\n"
-		  "log2_min_pcm_luma_coding_block_size_minus3 %u\n"
-		  "log2_diff_max_min_pcm_luma_coding_block_size %u\n"
-		  "num_short_term_ref_pic_sets %u\n"
-		  "num_long_term_ref_pics_sps %u\n"
-		  "chroma_format_idc %u\n"
-		  "sps_max_sub_layers_minus1 %u\n"
-		  "flags %s",
-		  __entry->s.video_parameter_set_id,
-		  __entry->s.seq_parameter_set_id,
-		  __entry->s.pic_width_in_luma_samples,
-		  __entry->s.pic_height_in_luma_samples,
-		  __entry->s.bit_depth_luma_minus8,
-		  __entry->s.bit_depth_chroma_minus8,
-		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
-		  __entry->s.sps_max_dec_pic_buffering_minus1,
-		  __entry->s.sps_max_num_reorder_pics,
-		  __entry->s.sps_max_latency_increase_plus1,
-		  __entry->s.log2_min_luma_coding_block_size_minus3,
-		  __entry->s.log2_diff_max_min_luma_coding_block_size,
-		  __entry->s.log2_min_luma_transform_block_size_minus2,
-		  __entry->s.log2_diff_max_min_luma_transform_block_size,
-		  __entry->s.max_transform_hierarchy_depth_inter,
-		  __entry->s.max_transform_hierarchy_depth_intra,
-		  __entry->s.pcm_sample_bit_depth_luma_minus1,
-		  __entry->s.pcm_sample_bit_depth_chroma_minus1,
-		  __entry->s.log2_min_pcm_luma_coding_block_size_minus3,
-		  __entry->s.log2_diff_max_min_pcm_luma_coding_block_size,
-		  __entry->s.num_short_term_ref_pic_sets,
-		  __entry->s.num_long_term_ref_pics_sps,
-		  __entry->s.chroma_format_idc,
-		  __entry->s.sps_max_sub_layers_minus1,
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
-		  {V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED, "SCALING_LIST_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_AMP_ENABLED, "AMP_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET, "SAMPLE_ADAPTIVE_OFFSET"},
-		  {V4L2_HEVC_SPS_FLAG_PCM_ENABLED, "PCM_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED, "V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED"},
-		  {V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT, "LONG_TERM_REF_PICS_PRESENT"},
-		  {V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED, "TEMPORAL_MVP_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED, "STRONG_INTRA_SMOOTHING_ENABLED"}
-	))
-
-);
-
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_pps, p)),
-	TP_fast_assign(__entry->p = *p),
-	TP_printk("\npic_parameter_set_id %u\n"
-		  "num_extra_slice_header_bits %u\n"
-		  "num_ref_idx_l0_default_active_minus1 %u\n"
-		  "num_ref_idx_l1_default_active_minus1 %u\n"
-		  "init_qp_minus26 %d\n"
-		  "diff_cu_qp_delta_depth %u\n"
-		  "pps_cb_qp_offset %d\n"
-		  "pps_cr_qp_offset %d\n"
-		  "num_tile_columns_minus1 %d\n"
-		  "num_tile_rows_minus1 %d\n"
-		  "column_width_minus1 %s\n"
-		  "row_height_minus1 %s\n"
-		  "pps_beta_offset_div2 %d\n"
-		  "pps_tc_offset_div2 %d\n"
-		  "log2_parallel_merge_level_minus2 %u\n"
-		  "flags %s",
-		  __entry->p.pic_parameter_set_id,
-		  __entry->p.num_extra_slice_header_bits,
-		  __entry->p.num_ref_idx_l0_default_active_minus1,
-		  __entry->p.num_ref_idx_l1_default_active_minus1,
-		  __entry->p.init_qp_minus26,
-		  __entry->p.diff_cu_qp_delta_depth,
-		  __entry->p.pps_cb_qp_offset,
-		  __entry->p.pps_cr_qp_offset,
-		  __entry->p.num_tile_columns_minus1,
-		  __entry->p.num_tile_rows_minus1,
-		  __print_array(__entry->p.column_width_minus1,
-				ARRAY_SIZE(__entry->p.column_width_minus1),
-				sizeof(__entry->p.column_width_minus1[0])),
-		  __print_array(__entry->p.row_height_minus1,
-				ARRAY_SIZE(__entry->p.row_height_minus1),
-				sizeof(__entry->p.row_height_minus1[0])),
-		  __entry->p.pps_beta_offset_div2,
-		  __entry->p.pps_tc_offset_div2,
-		  __entry->p.log2_parallel_merge_level_minus2,
-		  __print_flags(__entry->p.flags, "|",
-		  {V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED, "DEPENDENT_SLICE_SEGMENT_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT, "OUTPUT_FLAG_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED, "SIGN_DATA_HIDING_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT, "CABAC_INIT_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
-		  {V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED, "CU_QP_DELTA_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT, "PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
-		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED, "WEIGHTED_BIPRED"},
-		  {V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, "TRANSQUANT_BYPASS_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_TILES_ENABLED, "TILES_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, "ENTROPY_CODING_SYNC_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, "LOOP_FILTER_ACROSS_TILES_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, "PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED, "DEBLOCKING_FILTER_OVERRIDE_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER, "DISABLE_DEBLOCKING_FILTER"},
-		  {V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT, "LISTS_MODIFICATION_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT, "SLICE_SEGMENT_HEADER_EXTENSION_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING, "UNIFORM_SPACING"}
-	))
-
-);
-
-
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_slice_params, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nbit_size %u\n"
-		  "data_byte_offset %u\n"
-		  "num_entry_point_offsets %u\n"
-		  "nal_unit_type %u\n"
-		  "nuh_temporal_id_plus1 %u\n"
-		  "slice_type %u\n"
-		  "colour_plane_id %u\n"
-		  "slice_pic_order_cnt %d\n"
-		  "num_ref_idx_l0_active_minus1 %u\n"
-		  "num_ref_idx_l1_active_minus1 %u\n"
-		  "collocated_ref_idx %u\n"
-		  "five_minus_max_num_merge_cand %u\n"
-		  "slice_qp_delta %d\n"
-		  "slice_cb_qp_offset %d\n"
-		  "slice_cr_qp_offset %d\n"
-		  "slice_act_y_qp_offset %d\n"
-		  "slice_act_cb_qp_offset %d\n"
-		  "slice_act_cr_qp_offset %d\n"
-		  "slice_beta_offset_div2 %d\n"
-		  "slice_tc_offset_div2 %d\n"
-		  "pic_struct %u\n"
-		  "slice_segment_addr %u\n"
-		  "ref_idx_l0 %s\n"
-		  "ref_idx_l1 %s\n"
-		  "short_term_ref_pic_set_size %u\n"
-		  "long_term_ref_pic_set_size %u\n"
-		  "flags %s",
-		  __entry->s.bit_size,
-		  __entry->s.data_byte_offset,
-		  __entry->s.num_entry_point_offsets,
-		  __entry->s.nal_unit_type,
-		  __entry->s.nuh_temporal_id_plus1,
-		  __entry->s.slice_type,
-		  __entry->s.colour_plane_id,
-		  __entry->s.slice_pic_order_cnt,
-		  __entry->s.num_ref_idx_l0_active_minus1,
-		  __entry->s.num_ref_idx_l1_active_minus1,
-		  __entry->s.collocated_ref_idx,
-		  __entry->s.five_minus_max_num_merge_cand,
-		  __entry->s.slice_qp_delta,
-		  __entry->s.slice_cb_qp_offset,
-		  __entry->s.slice_cr_qp_offset,
-		  __entry->s.slice_act_y_qp_offset,
-		  __entry->s.slice_act_cb_qp_offset,
-		  __entry->s.slice_act_cr_qp_offset,
-		  __entry->s.slice_beta_offset_div2,
-		  __entry->s.slice_tc_offset_div2,
-		  __entry->s.pic_struct,
-		  __entry->s.slice_segment_addr,
-		  __print_array(__entry->s.ref_idx_l0,
-				ARRAY_SIZE(__entry->s.ref_idx_l0),
-				sizeof(__entry->s.ref_idx_l0[0])),
-		  __print_array(__entry->s.ref_idx_l1,
-				ARRAY_SIZE(__entry->s.ref_idx_l1),
-				sizeof(__entry->s.ref_idx_l1[0])),
-		  __entry->s.short_term_ref_pic_set_size,
-		  __entry->s.long_term_ref_pic_set_size,
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA, "SLICE_SAO_LUMA"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA, "SLICE_SAO_CHROMA"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED, "SLICE_TEMPORAL_MVP_ENABLED"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO, "MVD_L1_ZERO"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT, "CABAC_INIT"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0, "COLLOCATED_FROM_L0"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV, "USE_INTEGER_MV"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, "SLICE_DEBLOCKING_FILTER_DISABLED"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, "SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, "DEPENDENT_SLICE_SEGMENT"}
-
-	))
-);
-
-DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
-	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_pred_weight_table, p)),
-	TP_fast_assign(__entry->p = *p),
-	TP_printk("\ndelta_luma_weight_l0 %s\n"
-		  "luma_offset_l0 %s\n"
-		  "delta_chroma_weight_l0 {%s}\n"
-		  "chroma_offset_l0 {%s}\n"
-		  "delta_luma_weight_l1 %s\n"
-		  "luma_offset_l1 %s\n"
-		  "delta_chroma_weight_l1 {%s}\n"
-		  "chroma_offset_l1 {%s}\n"
-		  "luma_log2_weight_denom %d\n"
-		  "delta_chroma_log2_weight_denom %d\n",
-		  __print_array(__entry->p.delta_luma_weight_l0,
-				ARRAY_SIZE(__entry->p.delta_luma_weight_l0),
-				sizeof(__entry->p.delta_luma_weight_l0[0])),
-		  __print_array(__entry->p.luma_offset_l0,
-				ARRAY_SIZE(__entry->p.luma_offset_l0),
-				sizeof(__entry->p.luma_offset_l0[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.delta_chroma_weight_l0,
-				   sizeof(__entry->p.delta_chroma_weight_l0),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.chroma_offset_l0,
-				   sizeof(__entry->p.chroma_offset_l0),
-				   false),
-		  __print_array(__entry->p.delta_luma_weight_l1,
-				ARRAY_SIZE(__entry->p.delta_luma_weight_l1),
-				sizeof(__entry->p.delta_luma_weight_l1[0])),
-		  __print_array(__entry->p.luma_offset_l1,
-				ARRAY_SIZE(__entry->p.luma_offset_l1),
-				sizeof(__entry->p.luma_offset_l1[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.delta_chroma_weight_l1,
-				   sizeof(__entry->p.delta_chroma_weight_l1),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.chroma_offset_l1,
-				   sizeof(__entry->p.chroma_offset_l1),
-				   false),
-		__entry->p.luma_log2_weight_denom,
-		__entry->p.delta_chroma_log2_weight_denom
-
-	))
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_scaling_matrix, s)),
-	TP_fast_assign(__entry->s = *s),
-	TP_printk("\nscaling_list_4x4 {%s}\n"
-		  "scaling_list_8x8 {%s}\n"
-		  "scaling_list_16x16 {%s}\n"
-		  "scaling_list_32x32 {%s}\n"
-		  "scaling_list_dc_coef_16x16 %s\n"
-		  "scaling_list_dc_coef_32x32 %s\n",
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_4x4,
-				   sizeof(__entry->s.scaling_list_4x4),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_8x8,
-				   sizeof(__entry->s.scaling_list_8x8),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_16x16,
-				   sizeof(__entry->s.scaling_list_16x16),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_32x32,
-				   sizeof(__entry->s.scaling_list_32x32),
-				   false),
-		  __print_array(__entry->s.scaling_list_dc_coef_16x16,
-				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_16x16),
-				sizeof(__entry->s.scaling_list_dc_coef_16x16[0])),
-		  __print_array(__entry->s.scaling_list_dc_coef_32x32,
-				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_32x32),
-				sizeof(__entry->s.scaling_list_dc_coef_32x32[0]))
-	))
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
-	TP_ARGS(d),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_decode_params, d)),
-	TP_fast_assign(__entry->d = *d),
-	TP_printk("\npic_order_cnt_val %d\n"
-		  "short_term_ref_pic_set_size %u\n"
-		  "long_term_ref_pic_set_size %u\n"
-		  "num_active_dpb_entries %u\n"
-		  "num_poc_st_curr_before %u\n"
-		  "num_poc_st_curr_after %u\n"
-		  "num_poc_lt_curr %u\n"
-		  "poc_st_curr_before %s\n"
-		  "poc_st_curr_after %s\n"
-		  "poc_lt_curr %s\n"
-		  "flags %s",
-		  __entry->d.pic_order_cnt_val,
-		  __entry->d.short_term_ref_pic_set_size,
-		  __entry->d.long_term_ref_pic_set_size,
-		  __entry->d.num_active_dpb_entries,
-		  __entry->d.num_poc_st_curr_before,
-		  __entry->d.num_poc_st_curr_after,
-		  __entry->d.num_poc_lt_curr,
-		  __print_array(__entry->d.poc_st_curr_before,
-				ARRAY_SIZE(__entry->d.poc_st_curr_before),
-				sizeof(__entry->d.poc_st_curr_before[0])),
-		  __print_array(__entry->d.poc_st_curr_after,
-				ARRAY_SIZE(__entry->d.poc_st_curr_after),
-				sizeof(__entry->d.poc_st_curr_after[0])),
-		  __print_array(__entry->d.poc_lt_curr,
-				ARRAY_SIZE(__entry->d.poc_lt_curr),
-				sizeof(__entry->d.poc_lt_curr[0])),
-		  __print_flags(__entry->d.flags, "|",
-		  {V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC, "IRAP_PIC"},
-		  {V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
-		  {V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR, "NO_OUTPUT_OF_PRIOR"}
-	))
-);
-
-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),
-	TP_ARGS(e),
-	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_dpb_entry, e)),
-	TP_fast_assign(__entry->e = *e),
-	TP_printk("\ntimestamp %llu\n"
-		  "flags %s\n"
-		  "field_pic %u\n"
-		  "pic_order_cnt_val %d\n",
-		__entry->e.timestamp,
-		__print_flags(__entry->e.flags, "|",
-		{V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE, "LONG_TERM_REFERENCE"}
-		  ),
-		__entry->e.field_pic,
-		__entry->e.pic_order_cnt_val
-	))
-
-DEFINE_EVENT(v4l2_ctrl_hevc_sps_tmpl, v4l2_ctrl_hevc_sps,
-	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_hevc_pps_tmpl, v4l2_ctrl_hevc_pps,
-	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
-	TP_ARGS(p)
-);
-
-DEFINE_EVENT(v4l2_ctrl_hevc_slice_params_tmpl, v4l2_ctrl_hevc_slice_params,
-	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_hevc_pred_weight_table_tmpl, v4l2_hevc_pred_weight_table,
-	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
-	TP_ARGS(p)
-);
-
-DEFINE_EVENT(v4l2_ctrl_hevc_scaling_matrix_tmpl, v4l2_ctrl_hevc_scaling_matrix,
-	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
-	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
-	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)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-hevc
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-mpeg2.h b/drivers/media/test-drivers/visl/visl-trace-mpeg2.h
deleted file mode 100644
index ba6c65481194..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-mpeg2.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_MPEG2_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_MPEG2_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_mpeg2_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_sequence, s)),
-	TP_fast_assign(__entry->s = *s;),
-	TP_printk("\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
-		  "profile_and_level_indication %u\nchroma_format %u\nflags %s\n",
-		  __entry->s.horizontal_size,
-		  __entry->s.vertical_size,
-		  __entry->s.vbv_buffer_size,
-		  __entry->s.profile_and_level_indication,
-		  __entry->s.chroma_format,
-		  __print_flags(__entry->s.flags, "|",
-		  {V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE, "PROGRESSIVE"})
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_picture, p)),
-	TP_fast_assign(__entry->p = *p;),
-	TP_printk("\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
-		  "picture_coding_type: %u\npicture_structure %u\nintra_dc_precision %u\n",
-		  __entry->p.backward_ref_ts,
-		  __entry->p.forward_ref_ts,
-		  __print_flags(__entry->p.flags, "|",
-		  {V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST, "TOP_FIELD_FIRST"},
-		  {V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT, "FRAME_PRED_DCT"},
-		  {V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV, "CONCEALMENT_MV"},
-		  {V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE, "Q_SCALE_TYPE"},
-		  {V4L2_MPEG2_PIC_FLAG_INTRA_VLC, "INTA_VLC"},
-		  {V4L2_MPEG2_PIC_FLAG_ALT_SCAN, "ALT_SCAN"},
-		  {V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST, "REPEAT_FIRST"},
-		  {V4L2_MPEG2_PIC_FLAG_PROGRESSIVE, "PROGRESSIVE"}),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.f_code,
-				   sizeof(__entry->p.f_code),
-				   false),
-		  __entry->p.picture_coding_type,
-		  __entry->p.picture_structure,
-		  __entry->p.intra_dc_precision
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
-	TP_ARGS(q),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_quantisation, q)),
-	TP_fast_assign(__entry->q = *q;),
-	TP_printk("\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
-		  "chroma_intra_quantiser_matrix %s\nchroma_non_intra_quantiser_matrix %s\n",
-		  __print_array(__entry->q.intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.intra_quantiser_matrix),
-				sizeof(__entry->q.intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.non_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.non_intra_quantiser_matrix),
-				sizeof(__entry->q.non_intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.chroma_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.chroma_intra_quantiser_matrix),
-				sizeof(__entry->q.chroma_intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.chroma_non_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.chroma_non_intra_quantiser_matrix),
-				sizeof(__entry->q.chroma_non_intra_quantiser_matrix[0]))
-		  )
-)
-
-DEFINE_EVENT(v4l2_ctrl_mpeg2_seq_tmpl, v4l2_ctrl_mpeg2_sequence,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
-	TP_ARGS(s)
-);
-
-DEFINE_EVENT(v4l2_ctrl_mpeg2_pic_tmpl, v4l2_ctrl_mpeg2_picture,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
-	TP_ARGS(p)
-);
-
-DEFINE_EVENT(v4l2_ctrl_mpeg2_quant_tmpl, v4l2_ctrl_mpeg2_quantisation,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
-	TP_ARGS(q)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-mpeg2
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-points.c b/drivers/media/test-drivers/visl/visl-trace-points.c
deleted file mode 100644
index 321ff732c682..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-points.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include "visl.h"
-
-#define CREATE_TRACE_POINTS
-#include "visl-trace-fwht.h"
-#include "visl-trace-mpeg2.h"
-#include "visl-trace-vp8.h"
-#include "visl-trace-vp9.h"
-#include "visl-trace-h264.h"
-#include "visl-trace-hevc.h"
-#include "visl-trace-av1.h"
diff --git a/drivers/media/test-drivers/visl/visl-trace-vp8.h b/drivers/media/test-drivers/visl/visl-trace-vp8.h
deleted file mode 100644
index dabe17d69ddc..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-vp8.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_VP8_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_VP8_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_vp8_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
-	TP_printk("\nentropy.coeff_probs {%s}\n"
-		  "entropy.y_mode_probs %s\n"
-		  "entropy.uv_mode_probs %s\n"
-		  "entropy.mv_probs {%s}",
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.entropy.coeff_probs,
-				   sizeof(__entry->f.entropy.coeff_probs),
-				   false),
-		  __print_array(__entry->f.entropy.y_mode_probs,
-				ARRAY_SIZE(__entry->f.entropy.y_mode_probs),
-				sizeof(__entry->f.entropy.y_mode_probs[0])),
-		  __print_array(__entry->f.entropy.uv_mode_probs,
-				ARRAY_SIZE(__entry->f.entropy.uv_mode_probs),
-				sizeof(__entry->f.entropy.uv_mode_probs[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.entropy.mv_probs,
-				   sizeof(__entry->f.entropy.mv_probs),
-				   false)
-		  )
-)
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
-	TP_printk("\nsegment.quant_update %s\n"
-		  "segment.lf_update %s\n"
-		  "segment.segment_probs %s\n"
-		  "segment.flags %s\n"
-		  "lf.ref_frm_delta %s\n"
-		  "lf.mb_mode_delta %s\n"
-		  "lf.sharpness_level %u\n"
-		  "lf.level %u\n"
-		  "lf.flags %s\n"
-		  "quant.y_ac_qi %u\n"
-		  "quant.y_dc_delta %d\n"
-		  "quant.y2_dc_delta %d\n"
-		  "quant.y2_ac_delta %d\n"
-		  "quant.uv_dc_delta %d\n"
-		  "quant.uv_ac_delta %d\n"
-		  "coder_state.range %u\n"
-		  "coder_state.value %u\n"
-		  "coder_state.bit_count %u\n"
-		  "width %u\n"
-		  "height %u\n"
-		  "horizontal_scale %u\n"
-		  "vertical_scale %u\n"
-		  "version %u\n"
-		  "prob_skip_false %u\n"
-		  "prob_intra %u\n"
-		  "prob_last %u\n"
-		  "prob_gf %u\n"
-		  "num_dct_parts %u\n"
-		  "first_part_size %u\n"
-		  "first_part_header_bits %u\n"
-		  "dct_part_sizes %s\n"
-		  "last_frame_ts %llu\n"
-		  "golden_frame_ts %llu\n"
-		  "alt_frame_ts %llu\n"
-		  "flags %s",
-		  __print_array(__entry->f.segment.quant_update,
-				ARRAY_SIZE(__entry->f.segment.quant_update),
-				sizeof(__entry->f.segment.quant_update[0])),
-		  __print_array(__entry->f.segment.lf_update,
-				ARRAY_SIZE(__entry->f.segment.lf_update),
-				sizeof(__entry->f.segment.lf_update[0])),
-		  __print_array(__entry->f.segment.segment_probs,
-				ARRAY_SIZE(__entry->f.segment.segment_probs),
-				sizeof(__entry->f.segment.segment_probs[0])),
-		  __print_flags(__entry->f.segment.flags, "|",
-		  {V4L2_VP8_SEGMENT_FLAG_ENABLED, "SEGMENT_ENABLED"},
-		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP, "SEGMENT_UPDATE_MAP"},
-		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA, "SEGMENT_UPDATE_FEATURE_DATA"},
-		  {V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE, "SEGMENT_DELTA_VALUE_MODE"}),
-		  __print_array(__entry->f.lf.ref_frm_delta,
-				ARRAY_SIZE(__entry->f.lf.ref_frm_delta),
-				sizeof(__entry->f.lf.ref_frm_delta[0])),
-		  __print_array(__entry->f.lf.mb_mode_delta,
-				ARRAY_SIZE(__entry->f.lf.mb_mode_delta),
-				sizeof(__entry->f.lf.mb_mode_delta[0])),
-		  __entry->f.lf.sharpness_level,
-		  __entry->f.lf.level,
-		  __print_flags(__entry->f.lf.flags, "|",
-		  {V4L2_VP8_LF_ADJ_ENABLE, "LF_ADJ_ENABLED"},
-		  {V4L2_VP8_LF_DELTA_UPDATE, "LF_DELTA_UPDATE"},
-		  {V4L2_VP8_LF_FILTER_TYPE_SIMPLE, "LF_FILTER_TYPE_SIMPLE"}),
-		  __entry->f.quant.y_ac_qi,
-		  __entry->f.quant.y_dc_delta,
-		  __entry->f.quant.y2_dc_delta,
-		  __entry->f.quant.y2_ac_delta,
-		  __entry->f.quant.uv_dc_delta,
-		  __entry->f.quant.uv_ac_delta,
-		  __entry->f.coder_state.range,
-		  __entry->f.coder_state.value,
-		  __entry->f.coder_state.bit_count,
-		  __entry->f.width,
-		  __entry->f.height,
-		  __entry->f.horizontal_scale,
-		  __entry->f.vertical_scale,
-		  __entry->f.version,
-		  __entry->f.prob_skip_false,
-		  __entry->f.prob_intra,
-		  __entry->f.prob_last,
-		  __entry->f.prob_gf,
-		  __entry->f.num_dct_parts,
-		  __entry->f.first_part_size,
-		  __entry->f.first_part_header_bits,
-		  __print_array(__entry->f.dct_part_sizes,
-				ARRAY_SIZE(__entry->f.dct_part_sizes),
-				sizeof(__entry->f.dct_part_sizes[0])),
-		  __entry->f.last_frame_ts,
-		  __entry->f.golden_frame_ts,
-		  __entry->f.alt_frame_ts,
-		  __print_flags(__entry->f.flags, "|",
-		  {V4L2_VP8_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
-		  {V4L2_VP8_FRAME_FLAG_EXPERIMENTAL, "EXPERIMENTAL"},
-		  {V4L2_VP8_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
-		  {V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF, "MB_NO_SKIP_COEFF"},
-		  {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
-		  {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"})
-		  )
-);
-
-DEFINE_EVENT(v4l2_ctrl_vp8_frame_tmpl, v4l2_ctrl_vp8_frame,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f)
-);
-
-DEFINE_EVENT(v4l2_ctrl_vp8_entropy_tmpl, v4l2_ctrl_vp8_entropy,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-vp8
-#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-vp9.h b/drivers/media/test-drivers/visl/visl-trace-vp9.h
deleted file mode 100644
index 362b92b07f93..000000000000
--- a/drivers/media/test-drivers/visl/visl-trace-vp9.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#if !defined(_VISL_TRACE_VP9_H_) || defined(TRACE_HEADER_MULTI_READ)
-#define _VISL_TRACE_VP9_H_
-
-#include <linux/tracepoint.h>
-#include "visl.h"
-
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM visl_vp9_controls
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
-	TP_printk("\nlf.ref_deltas %s\n"
-		  "lf.mode_deltas %s\n"
-		  "lf.level %u\n"
-		  "lf.sharpness %u\n"
-		  "lf.flags %s\n"
-		  "quant.base_q_idx %u\n"
-		  "quant.delta_q_y_dc %d\n"
-		  "quant.delta_q_uv_dc %d\n"
-		  "quant.delta_q_uv_ac %d\n"
-		  "seg.feature_data {%s}\n"
-		  "seg.feature_enabled %s\n"
-		  "seg.tree_probs %s\n"
-		  "seg.pred_probs %s\n"
-		  "seg.flags %s\n"
-		  "flags %s\n"
-		  "compressed_header_size %u\n"
-		  "uncompressed_header_size %u\n"
-		  "frame_width_minus_1 %u\n"
-		  "frame_height_minus_1 %u\n"
-		  "render_width_minus_1 %u\n"
-		  "render_height_minus_1 %u\n"
-		  "last_frame_ts %llu\n"
-		  "golden_frame_ts %llu\n"
-		  "alt_frame_ts %llu\n"
-		  "ref_frame_sign_bias %s\n"
-		  "reset_frame_context %s\n"
-		  "frame_context_idx %u\n"
-		  "profile %u\n"
-		  "bit_depth %u\n"
-		  "interpolation_filter %s\n"
-		  "tile_cols_log2 %u\n"
-		  "tile_rows_log_2 %u\n"
-		  "reference_mode %s\n",
-		  __print_array(__entry->f.lf.ref_deltas,
-				ARRAY_SIZE(__entry->f.lf.ref_deltas),
-				sizeof(__entry->f.lf.ref_deltas[0])),
-		  __print_array(__entry->f.lf.mode_deltas,
-				ARRAY_SIZE(__entry->f.lf.mode_deltas),
-				sizeof(__entry->f.lf.mode_deltas[0])),
-		  __entry->f.lf.level,
-		  __entry->f.lf.sharpness,
-		  __print_flags(__entry->f.lf.flags, "|",
-		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
-		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"}),
-		  __entry->f.quant.base_q_idx,
-		  __entry->f.quant.delta_q_y_dc,
-		  __entry->f.quant.delta_q_uv_dc,
-		  __entry->f.quant.delta_q_uv_ac,
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.seg.feature_data,
-				   sizeof(__entry->f.seg.feature_data),
-				   false),
-		  __print_array(__entry->f.seg.feature_enabled,
-				ARRAY_SIZE(__entry->f.seg.feature_enabled),
-				sizeof(__entry->f.seg.feature_enabled[0])),
-		  __print_array(__entry->f.seg.tree_probs,
-				ARRAY_SIZE(__entry->f.seg.tree_probs),
-				sizeof(__entry->f.seg.tree_probs[0])),
-		  __print_array(__entry->f.seg.pred_probs,
-				ARRAY_SIZE(__entry->f.seg.pred_probs),
-				sizeof(__entry->f.seg.pred_probs[0])),
-		  __print_flags(__entry->f.seg.flags, "|",
-		  {V4L2_VP9_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
-		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
-		  {V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
-		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
-		  {V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE, "ABS_OR_DELTA_UPDATE"}),
-		  __print_flags(__entry->f.flags, "|",
-		  {V4L2_VP9_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
-		  {V4L2_VP9_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
-		  {V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT, "ERROR_RESILIENT"},
-		  {V4L2_VP9_FRAME_FLAG_INTRA_ONLY, "INTRA_ONLY"},
-		  {V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV, "ALLOW_HIGH_PREC_MV"},
-		  {V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX, "REFRESH_FRAME_CTX"},
-		  {V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE, "PARALLEL_DEC_MODE"},
-		  {V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING, "X_SUBSAMPLING"},
-		  {V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING, "Y_SUBSAMPLING"},
-		  {V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING, "COLOR_RANGE_FULL_SWING"}),
-		  __entry->f.compressed_header_size,
-		  __entry->f.uncompressed_header_size,
-		  __entry->f.frame_width_minus_1,
-		  __entry->f.frame_height_minus_1,
-		  __entry->f.render_width_minus_1,
-		  __entry->f.render_height_minus_1,
-		  __entry->f.last_frame_ts,
-		  __entry->f.golden_frame_ts,
-		  __entry->f.alt_frame_ts,
-		  __print_symbolic(__entry->f.ref_frame_sign_bias,
-		  {V4L2_VP9_SIGN_BIAS_LAST, "SIGN_BIAS_LAST"},
-		  {V4L2_VP9_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
-		  {V4L2_VP9_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"}),
-		  __print_symbolic(__entry->f.reset_frame_context,
-		  {V4L2_VP9_RESET_FRAME_CTX_NONE, "RESET_FRAME_CTX_NONE"},
-		  {V4L2_VP9_RESET_FRAME_CTX_SPEC, "RESET_FRAME_CTX_SPEC"},
-		  {V4L2_VP9_RESET_FRAME_CTX_ALL, "RESET_FRAME_CTX_ALL"}),
-		  __entry->f.frame_context_idx,
-		  __entry->f.profile,
-		  __entry->f.bit_depth,
-		  __print_symbolic(__entry->f.interpolation_filter,
-		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP, "INTERP_FILTER_EIGHTTAP"},
-		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH, "INTERP_FILTER_EIGHTTAP_SMOOTH"},
-		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SHARP, "INTERP_FILTER_EIGHTTAP_SHARP"},
-		  {V4L2_VP9_INTERP_FILTER_BILINEAR, "INTERP_FILTER_BILINEAR"},
-		  {V4L2_VP9_INTERP_FILTER_SWITCHABLE, "INTERP_FILTER_SWITCHABLE"}),
-		  __entry->f.tile_cols_log2,
-		  __entry->f.tile_rows_log2,
-		  __print_symbolic(__entry->f.reference_mode,
-		  {V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, "REFERENCE_MODE_SINGLE_REFERENCE"},
-		  {V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE, "REFERENCE_MODE_COMPOUND_REFERENCE"},
-		  {V4L2_VP9_REFERENCE_MODE_SELECT, "REFERENCE_MODE_SELECT"}))
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
-	TP_fast_assign(__entry->h = *h;),
-	TP_printk("\ntx_mode %s\n"
-		  "tx8 {%s}\n"
-		  "tx16 {%s}\n"
-		  "tx32 {%s}\n"
-		  "skip %s\n"
-		  "inter_mode {%s}\n"
-		  "interp_filter {%s}\n"
-		  "is_inter %s\n"
-		  "comp_mode %s\n"
-		  "single_ref {%s}\n"
-		  "comp_ref %s\n"
-		  "y_mode {%s}\n"
-		  "uv_mode {%s}\n"
-		  "partition {%s}\n",
-		  __print_symbolic(__entry->h.tx_mode,
-		  {V4L2_VP9_TX_MODE_ONLY_4X4, "TX_MODE_ONLY_4X4"},
-		  {V4L2_VP9_TX_MODE_ALLOW_8X8, "TX_MODE_ALLOW_8X8"},
-		  {V4L2_VP9_TX_MODE_ALLOW_16X16, "TX_MODE_ALLOW_16X16"},
-		  {V4L2_VP9_TX_MODE_ALLOW_32X32, "TX_MODE_ALLOW_32X32"},
-		  {V4L2_VP9_TX_MODE_SELECT, "TX_MODE_SELECT"}),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx8,
-				   sizeof(__entry->h.tx8),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx16,
-				   sizeof(__entry->h.tx16),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx32,
-				   sizeof(__entry->h.tx32),
-				   false),
-		  __print_array(__entry->h.skip,
-				ARRAY_SIZE(__entry->h.skip),
-				sizeof(__entry->h.skip[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.inter_mode,
-				   sizeof(__entry->h.inter_mode),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.interp_filter,
-				   sizeof(__entry->h.interp_filter),
-				   false),
-		  __print_array(__entry->h.is_inter,
-				ARRAY_SIZE(__entry->h.is_inter),
-				sizeof(__entry->h.is_inter[0])),
-		  __print_array(__entry->h.comp_mode,
-				ARRAY_SIZE(__entry->h.comp_mode),
-				sizeof(__entry->h.comp_mode[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.single_ref,
-				   sizeof(__entry->h.single_ref),
-				   false),
-		  __print_array(__entry->h.comp_ref,
-				ARRAY_SIZE(__entry->h.comp_ref),
-				sizeof(__entry->h.comp_ref[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.y_mode,
-				   sizeof(__entry->h.y_mode),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.uv_mode,
-				   sizeof(__entry->h.uv_mode),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.partition,
-				   sizeof(__entry->h.partition),
-				   false)
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
-	TP_fast_assign(__entry->h = *h;),
-	TP_printk("\n coef {%s}",
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.coef,
-				   sizeof(__entry->h.coef),
-				   false)
-	)
-);
-
-DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
-	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_vp9_mv_probs, p)),
-	TP_fast_assign(__entry->p = *p;),
-	TP_printk("\n joint %s\n"
-		  "sign %s\n"
-		  "classes {%s}\n"
-		  "class0_bit %s\n"
-		  "bits {%s}\n"
-		  "class0_fr {%s}\n"
-		  "fr {%s}\n"
-		  "class0_hp %s\n"
-		  "hp %s\n",
-		  __print_array(__entry->p.joint,
-				ARRAY_SIZE(__entry->p.joint),
-				sizeof(__entry->p.joint[0])),
-		  __print_array(__entry->p.sign,
-				ARRAY_SIZE(__entry->p.sign),
-				sizeof(__entry->p.sign[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.classes,
-				   sizeof(__entry->p.classes),
-				   false),
-		  __print_array(__entry->p.class0_bit,
-				ARRAY_SIZE(__entry->p.class0_bit),
-				sizeof(__entry->p.class0_bit[0])),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.bits,
-				   sizeof(__entry->p.bits),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.class0_fr,
-				   sizeof(__entry->p.class0_fr),
-				   false),
-		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.fr,
-				   sizeof(__entry->p.fr),
-				   false),
-		  __print_array(__entry->p.class0_hp,
-				ARRAY_SIZE(__entry->p.class0_hp),
-				sizeof(__entry->p.class0_hp[0])),
-		  __print_array(__entry->p.hp,
-				ARRAY_SIZE(__entry->p.hp),
-				sizeof(__entry->p.hp[0]))
-	)
-);
-
-DEFINE_EVENT(v4l2_ctrl_vp9_frame_tmpl, v4l2_ctrl_vp9_frame,
-	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
-	TP_ARGS(f)
-);
-
-DEFINE_EVENT(v4l2_ctrl_vp9_compressed_hdr_tmpl, v4l2_ctrl_vp9_compressed_hdr,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h)
-);
-
-DEFINE_EVENT(v4l2_ctrl_vp9_compressed_coef_tmpl, v4l2_ctrl_vp9_compressed_coeff,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h)
-);
-
-
-DEFINE_EVENT(v4l2_vp9_mv_probs_tmpl, v4l2_vp9_mv_probs,
-	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
-	TP_ARGS(p)
-);
-
-#endif
-
-#undef TRACE_INCLUDE_PATH
-#undef TRACE_INCLUDE_FILE
-#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
-#define TRACE_INCLUDE_FILE visl-trace-vp9
-#include <trace/define_trace.h>
diff --git a/drivers/media/v4l2-core/v4l2-trace.c b/drivers/media/v4l2-core/v4l2-trace.c
index 95f3b02e1f84..183d5ecb49c5 100644
--- a/drivers/media/v4l2-core/v4l2-trace.c
+++ b/drivers/media/v4l2-core/v4l2-trace.c
@@ -5,8 +5,53 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/v4l2.h>
+#include <trace/events/v4l2_controls.h>
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_buf_done);
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_buf_queue);
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_dqbuf);
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_qbuf);
+
+/* Export AV1 controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_sequence);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_frame);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_tile_group_entry);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_film_grain);
+
+/* Export FWHT controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_fwht_params);
+
+/* Export H264 controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_sps);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_pps);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_scaling_matrix);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_pred_weights);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_slice_params);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_h264_ref_pic_list0);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_h264_ref_pic_list1);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_h264_decode_params);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_h264_dpb_entry);
+
+/* Export HEVC controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_hevc_sps);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_hevc_pps);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_hevc_slice_params);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_hevc_pred_weight_table);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_hevc_scaling_matrix);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_hevc_decode_params);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_hevc_dpb_entry);
+
+/* Export MPEG2 controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_mpeg2_sequence);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_mpeg2_picture);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_mpeg2_quantisation);
+
+/* Export VP8 controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_vp8_frame);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_vp8_entropy);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_vp9_frame);
+
+/* Export VP9 controls */
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_vp9_compressed_hdr);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_vp9_compressed_coeff);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_vp9_mv_probs);
diff --git a/include/trace/events/v4l2_controls.h b/include/trace/events/v4l2_controls.h
new file mode 100644
index 000000000000..9c74309b31ef
--- /dev/null
+++ b/include/trace/events/v4l2_controls.h
@@ -0,0 +1,1645 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_TRACE_V4L2_CONTROLS_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_V4L2_CONTROLS_H_
+
+#include <linux/tracepoint.h>
+#include <linux/v4l2-controls.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM v4l2_controls
+
+/* AV1 controls */
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_sequence, s)),
+	TP_fast_assign(__entry->s = *s;),
+	TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
+		  "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n",
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"},
+		  {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA, "ENABLE_FILTER_INTRA"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER, "ENABLE_INTRA_EDGE_FILTER"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND, "ENABLE_INTERINTRA_COMPOUND"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND, "ENABLE_MASKED_COMPOUND"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION, "ENABLE_WARPED_MOTION"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER, "ENABLE_DUAL_FILTER"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT, "ENABLE_ORDER_HINT"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP, "ENABLE_JNT_COMP"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS, "ENABLE_REF_FRAME_MVS"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES, "ENABLE_SUPERRES"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF, "ENABLE_CDEF"},
+		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION, "ENABLE_RESTORATION"},
+		  {V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME, "MONO_CHROME"},
+		  {V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE, "COLOR_RANGE"},
+		  {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X, "SUBSAMPLING_X"},
+		  {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y, "SUBSAMPLING_Y"},
+		  {V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT, "FILM_GRAIN_PARAMS_PRESENT"},
+		  {V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q, "SEPARATE_UV_DELTA_Q"}),
+		  __entry->s.seq_profile,
+		  __entry->s.order_hint_bits,
+		  __entry->s.bit_depth,
+		  __entry->s.max_frame_width_minus_1,
+		  __entry->s.max_frame_height_minus_1
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
+	TP_ARGS(t),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_tile_group_entry, t)),
+	TP_fast_assign(__entry->t = *t;),
+	TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
+		  __entry->t.tile_offset,
+		  __entry->t.tile_size,
+		  __entry->t.tile_row,
+		  __entry->t.tile_col
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
+	TP_ARGS(f),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_frame, f)),
+	TP_fast_assign(__entry->f = *f;),
+	TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
+		  "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n"
+		  "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n"
+		  "tile_info.width_in_sbs_minus_1: %s\ntile_info.height_in_sbs_minus_1: %s\n"
+		  "tile_info.tile_size_bytes: %u\nquantization.flags: %s\n"
+		  "quantization.base_q_idx: %u\nquantization.delta_q_y_dc: %d\n"
+		  "quantization.delta_q_u_dc: %d\nquantization.delta_q_u_ac: %d\n"
+		  "quantization.delta_q_v_dc: %d\nquantization.delta_q_v_ac: %d\n"
+		  "quantization.qm_y: %u\nquantization.qm_u: %u\nquantization.qm_v: %u\n"
+		  "quantization.delta_q_res: %u\nsuperres_denom: %u\nsegmentation.flags: %s\n"
+		  "segmentation.last_active_seg_id: %u\nsegmentation.feature_enabled:%s\n"
+		  "loop_filter.flags: %s\nloop_filter.level: %s\nloop_filter.sharpness: %u\n"
+		  "loop_filter.ref_deltas: %s\nloop_filter.mode_deltas: %s\n"
+		  "loop_filter.delta_lf_res: %u\ncdef.damping_minus_3: %u\ncdef.bits: %u\n"
+		  "cdef.y_pri_strength: %s\ncdef.y_sec_strength: %s\n"
+		  "cdef.uv_pri_strength: %s\ncdef.uv_sec_strength:%s\nskip_mode_frame: %s\n"
+		  "primary_ref_frame: %u\nloop_restoration.flags: %s\n"
+		  "loop_restoration.lr_unit_shift: %u\nloop_restoration.lr_uv_shift: %u\n"
+		  "loop_restoration.frame_restoration_type: %s\n"
+		  "loop_restoration.loop_restoration_size: %s\nflags: %s\norder_hint: %u\n"
+		  "upscaled_width: %u\nframe_width_minus_1: %u\nframe_height_minus_1: %u\n"
+		  "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n"
+		  "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n"
+		  "ref_frame_idx: %s\nrefresh_frame_flags: %u\n",
+		  __print_flags(__entry->f.tile_info.flags, "|",
+		  {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}),
+		  __entry->f.tile_info.context_update_tile_id,
+		  __entry->f.tile_info.tile_cols,
+		  __entry->f.tile_info.tile_rows,
+		  __print_array(__entry->f.tile_info.mi_col_starts,
+				ARRAY_SIZE(__entry->f.tile_info.mi_col_starts),
+				sizeof(__entry->f.tile_info.mi_col_starts[0])),
+		  __print_array(__entry->f.tile_info.mi_row_starts,
+				ARRAY_SIZE(__entry->f.tile_info.mi_row_starts),
+				sizeof(__entry->f.tile_info.mi_row_starts[0])),
+		  __print_array(__entry->f.tile_info.width_in_sbs_minus_1,
+				ARRAY_SIZE(__entry->f.tile_info.width_in_sbs_minus_1),
+				sizeof(__entry->f.tile_info.width_in_sbs_minus_1[0])),
+		  __print_array(__entry->f.tile_info.height_in_sbs_minus_1,
+				ARRAY_SIZE(__entry->f.tile_info.height_in_sbs_minus_1),
+				sizeof(__entry->f.tile_info.height_in_sbs_minus_1[0])),
+		  __entry->f.tile_info.tile_size_bytes,
+		  __print_flags(__entry->f.quantization.flags, "|",
+		  {V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA, "DIFF_UV_DELTA"},
+		  {V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX, "USING_QMATRIX"},
+		  {V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT, "DELTA_Q_PRESENT"}),
+		  __entry->f.quantization.base_q_idx,
+		  __entry->f.quantization.delta_q_y_dc,
+		  __entry->f.quantization.delta_q_u_dc,
+		  __entry->f.quantization.delta_q_u_ac,
+		  __entry->f.quantization.delta_q_v_dc,
+		  __entry->f.quantization.delta_q_v_ac,
+		  __entry->f.quantization.qm_y,
+		  __entry->f.quantization.qm_u,
+		  __entry->f.quantization.qm_v,
+		  __entry->f.quantization.delta_q_res,
+		  __entry->f.superres_denom,
+		  __print_flags(__entry->f.segmentation.flags, "|",
+		  {V4L2_AV1_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
+		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
+		  {V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
+		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
+		  {V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP, "SEG_ID_PRE_SKIP"}),
+		  __entry->f.segmentation.last_active_seg_id,
+		  __print_array(__entry->f.segmentation.feature_enabled,
+				ARRAY_SIZE(__entry->f.segmentation.feature_enabled),
+				sizeof(__entry->f.segmentation.feature_enabled[0])),
+		  __print_flags(__entry->f.loop_filter.flags, "|",
+		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
+		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"},
+		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT, "DELTA_LF_PRESENT"},
+		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI, "DELTA_LF_MULTI"}),
+		  __print_array(__entry->f.loop_filter.level,
+				ARRAY_SIZE(__entry->f.loop_filter.level),
+				sizeof(__entry->f.loop_filter.level[0])),
+		  __entry->f.loop_filter.sharpness,
+		  __print_array(__entry->f.loop_filter.ref_deltas,
+				ARRAY_SIZE(__entry->f.loop_filter.ref_deltas),
+				sizeof(__entry->f.loop_filter.ref_deltas[0])),
+		  __print_array(__entry->f.loop_filter.mode_deltas,
+				ARRAY_SIZE(__entry->f.loop_filter.mode_deltas),
+				sizeof(__entry->f.loop_filter.mode_deltas[0])),
+		  __entry->f.loop_filter.delta_lf_res,
+		  __entry->f.cdef.damping_minus_3,
+		  __entry->f.cdef.bits,
+		  __print_array(__entry->f.cdef.y_pri_strength,
+				ARRAY_SIZE(__entry->f.cdef.y_pri_strength),
+				sizeof(__entry->f.cdef.y_pri_strength[0])),
+		  __print_array(__entry->f.cdef.y_sec_strength,
+				ARRAY_SIZE(__entry->f.cdef.y_sec_strength),
+				sizeof(__entry->f.cdef.y_sec_strength[0])),
+		  __print_array(__entry->f.cdef.uv_pri_strength,
+				ARRAY_SIZE(__entry->f.cdef.uv_pri_strength),
+				sizeof(__entry->f.cdef.uv_pri_strength[0])),
+		  __print_array(__entry->f.cdef.uv_sec_strength,
+				ARRAY_SIZE(__entry->f.cdef.uv_sec_strength),
+				sizeof(__entry->f.cdef.uv_sec_strength[0])),
+		  __print_array(__entry->f.skip_mode_frame,
+				ARRAY_SIZE(__entry->f.skip_mode_frame),
+				sizeof(__entry->f.skip_mode_frame[0])),
+		  __entry->f.primary_ref_frame,
+		  __print_flags(__entry->f.loop_restoration.flags, "|",
+		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR, "USES_LR"},
+		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR, "USES_CHROMA_LR"}),
+		  __entry->f.loop_restoration.lr_unit_shift,
+		  __entry->f.loop_restoration.lr_uv_shift,
+		  __print_array(__entry->f.loop_restoration.frame_restoration_type,
+				ARRAY_SIZE(__entry->f.loop_restoration.frame_restoration_type),
+				sizeof(__entry->f.loop_restoration.frame_restoration_type[0])),
+		  __print_array(__entry->f.loop_restoration.loop_restoration_size,
+				ARRAY_SIZE(__entry->f.loop_restoration.loop_restoration_size),
+				sizeof(__entry->f.loop_restoration.loop_restoration_size[0])),
+		  __print_flags(__entry->f.flags, "|",
+		  {V4L2_AV1_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+		  {V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME, "SHOWABLE_FRAME"},
+		  {V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE, "ERROR_RESILIENT_MODE"},
+		  {V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE, "DISABLE_CDF_UPDATE"},
+		  {V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS, "ALLOW_SCREEN_CONTENT_TOOLS"},
+		  {V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV, "FORCE_INTEGER_MV"},
+		  {V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC, "ALLOW_INTRABC"},
+		  {V4L2_AV1_FRAME_FLAG_USE_SUPERRES, "USE_SUPERRES"},
+		  {V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV, "ALLOW_HIGH_PRECISION_MV"},
+		  {V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE, "IS_MOTION_MODE_SWITCHABLE"},
+		  {V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS, "USE_REF_FRAME_MVS"},
+		  {V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF,
+		   "DISABLE_FRAME_END_UPDATE_CDF"},
+		  {V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION, "ALLOW_WARPED_MOTION"},
+		  {V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT, "REFERENCE_SELECT"},
+		  {V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET, "REDUCED_TX_SET"},
+		  {V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED, "SKIP_MODE_ALLOWED"},
+		  {V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT, "SKIP_MODE_PRESENT"},
+		  {V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE, "FRAME_SIZE_OVERRIDE"},
+		  {V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT, "BUFFER_REMOVAL_TIME_PRESENT"},
+		  {V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING, "FRAME_REFS_SHORT_SIGNALING"}),
+		  __entry->f.order_hint,
+		  __entry->f.upscaled_width,
+		  __entry->f.frame_width_minus_1,
+		  __entry->f.frame_height_minus_1,
+		  __entry->f.render_width_minus_1,
+		  __entry->f.render_height_minus_1,
+		  __entry->f.current_frame_id,
+		  __print_array(__entry->f.buffer_removal_time,
+				ARRAY_SIZE(__entry->f.buffer_removal_time),
+				sizeof(__entry->f.buffer_removal_time[0])),
+		  __print_array(__entry->f.order_hints,
+				ARRAY_SIZE(__entry->f.order_hints),
+				sizeof(__entry->f.order_hints[0])),
+		  __print_array(__entry->f.reference_frame_ts,
+				ARRAY_SIZE(__entry->f.reference_frame_ts),
+				sizeof(__entry->f.reference_frame_ts[0])),
+		  __print_array(__entry->f.ref_frame_idx,
+				ARRAY_SIZE(__entry->f.ref_frame_idx),
+				sizeof(__entry->f.ref_frame_idx[0])),
+		  __entry->f.refresh_frame_flags
+	)
+);
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
+	TP_ARGS(f),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_film_grain, f)),
+	TP_fast_assign(__entry->f = *f;),
+	TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
+		  "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n"
+		  "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n"
+		  "point_cb_scaling: %s\nnum_cr_points: %u\npoint_cr_value: %s\n"
+		  "point_cr_scaling: %s\ngrain_scaling_minus_8: %u\nar_coeff_lag: %u\n"
+		  "ar_coeffs_y_plus_128: %s\nar_coeffs_cb_plus_128: %s\n"
+		  "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n"
+		  "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n"
+		  "cb_offset: %u\ncr_offset: %u\n",
+		  __print_flags(__entry->f.flags, "|",
+		  {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"},
+		  {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"},
+		  {V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA, "CHROMA_SCALING_FROM_LUMA"},
+		  {V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP, "OVERLAP"},
+		  {V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE, "CLIP_TO_RESTRICTED_RANGE"}),
+		  __entry->f.cr_mult,
+		  __entry->f.grain_seed,
+		  __entry->f.film_grain_params_ref_idx,
+		  __entry->f.num_y_points,
+		  __print_array(__entry->f.point_y_value,
+				ARRAY_SIZE(__entry->f.point_y_value),
+				sizeof(__entry->f.point_y_value[0])),
+		  __print_array(__entry->f.point_y_scaling,
+				ARRAY_SIZE(__entry->f.point_y_scaling),
+				sizeof(__entry->f.point_y_scaling[0])),
+		  __entry->f.num_cb_points,
+		  __print_array(__entry->f.point_cb_value,
+				ARRAY_SIZE(__entry->f.point_cb_value),
+				sizeof(__entry->f.point_cb_value[0])),
+		  __print_array(__entry->f.point_cb_scaling,
+				ARRAY_SIZE(__entry->f.point_cb_scaling),
+				sizeof(__entry->f.point_cb_scaling[0])),
+		  __entry->f.num_cr_points,
+		  __print_array(__entry->f.point_cr_value,
+				ARRAY_SIZE(__entry->f.point_cr_value),
+				sizeof(__entry->f.point_cr_value[0])),
+		  __print_array(__entry->f.point_cr_scaling,
+				ARRAY_SIZE(__entry->f.point_cr_scaling),
+				sizeof(__entry->f.point_cr_scaling[0])),
+		  __entry->f.grain_scaling_minus_8,
+		  __entry->f.ar_coeff_lag,
+		  __print_array(__entry->f.ar_coeffs_y_plus_128,
+				ARRAY_SIZE(__entry->f.ar_coeffs_y_plus_128),
+				sizeof(__entry->f.ar_coeffs_y_plus_128[0])),
+		  __print_array(__entry->f.ar_coeffs_cb_plus_128,
+				ARRAY_SIZE(__entry->f.ar_coeffs_cb_plus_128),
+				sizeof(__entry->f.ar_coeffs_cb_plus_128[0])),
+		  __print_array(__entry->f.ar_coeffs_cr_plus_128,
+				ARRAY_SIZE(__entry->f.ar_coeffs_cr_plus_128),
+				sizeof(__entry->f.ar_coeffs_cr_plus_128[0])),
+		  __entry->f.ar_coeff_shift_minus_6,
+		  __entry->f.grain_scale_shift,
+		  __entry->f.cb_mult,
+		  __entry->f.cb_luma_mult,
+		  __entry->f.cr_luma_mult,
+		  __entry->f.cb_offset,
+		  __entry->f.cr_offset
+	)
+)
+
+DEFINE_EVENT(v4l2_ctrl_av1_seq_tmpl, v4l2_ctrl_av1_sequence,
+	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_frame_tmpl, v4l2_ctrl_av1_frame,
+	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
+	TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_tge_tmpl, v4l2_ctrl_av1_tile_group_entry,
+	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
+	TP_ARGS(t)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_film_grain_tmpl, v4l2_ctrl_av1_film_grain,
+	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
+	TP_ARGS(f)
+);
+
+/* FWHT controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(
+			 __field(u64, backward_ref_ts)
+			 __field(u32, version)
+			 __field(u32, width)
+			 __field(u32, height)
+			 __field(u32, flags)
+			 __field(u32, colorspace)
+			 __field(u32, xfer_func)
+			 __field(u32, ycbcr_enc)
+			 __field(u32, quantization)
+			 ),
+	TP_fast_assign(
+		       __entry->backward_ref_ts = p->backward_ref_ts;
+		       __entry->version = p->version;
+		       __entry->width = p->width;
+		       __entry->height = p->height;
+		       __entry->flags = p->flags;
+		       __entry->colorspace = p->colorspace;
+		       __entry->xfer_func = p->xfer_func;
+		       __entry->ycbcr_enc = p->ycbcr_enc;
+		       __entry->quantization = p->quantization;
+		       ),
+	TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u xfer_func %u ycbcr_enc %u quantization %u",
+		  __entry->backward_ref_ts, __entry->version, __entry->width, __entry->height,
+		  __print_flags(__entry->flags, "|",
+		  {V4L2_FWHT_FL_IS_INTERLACED, "IS_INTERLACED"},
+		  {V4L2_FWHT_FL_IS_BOTTOM_FIRST, "IS_BOTTOM_FIRST"},
+		  {V4L2_FWHT_FL_IS_ALTERNATE, "IS_ALTERNATE"},
+		  {V4L2_FWHT_FL_IS_BOTTOM_FIELD, "IS_BOTTOM_FIELD"},
+		  {V4L2_FWHT_FL_LUMA_IS_UNCOMPRESSED, "LUMA_IS_UNCOMPRESSED"},
+		  {V4L2_FWHT_FL_CB_IS_UNCOMPRESSED, "CB_IS_UNCOMPRESSED"},
+		  {V4L2_FWHT_FL_CR_IS_UNCOMPRESSED, "CR_IS_UNCOMPRESSED"},
+		  {V4L2_FWHT_FL_ALPHA_IS_UNCOMPRESSED, "ALPHA_IS_UNCOMPRESSED"},
+		  {V4L2_FWHT_FL_I_FRAME, "I_FRAME"},
+		  {V4L2_FWHT_FL_PIXENC_HSV, "PIXENC_HSV"},
+		  {V4L2_FWHT_FL_PIXENC_RGB, "PIXENC_RGB"},
+		  {V4L2_FWHT_FL_PIXENC_YUV, "PIXENC_YUV"}),
+		  __entry->colorspace, __entry->xfer_func, __entry->ycbcr_enc,
+		  __entry->quantization)
+);
+
+DEFINE_EVENT(v4l2_ctrl_fwht_params_tmpl, v4l2_ctrl_fwht_params,
+	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
+	TP_ARGS(p)
+);
+
+/* H264 controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_sps, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nprofile_idc %u\n"
+		  "constraint_set_flags %s\n"
+		  "level_idc %u\n"
+		  "seq_parameter_set_id %u\n"
+		  "chroma_format_idc %u\n"
+		  "bit_depth_luma_minus8 %u\n"
+		  "bit_depth_chroma_minus8 %u\n"
+		  "log2_max_frame_num_minus4 %u\n"
+		  "pic_order_cnt_type %u\n"
+		  "log2_max_pic_order_cnt_lsb_minus4 %u\n"
+		  "max_num_ref_frames %u\n"
+		  "num_ref_frames_in_pic_order_cnt_cycle %u\n"
+		  "offset_for_ref_frame %s\n"
+		  "offset_for_non_ref_pic %d\n"
+		  "offset_for_top_to_bottom_field %d\n"
+		  "pic_width_in_mbs_minus1 %u\n"
+		  "pic_height_in_map_units_minus1 %u\n"
+		  "flags %s",
+		  __entry->s.profile_idc,
+		  __print_flags(__entry->s.constraint_set_flags, "|",
+		  {V4L2_H264_SPS_CONSTRAINT_SET0_FLAG, "CONSTRAINT_SET0_FLAG"},
+		  {V4L2_H264_SPS_CONSTRAINT_SET1_FLAG, "CONSTRAINT_SET1_FLAG"},
+		  {V4L2_H264_SPS_CONSTRAINT_SET2_FLAG, "CONSTRAINT_SET2_FLAG"},
+		  {V4L2_H264_SPS_CONSTRAINT_SET3_FLAG, "CONSTRAINT_SET3_FLAG"},
+		  {V4L2_H264_SPS_CONSTRAINT_SET4_FLAG, "CONSTRAINT_SET4_FLAG"},
+		  {V4L2_H264_SPS_CONSTRAINT_SET5_FLAG, "CONSTRAINT_SET5_FLAG"}),
+		  __entry->s.level_idc,
+		  __entry->s.seq_parameter_set_id,
+		  __entry->s.chroma_format_idc,
+		  __entry->s.bit_depth_luma_minus8,
+		  __entry->s.bit_depth_chroma_minus8,
+		  __entry->s.log2_max_frame_num_minus4,
+		  __entry->s.pic_order_cnt_type,
+		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
+		  __entry->s.max_num_ref_frames,
+		  __entry->s.num_ref_frames_in_pic_order_cnt_cycle,
+		  __print_array(__entry->s.offset_for_ref_frame,
+				ARRAY_SIZE(__entry->s.offset_for_ref_frame),
+				sizeof(__entry->s.offset_for_ref_frame[0])),
+		  __entry->s.offset_for_non_ref_pic,
+		  __entry->s.offset_for_top_to_bottom_field,
+		  __entry->s.pic_width_in_mbs_minus1,
+		  __entry->s.pic_height_in_map_units_minus1,
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
+		  {V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS, "QPPRIME_Y_ZERO_TRANSFORM_BYPASS"},
+		  {V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO, "DELTA_PIC_ORDER_ALWAYS_ZERO"},
+		  {V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED, "GAPS_IN_FRAME_NUM_VALUE_ALLOWED"},
+		  {V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY, "FRAME_MBS_ONLY"},
+		  {V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD, "MB_ADAPTIVE_FRAME_FIELD"},
+		  {V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE, "DIRECT_8X8_INFERENCE"}
+		  ))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pps, p)),
+	TP_fast_assign(__entry->p = *p),
+	TP_printk("\npic_parameter_set_id %u\n"
+		  "seq_parameter_set_id %u\n"
+		  "num_slice_groups_minus1 %u\n"
+		  "num_ref_idx_l0_default_active_minus1 %u\n"
+		  "num_ref_idx_l1_default_active_minus1 %u\n"
+		  "weighted_bipred_idc %u\n"
+		  "pic_init_qp_minus26 %d\n"
+		  "pic_init_qs_minus26 %d\n"
+		  "chroma_qp_index_offset %d\n"
+		  "second_chroma_qp_index_offset %d\n"
+		  "flags %s",
+		  __entry->p.pic_parameter_set_id,
+		  __entry->p.seq_parameter_set_id,
+		  __entry->p.num_slice_groups_minus1,
+		  __entry->p.num_ref_idx_l0_default_active_minus1,
+		  __entry->p.num_ref_idx_l1_default_active_minus1,
+		  __entry->p.weighted_bipred_idc,
+		  __entry->p.pic_init_qp_minus26,
+		  __entry->p.pic_init_qs_minus26,
+		  __entry->p.chroma_qp_index_offset,
+		  __entry->p.second_chroma_qp_index_offset,
+		  __print_flags(__entry->p.flags, "|",
+		  {V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE, "ENTROPY_CODING_MODE"},
+		  {V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT, "BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT"},
+		  {V4L2_H264_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
+		  {V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+		  {V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
+		  {V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT, "REDUNDANT_PIC_CNT_PRESENT"},
+		  {V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE, "TRANSFORM_8X8_MODE"},
+		  {V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT, "SCALING_MATRIX_PRESENT"}
+		  ))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_scaling_matrix, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_4x4,
+				   sizeof(__entry->s.scaling_list_4x4),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_8x8,
+				   sizeof(__entry->s.scaling_list_8x8),
+				   false)
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pred_weights, p)),
+	TP_fast_assign(__entry->p = *p),
+	TP_printk("\nluma_log2_weight_denom %u\n"
+		  "chroma_log2_weight_denom %u\n"
+		  "weight_factor[0].luma_weight %s\n"
+		  "weight_factor[0].luma_offset %s\n"
+		  "weight_factor[0].chroma_weight {%s}\n"
+		  "weight_factor[0].chroma_offset {%s}\n"
+		  "weight_factor[1].luma_weight %s\n"
+		  "weight_factor[1].luma_offset %s\n"
+		  "weight_factor[1].chroma_weight {%s}\n"
+		  "weight_factor[1].chroma_offset {%s}\n",
+		  __entry->p.luma_log2_weight_denom,
+		  __entry->p.chroma_log2_weight_denom,
+		  __print_array(__entry->p.weight_factors[0].luma_weight,
+				ARRAY_SIZE(__entry->p.weight_factors[0].luma_weight),
+				sizeof(__entry->p.weight_factors[0].luma_weight[0])),
+		  __print_array(__entry->p.weight_factors[0].luma_offset,
+				ARRAY_SIZE(__entry->p.weight_factors[0].luma_offset),
+				sizeof(__entry->p.weight_factors[0].luma_offset[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.weight_factors[0].chroma_weight,
+				   sizeof(__entry->p.weight_factors[0].chroma_weight),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.weight_factors[0].chroma_offset,
+				   sizeof(__entry->p.weight_factors[0].chroma_offset),
+				   false),
+		  __print_array(__entry->p.weight_factors[1].luma_weight,
+				ARRAY_SIZE(__entry->p.weight_factors[1].luma_weight),
+				sizeof(__entry->p.weight_factors[1].luma_weight[0])),
+		  __print_array(__entry->p.weight_factors[1].luma_offset,
+				ARRAY_SIZE(__entry->p.weight_factors[1].luma_offset),
+				sizeof(__entry->p.weight_factors[1].luma_offset[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.weight_factors[1].chroma_weight,
+				   sizeof(__entry->p.weight_factors[1].chroma_weight),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.weight_factors[1].chroma_offset,
+				   sizeof(__entry->p.weight_factors[1].chroma_offset),
+				   false)
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_slice_params, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nheader_bit_size %u\n"
+		  "first_mb_in_slice %u\n"
+		  "slice_type %s\n"
+		  "colour_plane_id %u\n"
+		  "redundant_pic_cnt %u\n"
+		  "cabac_init_idc %u\n"
+		  "slice_qp_delta %d\n"
+		  "slice_qs_delta %d\n"
+		  "disable_deblocking_filter_idc %u\n"
+		  "slice_alpha_c0_offset_div2 %u\n"
+		  "slice_beta_offset_div2 %u\n"
+		  "num_ref_idx_l0_active_minus1 %u\n"
+		  "num_ref_idx_l1_active_minus1 %u\n"
+		  "flags %s",
+		  __entry->s.header_bit_size,
+		  __entry->s.first_mb_in_slice,
+		  __print_symbolic(__entry->s.slice_type,
+		  {V4L2_H264_SLICE_TYPE_P, "P"},
+		  {V4L2_H264_SLICE_TYPE_B, "B"},
+		  {V4L2_H264_SLICE_TYPE_I, "I"},
+		  {V4L2_H264_SLICE_TYPE_SP, "SP"},
+		  {V4L2_H264_SLICE_TYPE_SI, "SI"}),
+		  __entry->s.colour_plane_id,
+		  __entry->s.redundant_pic_cnt,
+		  __entry->s.cabac_init_idc,
+		  __entry->s.slice_qp_delta,
+		  __entry->s.slice_qs_delta,
+		  __entry->s.disable_deblocking_filter_idc,
+		  __entry->s.slice_alpha_c0_offset_div2,
+		  __entry->s.slice_beta_offset_div2,
+		  __entry->s.num_ref_idx_l0_active_minus1,
+		  __entry->s.num_ref_idx_l1_active_minus1,
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED, "DIRECT_SPATIAL_MV_PRED"},
+		  {V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH, "SP_FOR_SWITCH"})
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
+	TP_PROTO(const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(r, i),
+	TP_STRUCT__entry(__field_struct(struct v4l2_h264_reference, r)
+			 __field(int, i)),
+	TP_fast_assign(__entry->r = *r; __entry->i = i;),
+	TP_printk("[%d]: fields %s index %u",
+		  __entry->i,
+		  __print_flags(__entry->r.fields, "|",
+		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
+		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
+		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
+		  __entry->r.index
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
+	TP_ARGS(d),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_decode_params, d)),
+	TP_fast_assign(__entry->d = *d),
+	TP_printk("\nnal_ref_idc %u\n"
+		  "frame_num %u\n"
+		  "top_field_order_cnt %d\n"
+		  "bottom_field_order_cnt %d\n"
+		  "idr_pic_id %u\n"
+		  "pic_order_cnt_lsb %u\n"
+		  "delta_pic_order_cnt_bottom %d\n"
+		  "delta_pic_order_cnt0 %d\n"
+		  "delta_pic_order_cnt1 %d\n"
+		  "dec_ref_pic_marking_bit_size %u\n"
+		  "pic_order_cnt_bit_size %u\n"
+		  "slice_group_change_cycle %u\n"
+		  "flags %s\n",
+		  __entry->d.nal_ref_idc,
+		  __entry->d.frame_num,
+		  __entry->d.top_field_order_cnt,
+		  __entry->d.bottom_field_order_cnt,
+		  __entry->d.idr_pic_id,
+		  __entry->d.pic_order_cnt_lsb,
+		  __entry->d.delta_pic_order_cnt_bottom,
+		  __entry->d.delta_pic_order_cnt0,
+		  __entry->d.delta_pic_order_cnt1,
+		  __entry->d.dec_ref_pic_marking_bit_size,
+		  __entry->d.pic_order_cnt_bit_size,
+		  __entry->d.slice_group_change_cycle,
+		  __print_flags(__entry->d.flags, "|",
+		  {V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
+		  {V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC, "FIELD_PIC"},
+		  {V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD, "BOTTOM_FIELD"},
+		  {V4L2_H264_DECODE_PARAM_FLAG_PFRAME, "PFRAME"},
+		  {V4L2_H264_DECODE_PARAM_FLAG_BFRAME, "BFRAME"})
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
+	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
+	TP_ARGS(e, i),
+	TP_STRUCT__entry(__field_struct(struct v4l2_h264_dpb_entry, e)
+			 __field(int, i)),
+	TP_fast_assign(__entry->e = *e; __entry->i = i;),
+	TP_printk("[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
+		  "top_field_order_cnt %d bottom_field_order_cnt %d flags %s",
+		  __entry->i,
+		  __entry->e.reference_ts,
+		  __entry->e.pic_num,
+		  __entry->e.frame_num,
+		  __print_flags(__entry->e.fields, "|",
+		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
+		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
+		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
+		  __entry->e.top_field_order_cnt,
+		  __entry->e.bottom_field_order_cnt,
+		  __print_flags(__entry->e.flags, "|",
+		  {V4L2_H264_DPB_ENTRY_FLAG_VALID, "VALID"},
+		  {V4L2_H264_DPB_ENTRY_FLAG_ACTIVE, "ACTIVE"},
+		  {V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM, "LONG_TERM"},
+		  {V4L2_H264_DPB_ENTRY_FLAG_FIELD, "FIELD"})
+
+	)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_sps_tmpl, v4l2_ctrl_h264_sps,
+	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_pps_tmpl, v4l2_ctrl_h264_pps,
+	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
+	TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_scaling_matrix_tmpl, v4l2_ctrl_h264_scaling_matrix,
+	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_pred_weights_tmpl, v4l2_ctrl_h264_pred_weights,
+	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
+	TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_slice_params_tmpl, v4l2_ctrl_h264_slice_params,
+	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list0,
+	TP_PROTO(const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(r, i)
+);
+
+DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list1,
+	TP_PROTO(const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(r, i)
+);
+
+DEFINE_EVENT(v4l2_ctrl_h264_decode_params_tmpl, v4l2_ctrl_h264_decode_params,
+	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
+	TP_ARGS(d)
+);
+
+DEFINE_EVENT(v4l2_h264_dpb_entry_tmpl, v4l2_h264_dpb_entry,
+	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
+	TP_ARGS(e, i)
+);
+
+/* HEVC controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_sps, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nvideo_parameter_set_id %u\n"
+		  "seq_parameter_set_id %u\n"
+		  "pic_width_in_luma_samples %u\n"
+		  "pic_height_in_luma_samples %u\n"
+		  "bit_depth_luma_minus8 %u\n"
+		  "bit_depth_chroma_minus8 %u\n"
+		  "log2_max_pic_order_cnt_lsb_minus4 %u\n"
+		  "sps_max_dec_pic_buffering_minus1 %u\n"
+		  "sps_max_num_reorder_pics %u\n"
+		  "sps_max_latency_increase_plus1 %u\n"
+		  "log2_min_luma_coding_block_size_minus3 %u\n"
+		  "log2_diff_max_min_luma_coding_block_size %u\n"
+		  "log2_min_luma_transform_block_size_minus2 %u\n"
+		  "log2_diff_max_min_luma_transform_block_size %u\n"
+		  "max_transform_hierarchy_depth_inter %u\n"
+		  "max_transform_hierarchy_depth_intra %u\n"
+		  "pcm_sample_bit_depth_luma_minus1 %u\n"
+		  "pcm_sample_bit_depth_chroma_minus1 %u\n"
+		  "log2_min_pcm_luma_coding_block_size_minus3 %u\n"
+		  "log2_diff_max_min_pcm_luma_coding_block_size %u\n"
+		  "num_short_term_ref_pic_sets %u\n"
+		  "num_long_term_ref_pics_sps %u\n"
+		  "chroma_format_idc %u\n"
+		  "sps_max_sub_layers_minus1 %u\n"
+		  "flags %s",
+		  __entry->s.video_parameter_set_id,
+		  __entry->s.seq_parameter_set_id,
+		  __entry->s.pic_width_in_luma_samples,
+		  __entry->s.pic_height_in_luma_samples,
+		  __entry->s.bit_depth_luma_minus8,
+		  __entry->s.bit_depth_chroma_minus8,
+		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
+		  __entry->s.sps_max_dec_pic_buffering_minus1,
+		  __entry->s.sps_max_num_reorder_pics,
+		  __entry->s.sps_max_latency_increase_plus1,
+		  __entry->s.log2_min_luma_coding_block_size_minus3,
+		  __entry->s.log2_diff_max_min_luma_coding_block_size,
+		  __entry->s.log2_min_luma_transform_block_size_minus2,
+		  __entry->s.log2_diff_max_min_luma_transform_block_size,
+		  __entry->s.max_transform_hierarchy_depth_inter,
+		  __entry->s.max_transform_hierarchy_depth_intra,
+		  __entry->s.pcm_sample_bit_depth_luma_minus1,
+		  __entry->s.pcm_sample_bit_depth_chroma_minus1,
+		  __entry->s.log2_min_pcm_luma_coding_block_size_minus3,
+		  __entry->s.log2_diff_max_min_pcm_luma_coding_block_size,
+		  __entry->s.num_short_term_ref_pic_sets,
+		  __entry->s.num_long_term_ref_pics_sps,
+		  __entry->s.chroma_format_idc,
+		  __entry->s.sps_max_sub_layers_minus1,
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
+		  {V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED, "SCALING_LIST_ENABLED"},
+		  {V4L2_HEVC_SPS_FLAG_AMP_ENABLED, "AMP_ENABLED"},
+		  {V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET, "SAMPLE_ADAPTIVE_OFFSET"},
+		  {V4L2_HEVC_SPS_FLAG_PCM_ENABLED, "PCM_ENABLED"},
+		  {V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED, "V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED"},
+		  {V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT, "LONG_TERM_REF_PICS_PRESENT"},
+		  {V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED, "TEMPORAL_MVP_ENABLED"},
+		  {V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED, "STRONG_INTRA_SMOOTHING_ENABLED"}
+	))
+
+);
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_pps, p)),
+	TP_fast_assign(__entry->p = *p),
+	TP_printk("\npic_parameter_set_id %u\n"
+		  "num_extra_slice_header_bits %u\n"
+		  "num_ref_idx_l0_default_active_minus1 %u\n"
+		  "num_ref_idx_l1_default_active_minus1 %u\n"
+		  "init_qp_minus26 %d\n"
+		  "diff_cu_qp_delta_depth %u\n"
+		  "pps_cb_qp_offset %d\n"
+		  "pps_cr_qp_offset %d\n"
+		  "num_tile_columns_minus1 %d\n"
+		  "num_tile_rows_minus1 %d\n"
+		  "column_width_minus1 %s\n"
+		  "row_height_minus1 %s\n"
+		  "pps_beta_offset_div2 %d\n"
+		  "pps_tc_offset_div2 %d\n"
+		  "log2_parallel_merge_level_minus2 %u\n"
+		  "flags %s",
+		  __entry->p.pic_parameter_set_id,
+		  __entry->p.num_extra_slice_header_bits,
+		  __entry->p.num_ref_idx_l0_default_active_minus1,
+		  __entry->p.num_ref_idx_l1_default_active_minus1,
+		  __entry->p.init_qp_minus26,
+		  __entry->p.diff_cu_qp_delta_depth,
+		  __entry->p.pps_cb_qp_offset,
+		  __entry->p.pps_cr_qp_offset,
+		  __entry->p.num_tile_columns_minus1,
+		  __entry->p.num_tile_rows_minus1,
+		  __print_array(__entry->p.column_width_minus1,
+				ARRAY_SIZE(__entry->p.column_width_minus1),
+				sizeof(__entry->p.column_width_minus1[0])),
+		  __print_array(__entry->p.row_height_minus1,
+				ARRAY_SIZE(__entry->p.row_height_minus1),
+				sizeof(__entry->p.row_height_minus1[0])),
+		  __entry->p.pps_beta_offset_div2,
+		  __entry->p.pps_tc_offset_div2,
+		  __entry->p.log2_parallel_merge_level_minus2,
+		  __print_flags(__entry->p.flags, "|",
+		  {V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED, "DEPENDENT_SLICE_SEGMENT_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT, "OUTPUT_FLAG_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED, "SIGN_DATA_HIDING_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT, "CABAC_INIT_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
+		  {V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED, "CU_QP_DELTA_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT, "PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
+		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED, "WEIGHTED_BIPRED"},
+		  {V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, "TRANSQUANT_BYPASS_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_TILES_ENABLED, "TILES_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, "ENTROPY_CODING_SYNC_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, "LOOP_FILTER_ACROSS_TILES_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, "PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED, "DEBLOCKING_FILTER_OVERRIDE_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER, "DISABLE_DEBLOCKING_FILTER"},
+		  {V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT, "LISTS_MODIFICATION_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT, "SLICE_SEGMENT_HEADER_EXTENSION_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING, "UNIFORM_SPACING"}
+	))
+
+);
+
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_slice_params, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nbit_size %u\n"
+		  "data_byte_offset %u\n"
+		  "num_entry_point_offsets %u\n"
+		  "nal_unit_type %u\n"
+		  "nuh_temporal_id_plus1 %u\n"
+		  "slice_type %u\n"
+		  "colour_plane_id %u\n"
+		  "slice_pic_order_cnt %d\n"
+		  "num_ref_idx_l0_active_minus1 %u\n"
+		  "num_ref_idx_l1_active_minus1 %u\n"
+		  "collocated_ref_idx %u\n"
+		  "five_minus_max_num_merge_cand %u\n"
+		  "slice_qp_delta %d\n"
+		  "slice_cb_qp_offset %d\n"
+		  "slice_cr_qp_offset %d\n"
+		  "slice_act_y_qp_offset %d\n"
+		  "slice_act_cb_qp_offset %d\n"
+		  "slice_act_cr_qp_offset %d\n"
+		  "slice_beta_offset_div2 %d\n"
+		  "slice_tc_offset_div2 %d\n"
+		  "pic_struct %u\n"
+		  "slice_segment_addr %u\n"
+		  "ref_idx_l0 %s\n"
+		  "ref_idx_l1 %s\n"
+		  "short_term_ref_pic_set_size %u\n"
+		  "long_term_ref_pic_set_size %u\n"
+		  "flags %s",
+		  __entry->s.bit_size,
+		  __entry->s.data_byte_offset,
+		  __entry->s.num_entry_point_offsets,
+		  __entry->s.nal_unit_type,
+		  __entry->s.nuh_temporal_id_plus1,
+		  __entry->s.slice_type,
+		  __entry->s.colour_plane_id,
+		  __entry->s.slice_pic_order_cnt,
+		  __entry->s.num_ref_idx_l0_active_minus1,
+		  __entry->s.num_ref_idx_l1_active_minus1,
+		  __entry->s.collocated_ref_idx,
+		  __entry->s.five_minus_max_num_merge_cand,
+		  __entry->s.slice_qp_delta,
+		  __entry->s.slice_cb_qp_offset,
+		  __entry->s.slice_cr_qp_offset,
+		  __entry->s.slice_act_y_qp_offset,
+		  __entry->s.slice_act_cb_qp_offset,
+		  __entry->s.slice_act_cr_qp_offset,
+		  __entry->s.slice_beta_offset_div2,
+		  __entry->s.slice_tc_offset_div2,
+		  __entry->s.pic_struct,
+		  __entry->s.slice_segment_addr,
+		  __print_array(__entry->s.ref_idx_l0,
+				ARRAY_SIZE(__entry->s.ref_idx_l0),
+				sizeof(__entry->s.ref_idx_l0[0])),
+		  __print_array(__entry->s.ref_idx_l1,
+				ARRAY_SIZE(__entry->s.ref_idx_l1),
+				sizeof(__entry->s.ref_idx_l1[0])),
+		  __entry->s.short_term_ref_pic_set_size,
+		  __entry->s.long_term_ref_pic_set_size,
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA, "SLICE_SAO_LUMA"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA, "SLICE_SAO_CHROMA"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED, "SLICE_TEMPORAL_MVP_ENABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO, "MVD_L1_ZERO"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT, "CABAC_INIT"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0, "COLLOCATED_FROM_L0"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV, "USE_INTEGER_MV"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, "SLICE_DEBLOCKING_FILTER_DISABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, "SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, "DEPENDENT_SLICE_SEGMENT"}
+
+	))
+);
+
+DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
+	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_pred_weight_table, p)),
+	TP_fast_assign(__entry->p = *p),
+	TP_printk("\ndelta_luma_weight_l0 %s\n"
+		  "luma_offset_l0 %s\n"
+		  "delta_chroma_weight_l0 {%s}\n"
+		  "chroma_offset_l0 {%s}\n"
+		  "delta_luma_weight_l1 %s\n"
+		  "luma_offset_l1 %s\n"
+		  "delta_chroma_weight_l1 {%s}\n"
+		  "chroma_offset_l1 {%s}\n"
+		  "luma_log2_weight_denom %d\n"
+		  "delta_chroma_log2_weight_denom %d\n",
+		  __print_array(__entry->p.delta_luma_weight_l0,
+				ARRAY_SIZE(__entry->p.delta_luma_weight_l0),
+				sizeof(__entry->p.delta_luma_weight_l0[0])),
+		  __print_array(__entry->p.luma_offset_l0,
+				ARRAY_SIZE(__entry->p.luma_offset_l0),
+				sizeof(__entry->p.luma_offset_l0[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.delta_chroma_weight_l0,
+				   sizeof(__entry->p.delta_chroma_weight_l0),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.chroma_offset_l0,
+				   sizeof(__entry->p.chroma_offset_l0),
+				   false),
+		  __print_array(__entry->p.delta_luma_weight_l1,
+				ARRAY_SIZE(__entry->p.delta_luma_weight_l1),
+				sizeof(__entry->p.delta_luma_weight_l1[0])),
+		  __print_array(__entry->p.luma_offset_l1,
+				ARRAY_SIZE(__entry->p.luma_offset_l1),
+				sizeof(__entry->p.luma_offset_l1[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.delta_chroma_weight_l1,
+				   sizeof(__entry->p.delta_chroma_weight_l1),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.chroma_offset_l1,
+				   sizeof(__entry->p.chroma_offset_l1),
+				   false),
+		__entry->p.luma_log2_weight_denom,
+		__entry->p.delta_chroma_log2_weight_denom
+
+	))
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_scaling_matrix, s)),
+	TP_fast_assign(__entry->s = *s),
+	TP_printk("\nscaling_list_4x4 {%s}\n"
+		  "scaling_list_8x8 {%s}\n"
+		  "scaling_list_16x16 {%s}\n"
+		  "scaling_list_32x32 {%s}\n"
+		  "scaling_list_dc_coef_16x16 %s\n"
+		  "scaling_list_dc_coef_32x32 %s\n",
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_4x4,
+				   sizeof(__entry->s.scaling_list_4x4),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_8x8,
+				   sizeof(__entry->s.scaling_list_8x8),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_16x16,
+				   sizeof(__entry->s.scaling_list_16x16),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->s.scaling_list_32x32,
+				   sizeof(__entry->s.scaling_list_32x32),
+				   false),
+		  __print_array(__entry->s.scaling_list_dc_coef_16x16,
+				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_16x16),
+				sizeof(__entry->s.scaling_list_dc_coef_16x16[0])),
+		  __print_array(__entry->s.scaling_list_dc_coef_32x32,
+				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_32x32),
+				sizeof(__entry->s.scaling_list_dc_coef_32x32[0]))
+	))
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
+	TP_ARGS(d),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_decode_params, d)),
+	TP_fast_assign(__entry->d = *d),
+	TP_printk("\npic_order_cnt_val %d\n"
+		  "short_term_ref_pic_set_size %u\n"
+		  "long_term_ref_pic_set_size %u\n"
+		  "num_active_dpb_entries %u\n"
+		  "num_poc_st_curr_before %u\n"
+		  "num_poc_st_curr_after %u\n"
+		  "num_poc_lt_curr %u\n"
+		  "poc_st_curr_before %s\n"
+		  "poc_st_curr_after %s\n"
+		  "poc_lt_curr %s\n"
+		  "flags %s",
+		  __entry->d.pic_order_cnt_val,
+		  __entry->d.short_term_ref_pic_set_size,
+		  __entry->d.long_term_ref_pic_set_size,
+		  __entry->d.num_active_dpb_entries,
+		  __entry->d.num_poc_st_curr_before,
+		  __entry->d.num_poc_st_curr_after,
+		  __entry->d.num_poc_lt_curr,
+		  __print_array(__entry->d.poc_st_curr_before,
+				ARRAY_SIZE(__entry->d.poc_st_curr_before),
+				sizeof(__entry->d.poc_st_curr_before[0])),
+		  __print_array(__entry->d.poc_st_curr_after,
+				ARRAY_SIZE(__entry->d.poc_st_curr_after),
+				sizeof(__entry->d.poc_st_curr_after[0])),
+		  __print_array(__entry->d.poc_lt_curr,
+				ARRAY_SIZE(__entry->d.poc_lt_curr),
+				sizeof(__entry->d.poc_lt_curr[0])),
+		  __print_flags(__entry->d.flags, "|",
+		  {V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC, "IRAP_PIC"},
+		  {V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
+		  {V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR, "NO_OUTPUT_OF_PRIOR"}
+	))
+);
+
+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),
+	TP_ARGS(e),
+	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_dpb_entry, e)),
+	TP_fast_assign(__entry->e = *e),
+	TP_printk("\ntimestamp %llu\n"
+		  "flags %s\n"
+		  "field_pic %u\n"
+		  "pic_order_cnt_val %d\n",
+		__entry->e.timestamp,
+		__print_flags(__entry->e.flags, "|",
+		{V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE, "LONG_TERM_REFERENCE"}
+		  ),
+		__entry->e.field_pic,
+		__entry->e.pic_order_cnt_val
+	))
+
+DEFINE_EVENT(v4l2_ctrl_hevc_sps_tmpl, v4l2_ctrl_hevc_sps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_pps_tmpl, v4l2_ctrl_hevc_pps,
+	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
+	TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_slice_params_tmpl, v4l2_ctrl_hevc_slice_params,
+	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_hevc_pred_weight_table_tmpl, v4l2_hevc_pred_weight_table,
+	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
+	TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_scaling_matrix_tmpl, v4l2_ctrl_hevc_scaling_matrix,
+	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
+	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
+	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)
+);
+
+/* MPEG2 controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
+	TP_ARGS(s),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_sequence, s)),
+	TP_fast_assign(__entry->s = *s;),
+	TP_printk("\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
+		  "profile_and_level_indication %u\nchroma_format %u\nflags %s\n",
+		  __entry->s.horizontal_size,
+		  __entry->s.vertical_size,
+		  __entry->s.vbv_buffer_size,
+		  __entry->s.profile_and_level_indication,
+		  __entry->s.chroma_format,
+		  __print_flags(__entry->s.flags, "|",
+		  {V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE, "PROGRESSIVE"})
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_picture, p)),
+	TP_fast_assign(__entry->p = *p;),
+	TP_printk("\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
+		  "picture_coding_type: %u\npicture_structure %u\nintra_dc_precision %u\n",
+		  __entry->p.backward_ref_ts,
+		  __entry->p.forward_ref_ts,
+		  __print_flags(__entry->p.flags, "|",
+		  {V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST, "TOP_FIELD_FIRST"},
+		  {V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT, "FRAME_PRED_DCT"},
+		  {V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV, "CONCEALMENT_MV"},
+		  {V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE, "Q_SCALE_TYPE"},
+		  {V4L2_MPEG2_PIC_FLAG_INTRA_VLC, "INTA_VLC"},
+		  {V4L2_MPEG2_PIC_FLAG_ALT_SCAN, "ALT_SCAN"},
+		  {V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST, "REPEAT_FIRST"},
+		  {V4L2_MPEG2_PIC_FLAG_PROGRESSIVE, "PROGRESSIVE"}),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.f_code,
+				   sizeof(__entry->p.f_code),
+				   false),
+		  __entry->p.picture_coding_type,
+		  __entry->p.picture_structure,
+		  __entry->p.intra_dc_precision
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
+	TP_ARGS(q),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_quantisation, q)),
+	TP_fast_assign(__entry->q = *q;),
+	TP_printk("\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
+		  "chroma_intra_quantiser_matrix %s\nchroma_non_intra_quantiser_matrix %s\n",
+		  __print_array(__entry->q.intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->q.intra_quantiser_matrix),
+				sizeof(__entry->q.intra_quantiser_matrix[0])),
+		  __print_array(__entry->q.non_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->q.non_intra_quantiser_matrix),
+				sizeof(__entry->q.non_intra_quantiser_matrix[0])),
+		  __print_array(__entry->q.chroma_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->q.chroma_intra_quantiser_matrix),
+				sizeof(__entry->q.chroma_intra_quantiser_matrix[0])),
+		  __print_array(__entry->q.chroma_non_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->q.chroma_non_intra_quantiser_matrix),
+				sizeof(__entry->q.chroma_non_intra_quantiser_matrix[0]))
+		  )
+)
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_seq_tmpl, v4l2_ctrl_mpeg2_sequence,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
+	TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_pic_tmpl, v4l2_ctrl_mpeg2_picture,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
+	TP_ARGS(p)
+);
+
+DEFINE_EVENT(v4l2_ctrl_mpeg2_quant_tmpl, v4l2_ctrl_mpeg2_quantisation,
+	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
+	TP_ARGS(q)
+);
+
+/* VP8 controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(f),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
+	TP_fast_assign(__entry->f = *f;),
+	TP_printk("\nentropy.coeff_probs {%s}\n"
+		  "entropy.y_mode_probs %s\n"
+		  "entropy.uv_mode_probs %s\n"
+		  "entropy.mv_probs {%s}",
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->f.entropy.coeff_probs,
+				   sizeof(__entry->f.entropy.coeff_probs),
+				   false),
+		  __print_array(__entry->f.entropy.y_mode_probs,
+				ARRAY_SIZE(__entry->f.entropy.y_mode_probs),
+				sizeof(__entry->f.entropy.y_mode_probs[0])),
+		  __print_array(__entry->f.entropy.uv_mode_probs,
+				ARRAY_SIZE(__entry->f.entropy.uv_mode_probs),
+				sizeof(__entry->f.entropy.uv_mode_probs[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->f.entropy.mv_probs,
+				   sizeof(__entry->f.entropy.mv_probs),
+				   false)
+		  )
+)
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(f),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
+	TP_fast_assign(__entry->f = *f;),
+	TP_printk("\nsegment.quant_update %s\n"
+		  "segment.lf_update %s\n"
+		  "segment.segment_probs %s\n"
+		  "segment.flags %s\n"
+		  "lf.ref_frm_delta %s\n"
+		  "lf.mb_mode_delta %s\n"
+		  "lf.sharpness_level %u\n"
+		  "lf.level %u\n"
+		  "lf.flags %s\n"
+		  "quant.y_ac_qi %u\n"
+		  "quant.y_dc_delta %d\n"
+		  "quant.y2_dc_delta %d\n"
+		  "quant.y2_ac_delta %d\n"
+		  "quant.uv_dc_delta %d\n"
+		  "quant.uv_ac_delta %d\n"
+		  "coder_state.range %u\n"
+		  "coder_state.value %u\n"
+		  "coder_state.bit_count %u\n"
+		  "width %u\n"
+		  "height %u\n"
+		  "horizontal_scale %u\n"
+		  "vertical_scale %u\n"
+		  "version %u\n"
+		  "prob_skip_false %u\n"
+		  "prob_intra %u\n"
+		  "prob_last %u\n"
+		  "prob_gf %u\n"
+		  "num_dct_parts %u\n"
+		  "first_part_size %u\n"
+		  "first_part_header_bits %u\n"
+		  "dct_part_sizes %s\n"
+		  "last_frame_ts %llu\n"
+		  "golden_frame_ts %llu\n"
+		  "alt_frame_ts %llu\n"
+		  "flags %s",
+		  __print_array(__entry->f.segment.quant_update,
+				ARRAY_SIZE(__entry->f.segment.quant_update),
+				sizeof(__entry->f.segment.quant_update[0])),
+		  __print_array(__entry->f.segment.lf_update,
+				ARRAY_SIZE(__entry->f.segment.lf_update),
+				sizeof(__entry->f.segment.lf_update[0])),
+		  __print_array(__entry->f.segment.segment_probs,
+				ARRAY_SIZE(__entry->f.segment.segment_probs),
+				sizeof(__entry->f.segment.segment_probs[0])),
+		  __print_flags(__entry->f.segment.flags, "|",
+		  {V4L2_VP8_SEGMENT_FLAG_ENABLED, "SEGMENT_ENABLED"},
+		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP, "SEGMENT_UPDATE_MAP"},
+		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA, "SEGMENT_UPDATE_FEATURE_DATA"},
+		  {V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE, "SEGMENT_DELTA_VALUE_MODE"}),
+		  __print_array(__entry->f.lf.ref_frm_delta,
+				ARRAY_SIZE(__entry->f.lf.ref_frm_delta),
+				sizeof(__entry->f.lf.ref_frm_delta[0])),
+		  __print_array(__entry->f.lf.mb_mode_delta,
+				ARRAY_SIZE(__entry->f.lf.mb_mode_delta),
+				sizeof(__entry->f.lf.mb_mode_delta[0])),
+		  __entry->f.lf.sharpness_level,
+		  __entry->f.lf.level,
+		  __print_flags(__entry->f.lf.flags, "|",
+		  {V4L2_VP8_LF_ADJ_ENABLE, "LF_ADJ_ENABLED"},
+		  {V4L2_VP8_LF_DELTA_UPDATE, "LF_DELTA_UPDATE"},
+		  {V4L2_VP8_LF_FILTER_TYPE_SIMPLE, "LF_FILTER_TYPE_SIMPLE"}),
+		  __entry->f.quant.y_ac_qi,
+		  __entry->f.quant.y_dc_delta,
+		  __entry->f.quant.y2_dc_delta,
+		  __entry->f.quant.y2_ac_delta,
+		  __entry->f.quant.uv_dc_delta,
+		  __entry->f.quant.uv_ac_delta,
+		  __entry->f.coder_state.range,
+		  __entry->f.coder_state.value,
+		  __entry->f.coder_state.bit_count,
+		  __entry->f.width,
+		  __entry->f.height,
+		  __entry->f.horizontal_scale,
+		  __entry->f.vertical_scale,
+		  __entry->f.version,
+		  __entry->f.prob_skip_false,
+		  __entry->f.prob_intra,
+		  __entry->f.prob_last,
+		  __entry->f.prob_gf,
+		  __entry->f.num_dct_parts,
+		  __entry->f.first_part_size,
+		  __entry->f.first_part_header_bits,
+		  __print_array(__entry->f.dct_part_sizes,
+				ARRAY_SIZE(__entry->f.dct_part_sizes),
+				sizeof(__entry->f.dct_part_sizes[0])),
+		  __entry->f.last_frame_ts,
+		  __entry->f.golden_frame_ts,
+		  __entry->f.alt_frame_ts,
+		  __print_flags(__entry->f.flags, "|",
+		  {V4L2_VP8_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
+		  {V4L2_VP8_FRAME_FLAG_EXPERIMENTAL, "EXPERIMENTAL"},
+		  {V4L2_VP8_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+		  {V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF, "MB_NO_SKIP_COEFF"},
+		  {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
+		  {V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"})
+		  )
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp8_frame_tmpl, v4l2_ctrl_vp8_frame,
+	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp8_entropy_tmpl, v4l2_ctrl_vp8_entropy,
+	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(f)
+);
+
+/* VP9 controls */
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
+	TP_ARGS(f),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_frame, f)),
+	TP_fast_assign(__entry->f = *f;),
+	TP_printk("\nlf.ref_deltas %s\n"
+		  "lf.mode_deltas %s\n"
+		  "lf.level %u\n"
+		  "lf.sharpness %u\n"
+		  "lf.flags %s\n"
+		  "quant.base_q_idx %u\n"
+		  "quant.delta_q_y_dc %d\n"
+		  "quant.delta_q_uv_dc %d\n"
+		  "quant.delta_q_uv_ac %d\n"
+		  "seg.feature_data {%s}\n"
+		  "seg.feature_enabled %s\n"
+		  "seg.tree_probs %s\n"
+		  "seg.pred_probs %s\n"
+		  "seg.flags %s\n"
+		  "flags %s\n"
+		  "compressed_header_size %u\n"
+		  "uncompressed_header_size %u\n"
+		  "frame_width_minus_1 %u\n"
+		  "frame_height_minus_1 %u\n"
+		  "render_width_minus_1 %u\n"
+		  "render_height_minus_1 %u\n"
+		  "last_frame_ts %llu\n"
+		  "golden_frame_ts %llu\n"
+		  "alt_frame_ts %llu\n"
+		  "ref_frame_sign_bias %s\n"
+		  "reset_frame_context %s\n"
+		  "frame_context_idx %u\n"
+		  "profile %u\n"
+		  "bit_depth %u\n"
+		  "interpolation_filter %s\n"
+		  "tile_cols_log2 %u\n"
+		  "tile_rows_log_2 %u\n"
+		  "reference_mode %s\n",
+		  __print_array(__entry->f.lf.ref_deltas,
+				ARRAY_SIZE(__entry->f.lf.ref_deltas),
+				sizeof(__entry->f.lf.ref_deltas[0])),
+		  __print_array(__entry->f.lf.mode_deltas,
+				ARRAY_SIZE(__entry->f.lf.mode_deltas),
+				sizeof(__entry->f.lf.mode_deltas[0])),
+		  __entry->f.lf.level,
+		  __entry->f.lf.sharpness,
+		  __print_flags(__entry->f.lf.flags, "|",
+		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
+		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"}),
+		  __entry->f.quant.base_q_idx,
+		  __entry->f.quant.delta_q_y_dc,
+		  __entry->f.quant.delta_q_uv_dc,
+		  __entry->f.quant.delta_q_uv_ac,
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->f.seg.feature_data,
+				   sizeof(__entry->f.seg.feature_data),
+				   false),
+		  __print_array(__entry->f.seg.feature_enabled,
+				ARRAY_SIZE(__entry->f.seg.feature_enabled),
+				sizeof(__entry->f.seg.feature_enabled[0])),
+		  __print_array(__entry->f.seg.tree_probs,
+				ARRAY_SIZE(__entry->f.seg.tree_probs),
+				sizeof(__entry->f.seg.tree_probs[0])),
+		  __print_array(__entry->f.seg.pred_probs,
+				ARRAY_SIZE(__entry->f.seg.pred_probs),
+				sizeof(__entry->f.seg.pred_probs[0])),
+		  __print_flags(__entry->f.seg.flags, "|",
+		  {V4L2_VP9_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
+		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
+		  {V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
+		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
+		  {V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE, "ABS_OR_DELTA_UPDATE"}),
+		  __print_flags(__entry->f.flags, "|",
+		  {V4L2_VP9_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
+		  {V4L2_VP9_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+		  {V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT, "ERROR_RESILIENT"},
+		  {V4L2_VP9_FRAME_FLAG_INTRA_ONLY, "INTRA_ONLY"},
+		  {V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV, "ALLOW_HIGH_PREC_MV"},
+		  {V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX, "REFRESH_FRAME_CTX"},
+		  {V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE, "PARALLEL_DEC_MODE"},
+		  {V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING, "X_SUBSAMPLING"},
+		  {V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING, "Y_SUBSAMPLING"},
+		  {V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING, "COLOR_RANGE_FULL_SWING"}),
+		  __entry->f.compressed_header_size,
+		  __entry->f.uncompressed_header_size,
+		  __entry->f.frame_width_minus_1,
+		  __entry->f.frame_height_minus_1,
+		  __entry->f.render_width_minus_1,
+		  __entry->f.render_height_minus_1,
+		  __entry->f.last_frame_ts,
+		  __entry->f.golden_frame_ts,
+		  __entry->f.alt_frame_ts,
+		  __print_symbolic(__entry->f.ref_frame_sign_bias,
+		  {V4L2_VP9_SIGN_BIAS_LAST, "SIGN_BIAS_LAST"},
+		  {V4L2_VP9_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
+		  {V4L2_VP9_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"}),
+		  __print_symbolic(__entry->f.reset_frame_context,
+		  {V4L2_VP9_RESET_FRAME_CTX_NONE, "RESET_FRAME_CTX_NONE"},
+		  {V4L2_VP9_RESET_FRAME_CTX_SPEC, "RESET_FRAME_CTX_SPEC"},
+		  {V4L2_VP9_RESET_FRAME_CTX_ALL, "RESET_FRAME_CTX_ALL"}),
+		  __entry->f.frame_context_idx,
+		  __entry->f.profile,
+		  __entry->f.bit_depth,
+		  __print_symbolic(__entry->f.interpolation_filter,
+		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP, "INTERP_FILTER_EIGHTTAP"},
+		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH, "INTERP_FILTER_EIGHTTAP_SMOOTH"},
+		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SHARP, "INTERP_FILTER_EIGHTTAP_SHARP"},
+		  {V4L2_VP9_INTERP_FILTER_BILINEAR, "INTERP_FILTER_BILINEAR"},
+		  {V4L2_VP9_INTERP_FILTER_SWITCHABLE, "INTERP_FILTER_SWITCHABLE"}),
+		  __entry->f.tile_cols_log2,
+		  __entry->f.tile_rows_log2,
+		  __print_symbolic(__entry->f.reference_mode,
+		  {V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, "REFERENCE_MODE_SINGLE_REFERENCE"},
+		  {V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE, "REFERENCE_MODE_COMPOUND_REFERENCE"},
+		  {V4L2_VP9_REFERENCE_MODE_SELECT, "REFERENCE_MODE_SELECT"}))
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(h),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
+	TP_fast_assign(__entry->h = *h;),
+	TP_printk("\ntx_mode %s\n"
+		  "tx8 {%s}\n"
+		  "tx16 {%s}\n"
+		  "tx32 {%s}\n"
+		  "skip %s\n"
+		  "inter_mode {%s}\n"
+		  "interp_filter {%s}\n"
+		  "is_inter %s\n"
+		  "comp_mode %s\n"
+		  "single_ref {%s}\n"
+		  "comp_ref %s\n"
+		  "y_mode {%s}\n"
+		  "uv_mode {%s}\n"
+		  "partition {%s}\n",
+		  __print_symbolic(__entry->h.tx_mode,
+		  {V4L2_VP9_TX_MODE_ONLY_4X4, "TX_MODE_ONLY_4X4"},
+		  {V4L2_VP9_TX_MODE_ALLOW_8X8, "TX_MODE_ALLOW_8X8"},
+		  {V4L2_VP9_TX_MODE_ALLOW_16X16, "TX_MODE_ALLOW_16X16"},
+		  {V4L2_VP9_TX_MODE_ALLOW_32X32, "TX_MODE_ALLOW_32X32"},
+		  {V4L2_VP9_TX_MODE_SELECT, "TX_MODE_SELECT"}),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.tx8,
+				   sizeof(__entry->h.tx8),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.tx16,
+				   sizeof(__entry->h.tx16),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.tx32,
+				   sizeof(__entry->h.tx32),
+				   false),
+		  __print_array(__entry->h.skip,
+				ARRAY_SIZE(__entry->h.skip),
+				sizeof(__entry->h.skip[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.inter_mode,
+				   sizeof(__entry->h.inter_mode),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.interp_filter,
+				   sizeof(__entry->h.interp_filter),
+				   false),
+		  __print_array(__entry->h.is_inter,
+				ARRAY_SIZE(__entry->h.is_inter),
+				sizeof(__entry->h.is_inter[0])),
+		  __print_array(__entry->h.comp_mode,
+				ARRAY_SIZE(__entry->h.comp_mode),
+				sizeof(__entry->h.comp_mode[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.single_ref,
+				   sizeof(__entry->h.single_ref),
+				   false),
+		  __print_array(__entry->h.comp_ref,
+				ARRAY_SIZE(__entry->h.comp_ref),
+				sizeof(__entry->h.comp_ref[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.y_mode,
+				   sizeof(__entry->h.y_mode),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.uv_mode,
+				   sizeof(__entry->h.uv_mode),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.partition,
+				   sizeof(__entry->h.partition),
+				   false)
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
+	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(h),
+	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
+	TP_fast_assign(__entry->h = *h;),
+	TP_printk("\n coef {%s}",
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->h.coef,
+				   sizeof(__entry->h.coef),
+				   false)
+	)
+);
+
+DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
+	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
+	TP_ARGS(p),
+	TP_STRUCT__entry(__field_struct(struct v4l2_vp9_mv_probs, p)),
+	TP_fast_assign(__entry->p = *p;),
+	TP_printk("\n joint %s\n"
+		  "sign %s\n"
+		  "classes {%s}\n"
+		  "class0_bit %s\n"
+		  "bits {%s}\n"
+		  "class0_fr {%s}\n"
+		  "fr {%s}\n"
+		  "class0_hp %s\n"
+		  "hp %s\n",
+		  __print_array(__entry->p.joint,
+				ARRAY_SIZE(__entry->p.joint),
+				sizeof(__entry->p.joint[0])),
+		  __print_array(__entry->p.sign,
+				ARRAY_SIZE(__entry->p.sign),
+				sizeof(__entry->p.sign[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.classes,
+				   sizeof(__entry->p.classes),
+				   false),
+		  __print_array(__entry->p.class0_bit,
+				ARRAY_SIZE(__entry->p.class0_bit),
+				sizeof(__entry->p.class0_bit[0])),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.bits,
+				   sizeof(__entry->p.bits),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.class0_fr,
+				   sizeof(__entry->p.class0_fr),
+				   false),
+		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
+				   __entry->p.fr,
+				   sizeof(__entry->p.fr),
+				   false),
+		  __print_array(__entry->p.class0_hp,
+				ARRAY_SIZE(__entry->p.class0_hp),
+				sizeof(__entry->p.class0_hp[0])),
+		  __print_array(__entry->p.hp,
+				ARRAY_SIZE(__entry->p.hp),
+				sizeof(__entry->p.hp[0]))
+	)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_frame_tmpl, v4l2_ctrl_vp9_frame,
+	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
+	TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_compressed_hdr_tmpl, v4l2_ctrl_vp9_compressed_hdr,
+	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(h)
+);
+
+DEFINE_EVENT(v4l2_ctrl_vp9_compressed_coef_tmpl, v4l2_ctrl_vp9_compressed_coeff,
+	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(h)
+);
+
+
+DEFINE_EVENT(v4l2_vp9_mv_probs_tmpl, v4l2_vp9_mv_probs,
+	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
+	TP_ARGS(p)
+);
+
+#endif /* if !defined(_TRACE_V4L2_CONTROLS_H_) || defined(TRACE_HEADER_MULTI_READ) */
+
+#include <trace/define_trace.h>

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:32 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:32 -0400
Subject: [PATCH v2 2/9] media: Map each struct field to its own trace field
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-2-9756edf72ac1@collabora.com>

The trace events, moved from the visl driver, are simply using the
passed struct pointer to print the event in the trace.

This approach doesn't allow userspace to filter on fields, but also only
exposes the value of the pointer when using libtraceevent, which can't
be used to retrieve the control fields, forcing userspace to parse the
trace output.

To avoid that, list all fields from each passed struct in the trace.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 include/trace/events/v4l2_controls.h | 2171 ++++++++++++++++++++++++----------
 1 file changed, 1522 insertions(+), 649 deletions(-)

diff --git a/include/trace/events/v4l2_controls.h b/include/trace/events/v4l2_controls.h
index 9c74309b31ef..3a9bc75752bf 100644
--- a/include/trace/events/v4l2_controls.h
+++ b/include/trace/events/v4l2_controls.h
@@ -8,15 +8,34 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM v4l2_controls
 
+/* V4L2 controls tracing events.
+ *
+ * These events are used to trace each V4L2 control when they are set by userspace.
+ * They can be identified by the name of the event. All control fields are copied in a TP_STRUCT
+ * field so that they can be filtered separately in userspace.
+ *
+ * Currently only the codec controls are supported.
+ */
+
 /* AV1 controls */
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_sequence, s)),
-	TP_fast_assign(__entry->s = *s;),
+	TP_STRUCT__entry(__field(__u32, flags)
+			 __field(__u8, seq_profile)
+			 __field(__u8, order_hint_bits)
+			 __field(__u8, bit_depth)
+			 __field(__u16, max_frame_width_minus_1)
+			 __field(__u16, max_frame_height_minus_1)),
+	TP_fast_assign(__entry->flags = s->flags;
+		       __entry->seq_profile = s->seq_profile;
+		       __entry->order_hint_bits = s->order_hint_bits;
+		       __entry->bit_depth = s->bit_depth;
+		       __entry->max_frame_width_minus_1 = s->max_frame_width_minus_1;
+		       __entry->max_frame_height_minus_1 = s->max_frame_height_minus_1;),
 	TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
 		  "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n",
-		  __print_flags(__entry->s.flags, "|",
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"},
 		  {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"},
 		  {V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA, "ENABLE_FILTER_INTRA"},
@@ -37,32 +56,176 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
 		  {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y, "SUBSAMPLING_Y"},
 		  {V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT, "FILM_GRAIN_PARAMS_PRESENT"},
 		  {V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q, "SEPARATE_UV_DELTA_Q"}),
-		  __entry->s.seq_profile,
-		  __entry->s.order_hint_bits,
-		  __entry->s.bit_depth,
-		  __entry->s.max_frame_width_minus_1,
-		  __entry->s.max_frame_height_minus_1
+		  __entry->seq_profile,
+		  __entry->order_hint_bits,
+		  __entry->bit_depth,
+		  __entry->max_frame_width_minus_1,
+		  __entry->max_frame_height_minus_1
 	)
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
 	TP_ARGS(t),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_tile_group_entry, t)),
-	TP_fast_assign(__entry->t = *t;),
+	TP_STRUCT__entry(__field(__u32, tile_offset)
+			 __field(__u32, tile_size)
+			 __field(__u32, tile_row)
+			 __field(__u32, tile_col)),
+	TP_fast_assign(__entry->tile_offset = t->tile_offset;
+		       __entry->tile_size = t->tile_size;
+		       __entry->tile_row = t->tile_row;
+		       __entry->tile_col = t->tile_col;),
 	TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
-		  __entry->t.tile_offset,
-		  __entry->t.tile_size,
-		  __entry->t.tile_row,
-		  __entry->t.tile_col
+		  __entry->tile_offset,
+		  __entry->tile_size,
+		  __entry->tile_row,
+		  __entry->tile_col
 	)
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
 	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
+	TP_STRUCT__entry(__field(u8, tile_info_flags)
+			 __field(u8, tile_info_context_update_tile_id)
+			 __field(u8, tile_info_tile_cols)
+			 __field(u8, tile_info_tile_rows)
+			 __array(u32, tile_info_mi_col_starts, V4L2_AV1_MAX_TILE_COLS + 1)
+			 __array(u32, tile_info_mi_row_starts, V4L2_AV1_MAX_TILE_ROWS + 1)
+			 __array(u32, tile_info_width_in_sbs_minus_1, V4L2_AV1_MAX_TILE_COLS)
+			 __array(u32, tile_info_height_in_sbs_minus_1, V4L2_AV1_MAX_TILE_ROWS)
+			 __field(u8, tile_info_tile_size_bytes)
+			 __field(u8, quantization_flags)
+			 __field(u8, quantization_base_q_idx)
+			 __field(s8, quantization_delta_q_y_dc)
+			 __field(s8, quantization_delta_q_u_dc)
+			 __field(s8, quantization_delta_q_u_ac)
+			 __field(s8, quantization_delta_q_v_dc)
+			 __field(s8, quantization_delta_q_v_ac)
+			 __field(u8, quantization_qm_y)
+			 __field(u8, quantization_qm_u)
+			 __field(u8, quantization_qm_v)
+			 __field(u8, quantization_delta_q_res)
+			 __field(u8, superres_denom)
+			 __field(u8, segmentation_flags)
+			 __field(u8, segmentation_last_active_seg_id)
+			 __array(u8, segmentation_feature_enabled, V4L2_AV1_MAX_SEGMENTS)
+			 __field(u8, loop_filter_flags)
+			 __array(u8, loop_filter_level, 4)
+			 __field(u8, loop_filter_sharpness)
+			 __array(s8, loop_filter_ref_deltas, V4L2_AV1_TOTAL_REFS_PER_FRAME)
+			 __array(s8, loop_filter_mode_deltas, 2)
+			 __field(u8, loop_filter_delta_lf_res)
+			 __field(u8, cdef_damping_minus_3)
+			 __field(u8, cdef_bits)
+			 __array(u8, cdef_y_pri_strength, V4L2_AV1_CDEF_MAX)
+			 __array(u8, cdef_y_sec_strength, V4L2_AV1_CDEF_MAX)
+			 __array(u8, cdef_uv_pri_strength, V4L2_AV1_CDEF_MAX)
+			 __array(u8, cdef_uv_sec_strength, V4L2_AV1_CDEF_MAX)
+			 __array(u8, skip_mode_frame, 2)
+			 __field(u8, primary_ref_frame)
+			 __field(u8, loop_restoration_flags)
+			 __field(u8, loop_restoration_lr_unit_shift)
+			 __field(u8, loop_restoration_lr_uv_shift)
+			 __array(int,
+				 loop_restoration_frame_restoration_type, V4L2_AV1_NUM_PLANES_MAX)
+			 __array(u32,
+				 loop_restoration_loop_restoration_size, V4L2_AV1_MAX_NUM_PLANES)
+			 __field(u32, flags)
+			 __field(u32, order_hint)
+			 __field(u32, upscaled_width)
+			 __field(u32, frame_width_minus_1)
+			 __field(u32, frame_height_minus_1)
+			 __field(u16, render_width_minus_1)
+			 __field(u16, render_height_minus_1)
+			 __field(u32, current_frame_id)
+			 __array(u32, buffer_removal_time, V4L2_AV1_MAX_OPERATING_POINTS)
+			 __array(u32, order_hints, V4L2_AV1_TOTAL_REFS_PER_FRAME)
+			 __array(u64, reference_frame_ts, V4L2_AV1_TOTAL_REFS_PER_FRAME)
+			 __array(s8, ref_frame_idx, V4L2_AV1_REFS_PER_FRAME)
+			 __field(u8, refresh_frame_flags)),
+	TP_fast_assign(__entry->tile_info_flags = f->tile_info.flags;
+		       __entry->tile_info_context_update_tile_id =
+				f->tile_info.context_update_tile_id;
+		       __entry->tile_info_tile_cols = f->tile_info.tile_cols;
+		       __entry->tile_info_tile_rows = f->tile_info.tile_rows;
+		       memcpy(__entry->tile_info_mi_col_starts, f->tile_info.mi_col_starts,
+			      sizeof(__entry->tile_info_mi_col_starts));
+		       memcpy(__entry->tile_info_mi_row_starts, f->tile_info.mi_row_starts,
+			      sizeof(__entry->tile_info_mi_row_starts));
+		       memcpy(__entry->tile_info_width_in_sbs_minus_1,
+			      f->tile_info.width_in_sbs_minus_1,
+			      sizeof(__entry->tile_info_width_in_sbs_minus_1));
+		       memcpy(__entry->tile_info_height_in_sbs_minus_1,
+			      f->tile_info.height_in_sbs_minus_1,
+			      sizeof(__entry->tile_info_height_in_sbs_minus_1));
+		       __entry->tile_info_tile_size_bytes = f->tile_info.tile_size_bytes;
+		       __entry->quantization_flags = f->quantization.flags;
+		       __entry->quantization_base_q_idx = f->quantization.base_q_idx;
+		       __entry->quantization_delta_q_y_dc = f->quantization.delta_q_y_dc;
+		       __entry->quantization_delta_q_u_dc = f->quantization.delta_q_u_dc;
+		       __entry->quantization_delta_q_u_ac = f->quantization.delta_q_u_ac;
+		       __entry->quantization_delta_q_v_dc = f->quantization.delta_q_v_dc;
+		       __entry->quantization_delta_q_v_ac = f->quantization.delta_q_v_ac;
+		       __entry->quantization_qm_y = f->quantization.qm_y;
+		       __entry->quantization_qm_u = f->quantization.qm_u;
+		       __entry->quantization_qm_v = f->quantization.qm_v;
+		       __entry->quantization_delta_q_res = f->quantization.delta_q_res;
+		       __entry->superres_denom = f->superres_denom;
+		       __entry->segmentation_flags = f->segmentation.flags;
+		       __entry->segmentation_last_active_seg_id =
+				f->segmentation.last_active_seg_id;
+		       memcpy(__entry->segmentation_feature_enabled,
+			      f->segmentation.feature_enabled,
+			      sizeof(__entry->segmentation_feature_enabled));
+		       __entry->loop_filter_flags = f->loop_filter.flags;
+		       memcpy(__entry->loop_filter_level, f->loop_filter.level,
+			      sizeof(__entry->loop_filter_level));
+		       __entry->loop_filter_sharpness = f->loop_filter.sharpness;
+		       memcpy(__entry->loop_filter_ref_deltas, f->loop_filter.ref_deltas,
+			      sizeof(__entry->loop_filter_ref_deltas));
+		       memcpy(__entry->loop_filter_mode_deltas, f->loop_filter.mode_deltas,
+			      sizeof(__entry->loop_filter_mode_deltas));
+		       __entry->loop_filter_delta_lf_res = f->loop_filter.delta_lf_res;
+		       __entry->cdef_damping_minus_3 = f->cdef.damping_minus_3;
+		       __entry->cdef_bits = f->cdef.bits;
+		       memcpy(__entry->cdef_y_pri_strength, f->cdef.y_pri_strength,
+			      sizeof(__entry->cdef_y_pri_strength));
+		       memcpy(__entry->cdef_y_sec_strength, f->cdef.y_sec_strength,
+			      sizeof(__entry->cdef_y_sec_strength));
+		       memcpy(__entry->cdef_uv_pri_strength, f->cdef.uv_pri_strength,
+			      sizeof(__entry->cdef_uv_pri_strength));
+		       memcpy(__entry->cdef_uv_sec_strength, f->cdef.uv_sec_strength,
+			      sizeof(__entry->cdef_uv_sec_strength));
+		       memcpy(__entry->skip_mode_frame, f->skip_mode_frame,
+			      sizeof(__entry->skip_mode_frame));
+		       __entry->primary_ref_frame = f->primary_ref_frame;
+		       __entry->loop_restoration_flags = f->loop_restoration.flags;
+		       __entry->loop_restoration_lr_unit_shift = f->loop_restoration.lr_unit_shift;
+		       __entry->loop_restoration_lr_uv_shift = f->loop_restoration.lr_uv_shift;
+		       memcpy(__entry->loop_restoration_frame_restoration_type,
+			      f->loop_restoration.frame_restoration_type,
+			      sizeof(__entry->loop_restoration_frame_restoration_type));
+		       memcpy(__entry->loop_restoration_loop_restoration_size,
+			      f->loop_restoration.loop_restoration_size,
+			      sizeof(__entry->loop_restoration_loop_restoration_size));
+		       __entry->flags = f->flags;
+		       __entry->order_hint = f->order_hint;
+		       __entry->upscaled_width = f->upscaled_width;
+		       __entry->frame_width_minus_1 = f->frame_width_minus_1;
+		       __entry->frame_height_minus_1 = f->frame_height_minus_1;
+		       __entry->render_width_minus_1 = f->render_width_minus_1;
+		       __entry->render_height_minus_1 = f->render_height_minus_1;
+		       __entry->current_frame_id = f->current_frame_id;
+		       memcpy(__entry->buffer_removal_time, f->buffer_removal_time,
+			      sizeof(__entry->buffer_removal_time));
+		       memcpy(__entry->order_hints, f->order_hints,
+			      sizeof(__entry->order_hints));
+		       memcpy(__entry->reference_frame_ts, f->reference_frame_ts,
+			      sizeof(__entry->reference_frame_ts));
+		       memcpy(__entry->ref_frame_idx, f->ref_frame_idx,
+			      sizeof(__entry->ref_frame_idx));
+		       __entry->refresh_frame_flags = f->refresh_frame_flags;),
 	TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
 		  "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n"
 		  "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n"
@@ -87,95 +250,95 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 		  "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n"
 		  "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n"
 		  "ref_frame_idx: %s\nrefresh_frame_flags: %u\n",
-		  __print_flags(__entry->f.tile_info.flags, "|",
+		  __print_flags(__entry->tile_info_flags, "|",
 		  {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}),
-		  __entry->f.tile_info.context_update_tile_id,
-		  __entry->f.tile_info.tile_cols,
-		  __entry->f.tile_info.tile_rows,
-		  __print_array(__entry->f.tile_info.mi_col_starts,
-				ARRAY_SIZE(__entry->f.tile_info.mi_col_starts),
-				sizeof(__entry->f.tile_info.mi_col_starts[0])),
-		  __print_array(__entry->f.tile_info.mi_row_starts,
-				ARRAY_SIZE(__entry->f.tile_info.mi_row_starts),
-				sizeof(__entry->f.tile_info.mi_row_starts[0])),
-		  __print_array(__entry->f.tile_info.width_in_sbs_minus_1,
-				ARRAY_SIZE(__entry->f.tile_info.width_in_sbs_minus_1),
-				sizeof(__entry->f.tile_info.width_in_sbs_minus_1[0])),
-		  __print_array(__entry->f.tile_info.height_in_sbs_minus_1,
-				ARRAY_SIZE(__entry->f.tile_info.height_in_sbs_minus_1),
-				sizeof(__entry->f.tile_info.height_in_sbs_minus_1[0])),
-		  __entry->f.tile_info.tile_size_bytes,
-		  __print_flags(__entry->f.quantization.flags, "|",
+		  __entry->tile_info_context_update_tile_id,
+		  __entry->tile_info_tile_cols,
+		  __entry->tile_info_tile_rows,
+		  __print_array(__entry->tile_info_mi_col_starts,
+				ARRAY_SIZE(__entry->tile_info_mi_col_starts),
+				sizeof(__entry->tile_info_mi_col_starts[0])),
+		  __print_array(__entry->tile_info_mi_row_starts,
+				ARRAY_SIZE(__entry->tile_info_mi_row_starts),
+				sizeof(__entry->tile_info_mi_row_starts[0])),
+		  __print_array(__entry->tile_info_width_in_sbs_minus_1,
+				ARRAY_SIZE(__entry->tile_info_width_in_sbs_minus_1),
+				sizeof(__entry->tile_info_width_in_sbs_minus_1[0])),
+		  __print_array(__entry->tile_info_height_in_sbs_minus_1,
+				ARRAY_SIZE(__entry->tile_info_height_in_sbs_minus_1),
+				sizeof(__entry->tile_info_height_in_sbs_minus_1[0])),
+		  __entry->tile_info_tile_size_bytes,
+		  __print_flags(__entry->quantization_flags, "|",
 		  {V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA, "DIFF_UV_DELTA"},
 		  {V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX, "USING_QMATRIX"},
 		  {V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT, "DELTA_Q_PRESENT"}),
-		  __entry->f.quantization.base_q_idx,
-		  __entry->f.quantization.delta_q_y_dc,
-		  __entry->f.quantization.delta_q_u_dc,
-		  __entry->f.quantization.delta_q_u_ac,
-		  __entry->f.quantization.delta_q_v_dc,
-		  __entry->f.quantization.delta_q_v_ac,
-		  __entry->f.quantization.qm_y,
-		  __entry->f.quantization.qm_u,
-		  __entry->f.quantization.qm_v,
-		  __entry->f.quantization.delta_q_res,
-		  __entry->f.superres_denom,
-		  __print_flags(__entry->f.segmentation.flags, "|",
+		  __entry->quantization_base_q_idx,
+		  __entry->quantization_delta_q_y_dc,
+		  __entry->quantization_delta_q_u_dc,
+		  __entry->quantization_delta_q_u_ac,
+		  __entry->quantization_delta_q_v_dc,
+		  __entry->quantization_delta_q_v_ac,
+		  __entry->quantization_qm_y,
+		  __entry->quantization_qm_u,
+		  __entry->quantization_qm_v,
+		  __entry->quantization_delta_q_res,
+		  __entry->superres_denom,
+		  __print_flags(__entry->segmentation_flags, "|",
 		  {V4L2_AV1_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
 		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
 		  {V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
 		  {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
 		  {V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP, "SEG_ID_PRE_SKIP"}),
-		  __entry->f.segmentation.last_active_seg_id,
-		  __print_array(__entry->f.segmentation.feature_enabled,
-				ARRAY_SIZE(__entry->f.segmentation.feature_enabled),
-				sizeof(__entry->f.segmentation.feature_enabled[0])),
-		  __print_flags(__entry->f.loop_filter.flags, "|",
+		  __entry->segmentation_last_active_seg_id,
+		  __print_array(__entry->segmentation_feature_enabled,
+				ARRAY_SIZE(__entry->segmentation_feature_enabled),
+				sizeof(__entry->segmentation_feature_enabled[0])),
+		  __print_flags(__entry->loop_filter_flags, "|",
 		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
 		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"},
 		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT, "DELTA_LF_PRESENT"},
 		  {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI, "DELTA_LF_MULTI"}),
-		  __print_array(__entry->f.loop_filter.level,
-				ARRAY_SIZE(__entry->f.loop_filter.level),
-				sizeof(__entry->f.loop_filter.level[0])),
-		  __entry->f.loop_filter.sharpness,
-		  __print_array(__entry->f.loop_filter.ref_deltas,
-				ARRAY_SIZE(__entry->f.loop_filter.ref_deltas),
-				sizeof(__entry->f.loop_filter.ref_deltas[0])),
-		  __print_array(__entry->f.loop_filter.mode_deltas,
-				ARRAY_SIZE(__entry->f.loop_filter.mode_deltas),
-				sizeof(__entry->f.loop_filter.mode_deltas[0])),
-		  __entry->f.loop_filter.delta_lf_res,
-		  __entry->f.cdef.damping_minus_3,
-		  __entry->f.cdef.bits,
-		  __print_array(__entry->f.cdef.y_pri_strength,
-				ARRAY_SIZE(__entry->f.cdef.y_pri_strength),
-				sizeof(__entry->f.cdef.y_pri_strength[0])),
-		  __print_array(__entry->f.cdef.y_sec_strength,
-				ARRAY_SIZE(__entry->f.cdef.y_sec_strength),
-				sizeof(__entry->f.cdef.y_sec_strength[0])),
-		  __print_array(__entry->f.cdef.uv_pri_strength,
-				ARRAY_SIZE(__entry->f.cdef.uv_pri_strength),
-				sizeof(__entry->f.cdef.uv_pri_strength[0])),
-		  __print_array(__entry->f.cdef.uv_sec_strength,
-				ARRAY_SIZE(__entry->f.cdef.uv_sec_strength),
-				sizeof(__entry->f.cdef.uv_sec_strength[0])),
-		  __print_array(__entry->f.skip_mode_frame,
-				ARRAY_SIZE(__entry->f.skip_mode_frame),
-				sizeof(__entry->f.skip_mode_frame[0])),
-		  __entry->f.primary_ref_frame,
-		  __print_flags(__entry->f.loop_restoration.flags, "|",
+		  __print_array(__entry->loop_filter_level,
+				ARRAY_SIZE(__entry->loop_filter_level),
+				sizeof(__entry->loop_filter_level[0])),
+		  __entry->loop_filter_sharpness,
+		  __print_array(__entry->loop_filter_ref_deltas,
+				ARRAY_SIZE(__entry->loop_filter_ref_deltas),
+				sizeof(__entry->loop_filter_ref_deltas[0])),
+		  __print_array(__entry->loop_filter_mode_deltas,
+				ARRAY_SIZE(__entry->loop_filter_mode_deltas),
+				sizeof(__entry->loop_filter_mode_deltas[0])),
+		  __entry->loop_filter_delta_lf_res,
+		  __entry->cdef_damping_minus_3,
+		  __entry->cdef_bits,
+		  __print_array(__entry->cdef_y_pri_strength,
+				ARRAY_SIZE(__entry->cdef_y_pri_strength),
+				sizeof(__entry->cdef_y_pri_strength[0])),
+		  __print_array(__entry->cdef_y_sec_strength,
+				ARRAY_SIZE(__entry->cdef_y_sec_strength),
+				sizeof(__entry->cdef_y_sec_strength[0])),
+		  __print_array(__entry->cdef_uv_pri_strength,
+				ARRAY_SIZE(__entry->cdef_uv_pri_strength),
+				sizeof(__entry->cdef_uv_pri_strength[0])),
+		  __print_array(__entry->cdef_uv_sec_strength,
+				ARRAY_SIZE(__entry->cdef_uv_sec_strength),
+				sizeof(__entry->cdef_uv_sec_strength[0])),
+		  __print_array(__entry->skip_mode_frame,
+				ARRAY_SIZE(__entry->skip_mode_frame),
+				sizeof(__entry->skip_mode_frame[0])),
+		  __entry->primary_ref_frame,
+		  __print_flags(__entry->loop_restoration_flags, "|",
 		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR, "USES_LR"},
 		  {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR, "USES_CHROMA_LR"}),
-		  __entry->f.loop_restoration.lr_unit_shift,
-		  __entry->f.loop_restoration.lr_uv_shift,
-		  __print_array(__entry->f.loop_restoration.frame_restoration_type,
-				ARRAY_SIZE(__entry->f.loop_restoration.frame_restoration_type),
-				sizeof(__entry->f.loop_restoration.frame_restoration_type[0])),
-		  __print_array(__entry->f.loop_restoration.loop_restoration_size,
-				ARRAY_SIZE(__entry->f.loop_restoration.loop_restoration_size),
-				sizeof(__entry->f.loop_restoration.loop_restoration_size[0])),
-		  __print_flags(__entry->f.flags, "|",
+		  __entry->loop_restoration_lr_unit_shift,
+		  __entry->loop_restoration_lr_uv_shift,
+		  __print_array(__entry->loop_restoration_frame_restoration_type,
+				ARRAY_SIZE(__entry->loop_restoration_frame_restoration_type),
+				sizeof(__entry->loop_restoration_frame_restoration_type[0])),
+		  __print_array(__entry->loop_restoration_loop_restoration_size,
+				ARRAY_SIZE(__entry->loop_restoration_loop_restoration_size),
+				sizeof(__entry->loop_restoration_loop_restoration_size[0])),
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_AV1_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
 		  {V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME, "SHOWABLE_FRAME"},
 		  {V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE, "ERROR_RESILIENT_MODE"},
@@ -197,26 +360,26 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 		  {V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE, "FRAME_SIZE_OVERRIDE"},
 		  {V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT, "BUFFER_REMOVAL_TIME_PRESENT"},
 		  {V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING, "FRAME_REFS_SHORT_SIGNALING"}),
-		  __entry->f.order_hint,
-		  __entry->f.upscaled_width,
-		  __entry->f.frame_width_minus_1,
-		  __entry->f.frame_height_minus_1,
-		  __entry->f.render_width_minus_1,
-		  __entry->f.render_height_minus_1,
-		  __entry->f.current_frame_id,
-		  __print_array(__entry->f.buffer_removal_time,
-				ARRAY_SIZE(__entry->f.buffer_removal_time),
-				sizeof(__entry->f.buffer_removal_time[0])),
-		  __print_array(__entry->f.order_hints,
-				ARRAY_SIZE(__entry->f.order_hints),
-				sizeof(__entry->f.order_hints[0])),
-		  __print_array(__entry->f.reference_frame_ts,
-				ARRAY_SIZE(__entry->f.reference_frame_ts),
-				sizeof(__entry->f.reference_frame_ts[0])),
-		  __print_array(__entry->f.ref_frame_idx,
-				ARRAY_SIZE(__entry->f.ref_frame_idx),
-				sizeof(__entry->f.ref_frame_idx[0])),
-		  __entry->f.refresh_frame_flags
+		  __entry->order_hint,
+		  __entry->upscaled_width,
+		  __entry->frame_width_minus_1,
+		  __entry->frame_height_minus_1,
+		  __entry->render_width_minus_1,
+		  __entry->render_height_minus_1,
+		  __entry->current_frame_id,
+		  __print_array(__entry->buffer_removal_time,
+				ARRAY_SIZE(__entry->buffer_removal_time),
+				sizeof(__entry->buffer_removal_time[0])),
+		  __print_array(__entry->order_hints,
+				ARRAY_SIZE(__entry->order_hints),
+				sizeof(__entry->order_hints[0])),
+		  __print_array(__entry->reference_frame_ts,
+				ARRAY_SIZE(__entry->reference_frame_ts),
+				sizeof(__entry->reference_frame_ts[0])),
+		  __print_array(__entry->ref_frame_idx,
+				ARRAY_SIZE(__entry->ref_frame_idx),
+				sizeof(__entry->ref_frame_idx[0])),
+		  __entry->refresh_frame_flags
 	)
 );
 
@@ -224,8 +387,65 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
 	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_film_grain, f)),
-	TP_fast_assign(__entry->f = *f;),
+	TP_STRUCT__entry(__field(__u8, flags)
+			 __field(__u8, cr_mult)
+			 __field(__u16, grain_seed)
+			 __field(__u8, film_grain_params_ref_idx)
+			 __field(__u8, num_y_points)
+			 __array(__u8, point_y_value, V4L2_AV1_MAX_NUM_Y_POINTS)
+			 __array(__u8, point_y_scaling, V4L2_AV1_MAX_NUM_Y_POINTS)
+			 __field(__u8, num_cb_points)
+			 __array(__u8, point_cb_value, V4L2_AV1_MAX_NUM_CB_POINTS)
+			 __array(__u8, point_cb_scaling, V4L2_AV1_MAX_NUM_CB_POINTS)
+			 __field(__u8, num_cr_points)
+			 __array(__u8, point_cr_value, V4L2_AV1_MAX_NUM_CR_POINTS)
+			 __array(__u8, point_cr_scaling, V4L2_AV1_MAX_NUM_CR_POINTS)
+			 __field(__u8, grain_scaling_minus_8)
+			 __field(__u8, ar_coeff_lag)
+			 __array(__u8, ar_coeffs_y_plus_128, V4L2_AV1_AR_COEFFS_SIZE)
+			 __array(__u8, ar_coeffs_cb_plus_128, V4L2_AV1_AR_COEFFS_SIZE)
+			 __array(__u8, ar_coeffs_cr_plus_128, V4L2_AV1_AR_COEFFS_SIZE)
+			 __field(__u8, ar_coeff_shift_minus_6)
+			 __field(__u8, grain_scale_shift)
+			 __field(__u8, cb_mult)
+			 __field(__u8, cb_luma_mult)
+			 __field(__u8, cr_luma_mult)
+			 __field(__u16, cb_offset)
+			 __field(__u16, cr_offset)),
+	TP_fast_assign(__entry->flags = f->flags;
+		       __entry->cr_mult = f->cr_mult;
+		       __entry->grain_seed = f->grain_seed;
+		       __entry->film_grain_params_ref_idx = f->film_grain_params_ref_idx;
+		       __entry->num_y_points = f->num_y_points;
+		       memcpy(__entry->point_y_value, f->point_y_value,
+			      sizeof(__entry->point_y_value));
+		       memcpy(__entry->point_y_scaling, f->point_y_scaling,
+			      sizeof(__entry->point_y_scaling));
+		       __entry->num_cb_points = f->num_cb_points;
+		       memcpy(__entry->point_cb_value, f->point_cb_value,
+			      sizeof(__entry->point_cb_value));
+		       memcpy(__entry->point_cb_scaling, f->point_cb_scaling,
+			      sizeof(__entry->point_cb_scaling));
+		       __entry->num_cr_points = f->num_cr_points;
+		       memcpy(__entry->point_cr_value, f->point_cr_value,
+			      sizeof(__entry->point_cr_value));
+		       memcpy(__entry->point_cr_scaling, f->point_cr_scaling,
+			      sizeof(__entry->point_cr_scaling));
+		       __entry->grain_scaling_minus_8 = f->grain_scaling_minus_8;
+		       __entry->ar_coeff_lag = f->ar_coeff_lag;
+		       memcpy(__entry->ar_coeffs_y_plus_128, f->ar_coeffs_y_plus_128,
+			      sizeof(__entry->ar_coeffs_y_plus_128));
+		       memcpy(__entry->ar_coeffs_cb_plus_128, f->ar_coeffs_cb_plus_128,
+			      sizeof(__entry->ar_coeffs_cb_plus_128));
+		       memcpy(__entry->ar_coeffs_cr_plus_128, f->ar_coeffs_cr_plus_128,
+			      sizeof(__entry->ar_coeffs_cr_plus_128));
+		       __entry->ar_coeff_shift_minus_6 = f->ar_coeff_shift_minus_6;
+		       __entry->grain_scale_shift = f->grain_scale_shift;
+		       __entry->cb_mult = f->cb_mult;
+		       __entry->cb_luma_mult = f->cb_luma_mult;
+		       __entry->cr_luma_mult = f->cr_luma_mult;
+		       __entry->cb_offset = f->cb_offset;
+		       __entry->cr_offset = f->cr_offset;),
 	TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
 		  "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n"
 		  "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n"
@@ -235,54 +455,54 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 		  "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n"
 		  "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n"
 		  "cb_offset: %u\ncr_offset: %u\n",
-		  __print_flags(__entry->f.flags, "|",
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"},
 		  {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"},
 		  {V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA, "CHROMA_SCALING_FROM_LUMA"},
 		  {V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP, "OVERLAP"},
 		  {V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE, "CLIP_TO_RESTRICTED_RANGE"}),
-		  __entry->f.cr_mult,
-		  __entry->f.grain_seed,
-		  __entry->f.film_grain_params_ref_idx,
-		  __entry->f.num_y_points,
-		  __print_array(__entry->f.point_y_value,
-				ARRAY_SIZE(__entry->f.point_y_value),
-				sizeof(__entry->f.point_y_value[0])),
-		  __print_array(__entry->f.point_y_scaling,
-				ARRAY_SIZE(__entry->f.point_y_scaling),
-				sizeof(__entry->f.point_y_scaling[0])),
-		  __entry->f.num_cb_points,
-		  __print_array(__entry->f.point_cb_value,
-				ARRAY_SIZE(__entry->f.point_cb_value),
-				sizeof(__entry->f.point_cb_value[0])),
-		  __print_array(__entry->f.point_cb_scaling,
-				ARRAY_SIZE(__entry->f.point_cb_scaling),
-				sizeof(__entry->f.point_cb_scaling[0])),
-		  __entry->f.num_cr_points,
-		  __print_array(__entry->f.point_cr_value,
-				ARRAY_SIZE(__entry->f.point_cr_value),
-				sizeof(__entry->f.point_cr_value[0])),
-		  __print_array(__entry->f.point_cr_scaling,
-				ARRAY_SIZE(__entry->f.point_cr_scaling),
-				sizeof(__entry->f.point_cr_scaling[0])),
-		  __entry->f.grain_scaling_minus_8,
-		  __entry->f.ar_coeff_lag,
-		  __print_array(__entry->f.ar_coeffs_y_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_y_plus_128),
-				sizeof(__entry->f.ar_coeffs_y_plus_128[0])),
-		  __print_array(__entry->f.ar_coeffs_cb_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_cb_plus_128),
-				sizeof(__entry->f.ar_coeffs_cb_plus_128[0])),
-		  __print_array(__entry->f.ar_coeffs_cr_plus_128,
-				ARRAY_SIZE(__entry->f.ar_coeffs_cr_plus_128),
-				sizeof(__entry->f.ar_coeffs_cr_plus_128[0])),
-		  __entry->f.ar_coeff_shift_minus_6,
-		  __entry->f.grain_scale_shift,
-		  __entry->f.cb_mult,
-		  __entry->f.cb_luma_mult,
-		  __entry->f.cr_luma_mult,
-		  __entry->f.cb_offset,
-		  __entry->f.cr_offset
+		  __entry->cr_mult,
+		  __entry->grain_seed,
+		  __entry->film_grain_params_ref_idx,
+		  __entry->num_y_points,
+		  __print_array(__entry->point_y_value,
+				ARRAY_SIZE(__entry->point_y_value),
+				sizeof(__entry->point_y_value[0])),
+		  __print_array(__entry->point_y_scaling,
+				ARRAY_SIZE(__entry->point_y_scaling),
+				sizeof(__entry->point_y_scaling[0])),
+		  __entry->num_cb_points,
+		  __print_array(__entry->point_cb_value,
+				ARRAY_SIZE(__entry->point_cb_value),
+				sizeof(__entry->point_cb_value[0])),
+		  __print_array(__entry->point_cb_scaling,
+				ARRAY_SIZE(__entry->point_cb_scaling),
+				sizeof(__entry->point_cb_scaling[0])),
+		  __entry->num_cr_points,
+		  __print_array(__entry->point_cr_value,
+				ARRAY_SIZE(__entry->point_cr_value),
+				sizeof(__entry->point_cr_value[0])),
+		  __print_array(__entry->point_cr_scaling,
+				ARRAY_SIZE(__entry->point_cr_scaling),
+				sizeof(__entry->point_cr_scaling[0])),
+		  __entry->grain_scaling_minus_8,
+		  __entry->ar_coeff_lag,
+		  __print_array(__entry->ar_coeffs_y_plus_128,
+				ARRAY_SIZE(__entry->ar_coeffs_y_plus_128),
+				sizeof(__entry->ar_coeffs_y_plus_128[0])),
+		  __print_array(__entry->ar_coeffs_cb_plus_128,
+				ARRAY_SIZE(__entry->ar_coeffs_cb_plus_128),
+				sizeof(__entry->ar_coeffs_cb_plus_128[0])),
+		  __print_array(__entry->ar_coeffs_cr_plus_128,
+				ARRAY_SIZE(__entry->ar_coeffs_cr_plus_128),
+				sizeof(__entry->ar_coeffs_cr_plus_128[0])),
+		  __entry->ar_coeff_shift_minus_6,
+		  __entry->grain_scale_shift,
+		  __entry->cb_mult,
+		  __entry->cb_luma_mult,
+		  __entry->cr_luma_mult,
+		  __entry->cb_offset,
+		  __entry->cr_offset
 	)
 )
 
@@ -333,7 +553,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
 		       __entry->ycbcr_enc = p->ycbcr_enc;
 		       __entry->quantization = p->quantization;
 		       ),
-	TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u xfer_func %u ycbcr_enc %u quantization %u",
+	TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u "
+		  "xfer_func %u ycbcr_enc %u quantization %u",
 		  __entry->backward_ref_ts, __entry->version, __entry->width, __entry->height,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_FWHT_FL_IS_INTERLACED, "IS_INTERLACED"},
@@ -362,8 +583,45 @@ DEFINE_EVENT(v4l2_ctrl_fwht_params_tmpl, v4l2_ctrl_fwht_params,
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_sps, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__field(u8, profile_idc)
+			 __field(u8, constraint_set_flags)
+			 __field(u8, level_idc)
+			 __field(u8, seq_parameter_set_id)
+			 __field(u8, chroma_format_idc)
+			 __field(u8, bit_depth_luma_minus8)
+			 __field(u8, bit_depth_chroma_minus8)
+			 __field(u8, log2_max_frame_num_minus4)
+			 __field(u8, pic_order_cnt_type)
+			 __field(u8, log2_max_pic_order_cnt_lsb_minus4)
+			 __field(u8, max_num_ref_frames)
+			 __field(u8, num_ref_frames_in_pic_order_cnt_cycle)
+			 __array(__s32, offset_for_ref_frame, 255)
+			 __field(__s32, offset_for_non_ref_pic)
+			 __field(__s32, offset_for_top_to_bottom_field)
+			 __field(u16, pic_width_in_mbs_minus1)
+			 __field(u16, pic_height_in_map_units_minus1)
+			 __field(u32, flags)),
+	TP_fast_assign(__entry->profile_idc = s->profile_idc;
+		       __entry->constraint_set_flags = s->constraint_set_flags;
+		       __entry->level_idc = s->level_idc;
+		       __entry->seq_parameter_set_id = s->seq_parameter_set_id;
+		       __entry->chroma_format_idc = s->chroma_format_idc;
+		       __entry->bit_depth_luma_minus8 = s->bit_depth_luma_minus8;
+		       __entry->bit_depth_chroma_minus8 = s->bit_depth_chroma_minus8;
+		       __entry->log2_max_frame_num_minus4 = s->log2_max_frame_num_minus4;
+		       __entry->pic_order_cnt_type = s->pic_order_cnt_type;
+		       __entry->log2_max_pic_order_cnt_lsb_minus4 =
+				s->log2_max_pic_order_cnt_lsb_minus4;
+		       __entry->max_num_ref_frames = s->max_num_ref_frames;
+		       __entry->num_ref_frames_in_pic_order_cnt_cycle =
+				s->num_ref_frames_in_pic_order_cnt_cycle;
+		       memcpy(__entry->offset_for_ref_frame, s->offset_for_ref_frame,
+			      sizeof(__entry->offset_for_ref_frame));
+		       __entry->offset_for_non_ref_pic = s->offset_for_non_ref_pic;
+		       __entry->offset_for_top_to_bottom_field = s->offset_for_top_to_bottom_field;
+		       __entry->pic_width_in_mbs_minus1 = s->pic_width_in_mbs_minus1;
+		       __entry->pic_height_in_map_units_minus1 = s->pic_height_in_map_units_minus1;
+		       __entry->flags = s->flags),
 	TP_printk("\nprofile_idc %u\n"
 		  "constraint_set_flags %s\n"
 		  "level_idc %u\n"
@@ -382,36 +640,38 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 		  "pic_width_in_mbs_minus1 %u\n"
 		  "pic_height_in_map_units_minus1 %u\n"
 		  "flags %s",
-		  __entry->s.profile_idc,
-		  __print_flags(__entry->s.constraint_set_flags, "|",
+		  __entry->profile_idc,
+		  __print_flags(__entry->constraint_set_flags, "|",
 		  {V4L2_H264_SPS_CONSTRAINT_SET0_FLAG, "CONSTRAINT_SET0_FLAG"},
 		  {V4L2_H264_SPS_CONSTRAINT_SET1_FLAG, "CONSTRAINT_SET1_FLAG"},
 		  {V4L2_H264_SPS_CONSTRAINT_SET2_FLAG, "CONSTRAINT_SET2_FLAG"},
 		  {V4L2_H264_SPS_CONSTRAINT_SET3_FLAG, "CONSTRAINT_SET3_FLAG"},
 		  {V4L2_H264_SPS_CONSTRAINT_SET4_FLAG, "CONSTRAINT_SET4_FLAG"},
 		  {V4L2_H264_SPS_CONSTRAINT_SET5_FLAG, "CONSTRAINT_SET5_FLAG"}),
-		  __entry->s.level_idc,
-		  __entry->s.seq_parameter_set_id,
-		  __entry->s.chroma_format_idc,
-		  __entry->s.bit_depth_luma_minus8,
-		  __entry->s.bit_depth_chroma_minus8,
-		  __entry->s.log2_max_frame_num_minus4,
-		  __entry->s.pic_order_cnt_type,
-		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
-		  __entry->s.max_num_ref_frames,
-		  __entry->s.num_ref_frames_in_pic_order_cnt_cycle,
-		  __print_array(__entry->s.offset_for_ref_frame,
-				ARRAY_SIZE(__entry->s.offset_for_ref_frame),
-				sizeof(__entry->s.offset_for_ref_frame[0])),
-		  __entry->s.offset_for_non_ref_pic,
-		  __entry->s.offset_for_top_to_bottom_field,
-		  __entry->s.pic_width_in_mbs_minus1,
-		  __entry->s.pic_height_in_map_units_minus1,
-		  __print_flags(__entry->s.flags, "|",
+		  __entry->level_idc,
+		  __entry->seq_parameter_set_id,
+		  __entry->chroma_format_idc,
+		  __entry->bit_depth_luma_minus8,
+		  __entry->bit_depth_chroma_minus8,
+		  __entry->log2_max_frame_num_minus4,
+		  __entry->pic_order_cnt_type,
+		  __entry->log2_max_pic_order_cnt_lsb_minus4,
+		  __entry->max_num_ref_frames,
+		  __entry->num_ref_frames_in_pic_order_cnt_cycle,
+		  __print_array(__entry->offset_for_ref_frame,
+				ARRAY_SIZE(__entry->offset_for_ref_frame),
+				sizeof(__entry->offset_for_ref_frame[0])),
+		  __entry->offset_for_non_ref_pic,
+		  __entry->offset_for_top_to_bottom_field,
+		  __entry->pic_width_in_mbs_minus1,
+		  __entry->pic_height_in_map_units_minus1,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
-		  {V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS, "QPPRIME_Y_ZERO_TRANSFORM_BYPASS"},
+		  {V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS,
+		   "QPPRIME_Y_ZERO_TRANSFORM_BYPASS"},
 		  {V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO, "DELTA_PIC_ORDER_ALWAYS_ZERO"},
-		  {V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED, "GAPS_IN_FRAME_NUM_VALUE_ALLOWED"},
+		  {V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED,
+		   "GAPS_IN_FRAME_NUM_VALUE_ALLOWED"},
 		  {V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY, "FRAME_MBS_ONLY"},
 		  {V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD, "MB_ADAPTIVE_FRAME_FIELD"},
 		  {V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE, "DIRECT_8X8_INFERENCE"}
@@ -421,8 +681,30 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pps, p)),
-	TP_fast_assign(__entry->p = *p),
+	TP_STRUCT__entry(__field(u8, pic_parameter_set_id)
+			 __field(u8, seq_parameter_set_id)
+			 __field(u8, num_slice_groups_minus1)
+			 __field(u8, num_ref_idx_l0_default_active_minus1)
+			 __field(u8, num_ref_idx_l1_default_active_minus1)
+			 __field(u8, weighted_bipred_idc)
+			 __field(__s8, pic_init_qp_minus26)
+			 __field(__s8, pic_init_qs_minus26)
+			 __field(__s8, chroma_qp_index_offset)
+			 __field(__s8, second_chroma_qp_index_offset)
+			 __field(u16, flags)),
+	TP_fast_assign(__entry->pic_parameter_set_id = p->pic_parameter_set_id;
+		       __entry->seq_parameter_set_id = p->seq_parameter_set_id;
+		       __entry->num_slice_groups_minus1 = p->num_slice_groups_minus1;
+		       __entry->num_ref_idx_l0_default_active_minus1 =
+				p->num_ref_idx_l0_default_active_minus1;
+		       __entry->num_ref_idx_l1_default_active_minus1 =
+				p->num_ref_idx_l1_default_active_minus1;
+		       __entry->weighted_bipred_idc = p->weighted_bipred_idc;
+		       __entry->pic_init_qp_minus26 = p->pic_init_qp_minus26;
+		       __entry->pic_init_qs_minus26 = p->pic_init_qs_minus26;
+		       __entry->chroma_qp_index_offset = p->chroma_qp_index_offset;
+		       __entry->second_chroma_qp_index_offset = p->second_chroma_qp_index_offset;
+		       __entry->flags = p->flags),
 	TP_printk("\npic_parameter_set_id %u\n"
 		  "seq_parameter_set_id %u\n"
 		  "num_slice_groups_minus1 %u\n"
@@ -434,21 +716,23 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 		  "chroma_qp_index_offset %d\n"
 		  "second_chroma_qp_index_offset %d\n"
 		  "flags %s",
-		  __entry->p.pic_parameter_set_id,
-		  __entry->p.seq_parameter_set_id,
-		  __entry->p.num_slice_groups_minus1,
-		  __entry->p.num_ref_idx_l0_default_active_minus1,
-		  __entry->p.num_ref_idx_l1_default_active_minus1,
-		  __entry->p.weighted_bipred_idc,
-		  __entry->p.pic_init_qp_minus26,
-		  __entry->p.pic_init_qs_minus26,
-		  __entry->p.chroma_qp_index_offset,
-		  __entry->p.second_chroma_qp_index_offset,
-		  __print_flags(__entry->p.flags, "|",
+		  __entry->pic_parameter_set_id,
+		  __entry->seq_parameter_set_id,
+		  __entry->num_slice_groups_minus1,
+		  __entry->num_ref_idx_l0_default_active_minus1,
+		  __entry->num_ref_idx_l1_default_active_minus1,
+		  __entry->weighted_bipred_idc,
+		  __entry->pic_init_qp_minus26,
+		  __entry->pic_init_qs_minus26,
+		  __entry->chroma_qp_index_offset,
+		  __entry->second_chroma_qp_index_offset,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE, "ENTROPY_CODING_MODE"},
-		  {V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT, "BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT"},
+		  {V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT,
+		   "BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT"},
 		  {V4L2_H264_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
-		  {V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+		  {V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT,
+		   "DEBLOCKING_FILTER_CONTROL_PRESENT"},
 		  {V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
 		  {V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT, "REDUNDANT_PIC_CNT_PRESENT"},
 		  {V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE, "TRANSFORM_8X8_MODE"},
@@ -459,16 +743,20 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_scaling_matrix, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__array(u8, scaling_list_4x4, 6 * 16)
+			 __array(u8, scaling_list_8x8, 6 * 64)),
+	TP_fast_assign(memcpy(__entry->scaling_list_4x4, s->scaling_list_4x4,
+			      sizeof(__entry->scaling_list_4x4));
+		       memcpy(__entry->scaling_list_8x8, s->scaling_list_8x8,
+			      sizeof(__entry->scaling_list_8x8))),
 	TP_printk("\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_4x4,
-				   sizeof(__entry->s.scaling_list_4x4),
+				   __entry->scaling_list_4x4,
+				   sizeof(__entry->scaling_list_4x4),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_8x8,
-				   sizeof(__entry->s.scaling_list_8x8),
+				   __entry->scaling_list_8x8,
+				   sizeof(__entry->scaling_list_8x8),
 				   false)
 	)
 );
@@ -476,8 +764,42 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_pred_weights, p)),
-	TP_fast_assign(__entry->p = *p),
+	TP_STRUCT__entry(__field(u16, luma_log2_weight_denom)
+			 __field(u16, chroma_log2_weight_denom)
+			 __array(__s16, weight_factors_0_luma_weight, 32)
+			 __array(__s16, weight_factors_0_luma_offset, 32)
+			 __array(__s16, weight_factors_0_chroma_weight, 32 * 2)
+			 __array(__s16, weight_factors_0_chroma_offset, 32 * 2)
+			 __array(__s16, weight_factors_1_luma_weight, 32)
+			 __array(__s16, weight_factors_1_luma_offset, 32)
+			 __array(__s16, weight_factors_1_chroma_weight, 32 * 2)
+			 __array(__s16, weight_factors_1_chroma_offset, 32 * 2)),
+	TP_fast_assign(__entry->luma_log2_weight_denom = p->luma_log2_weight_denom;
+		       __entry->chroma_log2_weight_denom = p->chroma_log2_weight_denom;
+		       memcpy(__entry->weight_factors_0_luma_weight,
+			      p->weight_factors[0].luma_weight,
+			      sizeof(__entry->weight_factors_0_luma_weight));
+		       memcpy(__entry->weight_factors_0_luma_offset,
+			      p->weight_factors[0].luma_offset,
+			      sizeof(__entry->weight_factors_0_luma_offset));
+		       memcpy(__entry->weight_factors_0_chroma_weight,
+			      p->weight_factors[0].chroma_weight,
+			      sizeof(__entry->weight_factors_0_chroma_weight));
+		       memcpy(__entry->weight_factors_0_chroma_offset,
+			      p->weight_factors[0].chroma_offset,
+			      sizeof(__entry->weight_factors_0_chroma_offset));
+		       memcpy(__entry->weight_factors_1_luma_weight,
+			      p->weight_factors[1].luma_weight,
+			      sizeof(__entry->weight_factors_1_luma_weight));
+		       memcpy(__entry->weight_factors_1_luma_offset,
+			      p->weight_factors[1].luma_offset,
+			      sizeof(__entry->weight_factors_1_luma_offset));
+		       memcpy(__entry->weight_factors_1_chroma_weight,
+			      p->weight_factors[1].chroma_weight,
+			      sizeof(__entry->weight_factors_1_chroma_weight));
+		       memcpy(__entry->weight_factors_1_chroma_offset,
+			      p->weight_factors[1].chroma_offset,
+			      sizeof(__entry->weight_factors_1_chroma_offset))),
 	TP_printk("\nluma_log2_weight_denom %u\n"
 		  "chroma_log2_weight_denom %u\n"
 		  "weight_factor[0].luma_weight %s\n"
@@ -488,35 +810,35 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 		  "weight_factor[1].luma_offset %s\n"
 		  "weight_factor[1].chroma_weight {%s}\n"
 		  "weight_factor[1].chroma_offset {%s}\n",
-		  __entry->p.luma_log2_weight_denom,
-		  __entry->p.chroma_log2_weight_denom,
-		  __print_array(__entry->p.weight_factors[0].luma_weight,
-				ARRAY_SIZE(__entry->p.weight_factors[0].luma_weight),
-				sizeof(__entry->p.weight_factors[0].luma_weight[0])),
-		  __print_array(__entry->p.weight_factors[0].luma_offset,
-				ARRAY_SIZE(__entry->p.weight_factors[0].luma_offset),
-				sizeof(__entry->p.weight_factors[0].luma_offset[0])),
+		  __entry->luma_log2_weight_denom,
+		  __entry->chroma_log2_weight_denom,
+		  __print_array(__entry->weight_factors_0_luma_weight,
+				ARRAY_SIZE(__entry->weight_factors_0_luma_weight),
+				sizeof(__entry->weight_factors_0_luma_weight[0])),
+		  __print_array(__entry->weight_factors_0_luma_offset,
+				ARRAY_SIZE(__entry->weight_factors_0_luma_offset),
+				sizeof(__entry->weight_factors_0_luma_offset[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[0].chroma_weight,
-				   sizeof(__entry->p.weight_factors[0].chroma_weight),
+				   __entry->weight_factors_0_chroma_weight,
+				   sizeof(__entry->weight_factors_0_chroma_weight),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[0].chroma_offset,
-				   sizeof(__entry->p.weight_factors[0].chroma_offset),
+				   __entry->weight_factors_0_chroma_offset,
+				   sizeof(__entry->weight_factors_0_chroma_offset),
 				   false),
-		  __print_array(__entry->p.weight_factors[1].luma_weight,
-				ARRAY_SIZE(__entry->p.weight_factors[1].luma_weight),
-				sizeof(__entry->p.weight_factors[1].luma_weight[0])),
-		  __print_array(__entry->p.weight_factors[1].luma_offset,
-				ARRAY_SIZE(__entry->p.weight_factors[1].luma_offset),
-				sizeof(__entry->p.weight_factors[1].luma_offset[0])),
+		  __print_array(__entry->weight_factors_1_luma_weight,
+				ARRAY_SIZE(__entry->weight_factors_1_luma_weight),
+				sizeof(__entry->weight_factors_1_luma_weight[0])),
+		  __print_array(__entry->weight_factors_1_luma_offset,
+				ARRAY_SIZE(__entry->weight_factors_1_luma_offset),
+				sizeof(__entry->weight_factors_1_luma_offset[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[1].chroma_weight,
-				   sizeof(__entry->p.weight_factors[1].chroma_weight),
+				   __entry->weight_factors_1_chroma_weight,
+				   sizeof(__entry->weight_factors_1_chroma_weight),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.weight_factors[1].chroma_offset,
-				   sizeof(__entry->p.weight_factors[1].chroma_offset),
+				   __entry->weight_factors_1_chroma_offset,
+				   sizeof(__entry->weight_factors_1_chroma_offset),
 				   false)
 	)
 );
@@ -524,8 +846,34 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_slice_params, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__field(u32, header_bit_size)
+			 __field(u32, first_mb_in_slice)
+			 __field(u8, slice_type)
+			 __field(u8, colour_plane_id)
+			 __field(u8, redundant_pic_cnt)
+			 __field(u8, cabac_init_idc)
+			 __field(__s8, slice_qp_delta)
+			 __field(__s8, slice_qs_delta)
+			 __field(u8, disable_deblocking_filter_idc)
+			 __field(__s8, slice_alpha_c0_offset_div2)
+			 __field(__s8, slice_beta_offset_div2)
+			 __field(u8, num_ref_idx_l0_active_minus1)
+			 __field(u8, num_ref_idx_l1_active_minus1)
+			 __field(u32, flags)),
+	TP_fast_assign(__entry->header_bit_size = s->header_bit_size;
+		       __entry->first_mb_in_slice = s->first_mb_in_slice;
+		       __entry->slice_type = s->slice_type;
+		       __entry->colour_plane_id = s->colour_plane_id;
+		       __entry->redundant_pic_cnt = s->redundant_pic_cnt;
+		       __entry->cabac_init_idc = s->cabac_init_idc;
+		       __entry->slice_qp_delta = s->slice_qp_delta;
+		       __entry->slice_qs_delta = s->slice_qs_delta;
+		       __entry->disable_deblocking_filter_idc = s->disable_deblocking_filter_idc;
+		       __entry->slice_alpha_c0_offset_div2 = s->slice_alpha_c0_offset_div2;
+		       __entry->slice_beta_offset_div2 = s->slice_beta_offset_div2;
+		       __entry->num_ref_idx_l0_active_minus1 = s->num_ref_idx_l0_active_minus1;
+		       __entry->num_ref_idx_l1_active_minus1 = s->num_ref_idx_l1_active_minus1;
+		       __entry->flags = s->flags),
 	TP_printk("\nheader_bit_size %u\n"
 		  "first_mb_in_slice %u\n"
 		  "slice_type %s\n"
@@ -540,25 +888,25 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 		  "num_ref_idx_l0_active_minus1 %u\n"
 		  "num_ref_idx_l1_active_minus1 %u\n"
 		  "flags %s",
-		  __entry->s.header_bit_size,
-		  __entry->s.first_mb_in_slice,
-		  __print_symbolic(__entry->s.slice_type,
+		  __entry->header_bit_size,
+		  __entry->first_mb_in_slice,
+		  __print_symbolic(__entry->slice_type,
 		  {V4L2_H264_SLICE_TYPE_P, "P"},
 		  {V4L2_H264_SLICE_TYPE_B, "B"},
 		  {V4L2_H264_SLICE_TYPE_I, "I"},
 		  {V4L2_H264_SLICE_TYPE_SP, "SP"},
 		  {V4L2_H264_SLICE_TYPE_SI, "SI"}),
-		  __entry->s.colour_plane_id,
-		  __entry->s.redundant_pic_cnt,
-		  __entry->s.cabac_init_idc,
-		  __entry->s.slice_qp_delta,
-		  __entry->s.slice_qs_delta,
-		  __entry->s.disable_deblocking_filter_idc,
-		  __entry->s.slice_alpha_c0_offset_div2,
-		  __entry->s.slice_beta_offset_div2,
-		  __entry->s.num_ref_idx_l0_active_minus1,
-		  __entry->s.num_ref_idx_l1_active_minus1,
-		  __print_flags(__entry->s.flags, "|",
+		  __entry->colour_plane_id,
+		  __entry->redundant_pic_cnt,
+		  __entry->cabac_init_idc,
+		  __entry->slice_qp_delta,
+		  __entry->slice_qs_delta,
+		  __entry->disable_deblocking_filter_idc,
+		  __entry->slice_alpha_c0_offset_div2,
+		  __entry->slice_beta_offset_div2,
+		  __entry->num_ref_idx_l0_active_minus1,
+		  __entry->num_ref_idx_l1_active_minus1,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED, "DIRECT_SPATIAL_MV_PRED"},
 		  {V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH, "SP_FOR_SWITCH"})
 	)
@@ -567,24 +915,51 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
 	TP_PROTO(const struct v4l2_h264_reference *r, int i),
 	TP_ARGS(r, i),
-	TP_STRUCT__entry(__field_struct(struct v4l2_h264_reference, r)
+	TP_STRUCT__entry(__field(u8, fields)
+			 __field(u8, index)
 			 __field(int, i)),
-	TP_fast_assign(__entry->r = *r; __entry->i = i;),
+	TP_fast_assign(__entry->fields = r->fields;
+		       __entry->index = r->index;
+		       __entry->i = i;),
 	TP_printk("[%d]: fields %s index %u",
 		  __entry->i,
-		  __print_flags(__entry->r.fields, "|",
+		  __print_flags(__entry->fields, "|",
 		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
 		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
 		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
-		  __entry->r.index
+		  __entry->index
 	)
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
 	TP_ARGS(d),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_h264_decode_params, d)),
-	TP_fast_assign(__entry->d = *d),
+	TP_STRUCT__entry(__field(u16, nal_ref_idc)
+			 __field(u16, frame_num)
+			 __field(__s32, top_field_order_cnt)
+			 __field(__s32, bottom_field_order_cnt)
+			 __field(u16, idr_pic_id)
+			 __field(u16, pic_order_cnt_lsb)
+			 __field(__s32, delta_pic_order_cnt_bottom)
+			 __field(__s32, delta_pic_order_cnt0)
+			 __field(__s32, delta_pic_order_cnt1)
+			 __field(u32, dec_ref_pic_marking_bit_size)
+			 __field(u32, pic_order_cnt_bit_size)
+			 __field(u32, slice_group_change_cycle)
+			 __field(u32, flags)),
+	TP_fast_assign(__entry->nal_ref_idc = d->nal_ref_idc;
+		       __entry->frame_num = d->frame_num;
+		       __entry->top_field_order_cnt = d->top_field_order_cnt;
+		       __entry->bottom_field_order_cnt = d->bottom_field_order_cnt;
+		       __entry->idr_pic_id = d->idr_pic_id;
+		       __entry->pic_order_cnt_lsb = d->pic_order_cnt_lsb;
+		       __entry->delta_pic_order_cnt_bottom = d->delta_pic_order_cnt_bottom;
+		       __entry->delta_pic_order_cnt0 = d->delta_pic_order_cnt0;
+		       __entry->delta_pic_order_cnt1 = d->delta_pic_order_cnt1;
+		       __entry->dec_ref_pic_marking_bit_size = d->dec_ref_pic_marking_bit_size;
+		       __entry->pic_order_cnt_bit_size = d->pic_order_cnt_bit_size;
+		       __entry->slice_group_change_cycle = d->slice_group_change_cycle;
+		       __entry->flags = d->flags),
 	TP_printk("\nnal_ref_idc %u\n"
 		  "frame_num %u\n"
 		  "top_field_order_cnt %d\n"
@@ -598,19 +973,19 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 		  "pic_order_cnt_bit_size %u\n"
 		  "slice_group_change_cycle %u\n"
 		  "flags %s\n",
-		  __entry->d.nal_ref_idc,
-		  __entry->d.frame_num,
-		  __entry->d.top_field_order_cnt,
-		  __entry->d.bottom_field_order_cnt,
-		  __entry->d.idr_pic_id,
-		  __entry->d.pic_order_cnt_lsb,
-		  __entry->d.delta_pic_order_cnt_bottom,
-		  __entry->d.delta_pic_order_cnt0,
-		  __entry->d.delta_pic_order_cnt1,
-		  __entry->d.dec_ref_pic_marking_bit_size,
-		  __entry->d.pic_order_cnt_bit_size,
-		  __entry->d.slice_group_change_cycle,
-		  __print_flags(__entry->d.flags, "|",
+		  __entry->nal_ref_idc,
+		  __entry->frame_num,
+		  __entry->top_field_order_cnt,
+		  __entry->bottom_field_order_cnt,
+		  __entry->idr_pic_id,
+		  __entry->pic_order_cnt_lsb,
+		  __entry->delta_pic_order_cnt_bottom,
+		  __entry->delta_pic_order_cnt0,
+		  __entry->delta_pic_order_cnt1,
+		  __entry->dec_ref_pic_marking_bit_size,
+		  __entry->pic_order_cnt_bit_size,
+		  __entry->slice_group_change_cycle,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
 		  {V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC, "FIELD_PIC"},
 		  {V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD, "BOTTOM_FIELD"},
@@ -622,22 +997,35 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
 	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
 	TP_ARGS(e, i),
-	TP_STRUCT__entry(__field_struct(struct v4l2_h264_dpb_entry, e)
+	TP_STRUCT__entry(__field(u64, reference_ts)
+			 __field(u32, pic_num)
+			 __field(u16, frame_num)
+			 __field(u8, fields)
+			 __field(__s32, top_field_order_cnt)
+			 __field(__s32, bottom_field_order_cnt)
+			 __field(u32, flags)
 			 __field(int, i)),
-	TP_fast_assign(__entry->e = *e; __entry->i = i;),
+	TP_fast_assign(__entry->reference_ts = e->reference_ts;
+		       __entry->pic_num = e->pic_num;
+		       __entry->frame_num = e->frame_num;
+		       __entry->fields = e->fields;
+		       __entry->top_field_order_cnt = e->top_field_order_cnt;
+		       __entry->bottom_field_order_cnt = e->bottom_field_order_cnt;
+		       __entry->flags = e->flags;
+		       __entry->i = i;),
 	TP_printk("[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
 		  "top_field_order_cnt %d bottom_field_order_cnt %d flags %s",
 		  __entry->i,
-		  __entry->e.reference_ts,
-		  __entry->e.pic_num,
-		  __entry->e.frame_num,
-		  __print_flags(__entry->e.fields, "|",
+		  __entry->reference_ts,
+		  __entry->pic_num,
+		  __entry->frame_num,
+		  __print_flags(__entry->fields, "|",
 		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
 		  {V4L2_H264_BOTTOM_FIELD_REF, "BOTTOM_FIELD_REF"},
 		  {V4L2_H264_FRAME_REF, "FRAME_REF"}),
-		  __entry->e.top_field_order_cnt,
-		  __entry->e.bottom_field_order_cnt,
-		  __print_flags(__entry->e.flags, "|",
+		  __entry->top_field_order_cnt,
+		  __entry->bottom_field_order_cnt,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_H264_DPB_ENTRY_FLAG_VALID, "VALID"},
 		  {V4L2_H264_DPB_ENTRY_FLAG_ACTIVE, "ACTIVE"},
 		  {V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM, "LONG_TERM"},
@@ -696,8 +1084,68 @@ DEFINE_EVENT(v4l2_h264_dpb_entry_tmpl, v4l2_h264_dpb_entry,
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_sps, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__field(__u8, video_parameter_set_id)
+			 __field(__u8, seq_parameter_set_id)
+			 __field(__u16, pic_width_in_luma_samples)
+			 __field(__u16, pic_height_in_luma_samples)
+			 __field(__u8, bit_depth_luma_minus8)
+			 __field(__u8, bit_depth_chroma_minus8)
+			 __field(__u8, log2_max_pic_order_cnt_lsb_minus4)
+			 __field(__u8, sps_max_dec_pic_buffering_minus1)
+			 __field(__u8, sps_max_num_reorder_pics)
+			 __field(__u8, sps_max_latency_increase_plus1)
+			 __field(__u8, log2_min_luma_coding_block_size_minus3)
+			 __field(__u8, log2_diff_max_min_luma_coding_block_size)
+			 __field(__u8, log2_min_luma_transform_block_size_minus2)
+			 __field(__u8, log2_diff_max_min_luma_transform_block_size)
+			 __field(__u8, max_transform_hierarchy_depth_inter)
+			 __field(__u8, max_transform_hierarchy_depth_intra)
+			 __field(__u8, pcm_sample_bit_depth_luma_minus1)
+			 __field(__u8, pcm_sample_bit_depth_chroma_minus1)
+			 __field(__u8, log2_min_pcm_luma_coding_block_size_minus3)
+			 __field(__u8, log2_diff_max_min_pcm_luma_coding_block_size)
+			 __field(__u8, num_short_term_ref_pic_sets)
+			 __field(__u8, num_long_term_ref_pics_sps)
+			 __field(__u8, chroma_format_idc)
+			 __field(__u8, sps_max_sub_layers_minus1)
+			 __field(__u64, flags)),
+	TP_fast_assign(__entry->video_parameter_set_id = s->video_parameter_set_id;
+		       __entry->seq_parameter_set_id = s->seq_parameter_set_id;
+		       __entry->pic_width_in_luma_samples = s->pic_width_in_luma_samples;
+		       __entry->pic_height_in_luma_samples = s->pic_height_in_luma_samples;
+		       __entry->bit_depth_luma_minus8 = s->bit_depth_luma_minus8;
+		       __entry->bit_depth_chroma_minus8 = s->bit_depth_chroma_minus8;
+		       __entry->log2_max_pic_order_cnt_lsb_minus4 =
+				s->log2_max_pic_order_cnt_lsb_minus4;
+		       __entry->sps_max_dec_pic_buffering_minus1 =
+				s->sps_max_dec_pic_buffering_minus1;
+		       __entry->sps_max_num_reorder_pics = s->sps_max_num_reorder_pics;
+		       __entry->sps_max_latency_increase_plus1 = s->sps_max_latency_increase_plus1;
+		       __entry->log2_min_luma_coding_block_size_minus3 =
+				s->log2_min_luma_coding_block_size_minus3;
+		       __entry->log2_diff_max_min_luma_coding_block_size =
+				s->log2_diff_max_min_luma_coding_block_size;
+		       __entry->log2_min_luma_transform_block_size_minus2 =
+				s->log2_min_luma_transform_block_size_minus2;
+		       __entry->log2_diff_max_min_luma_transform_block_size =
+				s->log2_diff_max_min_luma_transform_block_size;
+		       __entry->max_transform_hierarchy_depth_inter =
+				s->max_transform_hierarchy_depth_inter;
+		       __entry->max_transform_hierarchy_depth_intra =
+				s->max_transform_hierarchy_depth_intra;
+		       __entry->pcm_sample_bit_depth_luma_minus1 =
+				s->pcm_sample_bit_depth_luma_minus1;
+		       __entry->pcm_sample_bit_depth_chroma_minus1 =
+				s->pcm_sample_bit_depth_chroma_minus1;
+		       __entry->log2_min_pcm_luma_coding_block_size_minus3 =
+				s->log2_min_pcm_luma_coding_block_size_minus3;
+		       __entry->log2_diff_max_min_pcm_luma_coding_block_size =
+				s->log2_diff_max_min_pcm_luma_coding_block_size;
+		       __entry->num_short_term_ref_pic_sets = s->num_short_term_ref_pic_sets;
+		       __entry->num_long_term_ref_pics_sps = s->num_long_term_ref_pics_sps;
+		       __entry->chroma_format_idc = s->chroma_format_idc;
+		       __entry->sps_max_sub_layers_minus1 = s->sps_max_sub_layers_minus1;
+		       __entry->flags = s->flags;),
 	TP_printk("\nvideo_parameter_set_id %u\n"
 		  "seq_parameter_set_id %u\n"
 		  "pic_width_in_luma_samples %u\n"
@@ -723,40 +1171,42 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 		  "chroma_format_idc %u\n"
 		  "sps_max_sub_layers_minus1 %u\n"
 		  "flags %s",
-		  __entry->s.video_parameter_set_id,
-		  __entry->s.seq_parameter_set_id,
-		  __entry->s.pic_width_in_luma_samples,
-		  __entry->s.pic_height_in_luma_samples,
-		  __entry->s.bit_depth_luma_minus8,
-		  __entry->s.bit_depth_chroma_minus8,
-		  __entry->s.log2_max_pic_order_cnt_lsb_minus4,
-		  __entry->s.sps_max_dec_pic_buffering_minus1,
-		  __entry->s.sps_max_num_reorder_pics,
-		  __entry->s.sps_max_latency_increase_plus1,
-		  __entry->s.log2_min_luma_coding_block_size_minus3,
-		  __entry->s.log2_diff_max_min_luma_coding_block_size,
-		  __entry->s.log2_min_luma_transform_block_size_minus2,
-		  __entry->s.log2_diff_max_min_luma_transform_block_size,
-		  __entry->s.max_transform_hierarchy_depth_inter,
-		  __entry->s.max_transform_hierarchy_depth_intra,
-		  __entry->s.pcm_sample_bit_depth_luma_minus1,
-		  __entry->s.pcm_sample_bit_depth_chroma_minus1,
-		  __entry->s.log2_min_pcm_luma_coding_block_size_minus3,
-		  __entry->s.log2_diff_max_min_pcm_luma_coding_block_size,
-		  __entry->s.num_short_term_ref_pic_sets,
-		  __entry->s.num_long_term_ref_pics_sps,
-		  __entry->s.chroma_format_idc,
-		  __entry->s.sps_max_sub_layers_minus1,
-		  __print_flags(__entry->s.flags, "|",
+		  __entry->video_parameter_set_id,
+		  __entry->seq_parameter_set_id,
+		  __entry->pic_width_in_luma_samples,
+		  __entry->pic_height_in_luma_samples,
+		  __entry->bit_depth_luma_minus8,
+		  __entry->bit_depth_chroma_minus8,
+		  __entry->log2_max_pic_order_cnt_lsb_minus4,
+		  __entry->sps_max_dec_pic_buffering_minus1,
+		  __entry->sps_max_num_reorder_pics,
+		  __entry->sps_max_latency_increase_plus1,
+		  __entry->log2_min_luma_coding_block_size_minus3,
+		  __entry->log2_diff_max_min_luma_coding_block_size,
+		  __entry->log2_min_luma_transform_block_size_minus2,
+		  __entry->log2_diff_max_min_luma_transform_block_size,
+		  __entry->max_transform_hierarchy_depth_inter,
+		  __entry->max_transform_hierarchy_depth_intra,
+		  __entry->pcm_sample_bit_depth_luma_minus1,
+		  __entry->pcm_sample_bit_depth_chroma_minus1,
+		  __entry->log2_min_pcm_luma_coding_block_size_minus3,
+		  __entry->log2_diff_max_min_pcm_luma_coding_block_size,
+		  __entry->num_short_term_ref_pic_sets,
+		  __entry->num_long_term_ref_pics_sps,
+		  __entry->chroma_format_idc,
+		  __entry->sps_max_sub_layers_minus1,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE, "SEPARATE_COLOUR_PLANE"},
 		  {V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED, "SCALING_LIST_ENABLED"},
 		  {V4L2_HEVC_SPS_FLAG_AMP_ENABLED, "AMP_ENABLED"},
 		  {V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET, "SAMPLE_ADAPTIVE_OFFSET"},
 		  {V4L2_HEVC_SPS_FLAG_PCM_ENABLED, "PCM_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED, "V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED"},
+		  {V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED,
+		   "V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED"},
 		  {V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT, "LONG_TERM_REF_PICS_PRESENT"},
 		  {V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED, "TEMPORAL_MVP_ENABLED"},
-		  {V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED, "STRONG_INTRA_SMOOTHING_ENABLED"}
+		  {V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED,
+		   "STRONG_INTRA_SMOOTHING_ENABLED"}
 	))
 
 );
@@ -765,8 +1215,43 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_pps, p)),
-	TP_fast_assign(__entry->p = *p),
+	TP_STRUCT__entry(__field(__u8, pic_parameter_set_id)
+			 __field(__u8, num_extra_slice_header_bits)
+			 __field(__u8, num_ref_idx_l0_default_active_minus1)
+			 __field(__u8, num_ref_idx_l1_default_active_minus1)
+			 __field(__s8, init_qp_minus26)
+			 __field(__u8, diff_cu_qp_delta_depth)
+			 __field(__s8, pps_cb_qp_offset)
+			 __field(__s8, pps_cr_qp_offset)
+			 __field(__u8, num_tile_columns_minus1)
+			 __field(__u8, num_tile_rows_minus1)
+			 __array(__u8, column_width_minus1, 20)
+			 __array(__u8, row_height_minus1, 22)
+			 __field(__s8, pps_beta_offset_div2)
+			 __field(__s8, pps_tc_offset_div2)
+			 __field(__u8, log2_parallel_merge_level_minus2)
+			 __field(__u64, flags)),
+	TP_fast_assign(__entry->pic_parameter_set_id = p->pic_parameter_set_id;
+		       __entry->num_extra_slice_header_bits = p->num_extra_slice_header_bits;
+		       __entry->num_ref_idx_l0_default_active_minus1 =
+				p->num_ref_idx_l0_default_active_minus1;
+		       __entry->num_ref_idx_l1_default_active_minus1 =
+				p->num_ref_idx_l1_default_active_minus1;
+		       __entry->init_qp_minus26 = p->init_qp_minus26;
+		       __entry->diff_cu_qp_delta_depth = p->diff_cu_qp_delta_depth;
+		       __entry->pps_cb_qp_offset = p->pps_cb_qp_offset;
+		       __entry->pps_cr_qp_offset = p->pps_cr_qp_offset;
+		       __entry->num_tile_columns_minus1 = p->num_tile_columns_minus1;
+		       __entry->num_tile_rows_minus1 = p->num_tile_rows_minus1;
+		       memcpy(__entry->column_width_minus1, p->column_width_minus1,
+			      sizeof(__entry->column_width_minus1));
+		       memcpy(__entry->row_height_minus1, p->row_height_minus1,
+			      sizeof(__entry->row_height_minus1));
+		       __entry->pps_beta_offset_div2 = p->pps_beta_offset_div2;
+		       __entry->pps_tc_offset_div2 = p->pps_tc_offset_div2;
+		       __entry->log2_parallel_merge_level_minus2 =
+				p->log2_parallel_merge_level_minus2;
+		       __entry->flags = p->flags;),
 	TP_printk("\npic_parameter_set_id %u\n"
 		  "num_extra_slice_header_bits %u\n"
 		  "num_ref_idx_l0_default_active_minus1 %u\n"
@@ -783,45 +1268,52 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 		  "pps_tc_offset_div2 %d\n"
 		  "log2_parallel_merge_level_minus2 %u\n"
 		  "flags %s",
-		  __entry->p.pic_parameter_set_id,
-		  __entry->p.num_extra_slice_header_bits,
-		  __entry->p.num_ref_idx_l0_default_active_minus1,
-		  __entry->p.num_ref_idx_l1_default_active_minus1,
-		  __entry->p.init_qp_minus26,
-		  __entry->p.diff_cu_qp_delta_depth,
-		  __entry->p.pps_cb_qp_offset,
-		  __entry->p.pps_cr_qp_offset,
-		  __entry->p.num_tile_columns_minus1,
-		  __entry->p.num_tile_rows_minus1,
-		  __print_array(__entry->p.column_width_minus1,
-				ARRAY_SIZE(__entry->p.column_width_minus1),
-				sizeof(__entry->p.column_width_minus1[0])),
-		  __print_array(__entry->p.row_height_minus1,
-				ARRAY_SIZE(__entry->p.row_height_minus1),
-				sizeof(__entry->p.row_height_minus1[0])),
-		  __entry->p.pps_beta_offset_div2,
-		  __entry->p.pps_tc_offset_div2,
-		  __entry->p.log2_parallel_merge_level_minus2,
-		  __print_flags(__entry->p.flags, "|",
-		  {V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED, "DEPENDENT_SLICE_SEGMENT_ENABLED"},
+		  __entry->pic_parameter_set_id,
+		  __entry->num_extra_slice_header_bits,
+		  __entry->num_ref_idx_l0_default_active_minus1,
+		  __entry->num_ref_idx_l1_default_active_minus1,
+		  __entry->init_qp_minus26,
+		  __entry->diff_cu_qp_delta_depth,
+		  __entry->pps_cb_qp_offset,
+		  __entry->pps_cr_qp_offset,
+		  __entry->num_tile_columns_minus1,
+		  __entry->num_tile_rows_minus1,
+		  __print_array(__entry->column_width_minus1,
+				ARRAY_SIZE(__entry->column_width_minus1),
+				sizeof(__entry->column_width_minus1[0])),
+		  __print_array(__entry->row_height_minus1,
+				ARRAY_SIZE(__entry->row_height_minus1),
+				sizeof(__entry->row_height_minus1[0])),
+		  __entry->pps_beta_offset_div2,
+		  __entry->pps_tc_offset_div2,
+		  __entry->log2_parallel_merge_level_minus2,
+		  __print_flags(__entry->flags, "|",
+		  {V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED,
+		   "DEPENDENT_SLICE_SEGMENT_ENABLED"},
 		  {V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT, "OUTPUT_FLAG_PRESENT"},
 		  {V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED, "SIGN_DATA_HIDING_ENABLED"},
 		  {V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT, "CABAC_INIT_PRESENT"},
 		  {V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED, "CONSTRAINED_INTRA_PRED"},
 		  {V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED, "CU_QP_DELTA_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT, "PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT,
+		   "PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT"},
 		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED, "WEIGHTED_PRED"},
 		  {V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED, "WEIGHTED_BIPRED"},
 		  {V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, "TRANSQUANT_BYPASS_ENABLED"},
 		  {V4L2_HEVC_PPS_FLAG_TILES_ENABLED, "TILES_ENABLED"},
 		  {V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, "ENTROPY_CODING_SYNC_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, "LOOP_FILTER_ACROSS_TILES_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, "PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
-		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED, "DEBLOCKING_FILTER_OVERRIDE_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED,
+		   "LOOP_FILTER_ACROSS_TILES_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED,
+		   "PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED,
+		   "DEBLOCKING_FILTER_OVERRIDE_ENABLED"},
 		  {V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER, "DISABLE_DEBLOCKING_FILTER"},
 		  {V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT, "LISTS_MODIFICATION_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT, "SLICE_SEGMENT_HEADER_EXTENSION_PRESENT"},
-		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT, "DEBLOCKING_FILTER_CONTROL_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT,
+		   "SLICE_SEGMENT_HEADER_EXTENSION_PRESENT"},
+		  {V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT,
+		   "DEBLOCKING_FILTER_CONTROL_PRESENT"},
 		  {V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING, "UNIFORM_SPACING"}
 	))
 
@@ -832,8 +1324,60 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_slice_params, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__field(__u32, bit_size)
+			 __field(__u32, data_byte_offset)
+			 __field(__u32, num_entry_point_offsets)
+			 __field(__u8, nal_unit_type)
+			 __field(__u8, nuh_temporal_id_plus1)
+			 __field(__u8, slice_type)
+			 __field(__u8, colour_plane_id)
+			 __field(__s32, slice_pic_order_cnt)
+			 __field(__u8, num_ref_idx_l0_active_minus1)
+			 __field(__u8, num_ref_idx_l1_active_minus1)
+			 __field(__u8, collocated_ref_idx)
+			 __field(__u8, five_minus_max_num_merge_cand)
+			 __field(__s8, slice_qp_delta)
+			 __field(__s8, slice_cb_qp_offset)
+			 __field(__s8, slice_cr_qp_offset)
+			 __field(__s8, slice_act_y_qp_offset)
+			 __field(__s8, slice_act_cb_qp_offset)
+			 __field(__s8, slice_act_cr_qp_offset)
+			 __field(__s8, slice_beta_offset_div2)
+			 __field(__s8, slice_tc_offset_div2)
+			 __field(__u8, pic_struct)
+			 __field(__u32, slice_segment_addr)
+			 __array(__u8, ref_idx_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__u8, ref_idx_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __field(__u16, short_term_ref_pic_set_size)
+			 __field(__u16, long_term_ref_pic_set_size)
+			 __field(__u64, flags)),
+	TP_fast_assign(__entry->bit_size = s->bit_size;
+		       __entry->data_byte_offset = s->data_byte_offset;
+		       __entry->num_entry_point_offsets = s->num_entry_point_offsets;
+		       __entry->nal_unit_type = s->nal_unit_type;
+		       __entry->nuh_temporal_id_plus1 = s->nuh_temporal_id_plus1;
+		       __entry->slice_type = s->slice_type;
+		       __entry->colour_plane_id = s->colour_plane_id;
+		       __entry->slice_pic_order_cnt = s->slice_pic_order_cnt;
+		       __entry->num_ref_idx_l0_active_minus1 = s->num_ref_idx_l0_active_minus1;
+		       __entry->num_ref_idx_l1_active_minus1 = s->num_ref_idx_l1_active_minus1;
+		       __entry->collocated_ref_idx = s->collocated_ref_idx;
+		       __entry->five_minus_max_num_merge_cand = s->five_minus_max_num_merge_cand;
+		       __entry->slice_qp_delta = s->slice_qp_delta;
+		       __entry->slice_cb_qp_offset = s->slice_cb_qp_offset;
+		       __entry->slice_cr_qp_offset = s->slice_cr_qp_offset;
+		       __entry->slice_act_y_qp_offset = s->slice_act_y_qp_offset;
+		       __entry->slice_act_cb_qp_offset = s->slice_act_cb_qp_offset;
+		       __entry->slice_act_cr_qp_offset = s->slice_act_cr_qp_offset;
+		       __entry->slice_beta_offset_div2 = s->slice_beta_offset_div2;
+		       __entry->slice_tc_offset_div2 = s->slice_tc_offset_div2;
+		       __entry->pic_struct = s->pic_struct;
+		       __entry->slice_segment_addr = s->slice_segment_addr;
+		       memcpy(__entry->ref_idx_l0, s->ref_idx_l0, sizeof(__entry->ref_idx_l0));
+		       memcpy(__entry->ref_idx_l1, s->ref_idx_l1, sizeof(__entry->ref_idx_l1));
+		       __entry->short_term_ref_pic_set_size = s->short_term_ref_pic_set_size;
+		       __entry->long_term_ref_pic_set_size = s->long_term_ref_pic_set_size;
+		       __entry->flags = s->flags;),
 	TP_printk("\nbit_size %u\n"
 		  "data_byte_offset %u\n"
 		  "num_entry_point_offsets %u\n"
@@ -861,46 +1405,49 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 		  "short_term_ref_pic_set_size %u\n"
 		  "long_term_ref_pic_set_size %u\n"
 		  "flags %s",
-		  __entry->s.bit_size,
-		  __entry->s.data_byte_offset,
-		  __entry->s.num_entry_point_offsets,
-		  __entry->s.nal_unit_type,
-		  __entry->s.nuh_temporal_id_plus1,
-		  __entry->s.slice_type,
-		  __entry->s.colour_plane_id,
-		  __entry->s.slice_pic_order_cnt,
-		  __entry->s.num_ref_idx_l0_active_minus1,
-		  __entry->s.num_ref_idx_l1_active_minus1,
-		  __entry->s.collocated_ref_idx,
-		  __entry->s.five_minus_max_num_merge_cand,
-		  __entry->s.slice_qp_delta,
-		  __entry->s.slice_cb_qp_offset,
-		  __entry->s.slice_cr_qp_offset,
-		  __entry->s.slice_act_y_qp_offset,
-		  __entry->s.slice_act_cb_qp_offset,
-		  __entry->s.slice_act_cr_qp_offset,
-		  __entry->s.slice_beta_offset_div2,
-		  __entry->s.slice_tc_offset_div2,
-		  __entry->s.pic_struct,
-		  __entry->s.slice_segment_addr,
-		  __print_array(__entry->s.ref_idx_l0,
-				ARRAY_SIZE(__entry->s.ref_idx_l0),
-				sizeof(__entry->s.ref_idx_l0[0])),
-		  __print_array(__entry->s.ref_idx_l1,
-				ARRAY_SIZE(__entry->s.ref_idx_l1),
-				sizeof(__entry->s.ref_idx_l1[0])),
-		  __entry->s.short_term_ref_pic_set_size,
-		  __entry->s.long_term_ref_pic_set_size,
-		  __print_flags(__entry->s.flags, "|",
+		  __entry->bit_size,
+		  __entry->data_byte_offset,
+		  __entry->num_entry_point_offsets,
+		  __entry->nal_unit_type,
+		  __entry->nuh_temporal_id_plus1,
+		  __entry->slice_type,
+		  __entry->colour_plane_id,
+		  __entry->slice_pic_order_cnt,
+		  __entry->num_ref_idx_l0_active_minus1,
+		  __entry->num_ref_idx_l1_active_minus1,
+		  __entry->collocated_ref_idx,
+		  __entry->five_minus_max_num_merge_cand,
+		  __entry->slice_qp_delta,
+		  __entry->slice_cb_qp_offset,
+		  __entry->slice_cr_qp_offset,
+		  __entry->slice_act_y_qp_offset,
+		  __entry->slice_act_cb_qp_offset,
+		  __entry->slice_act_cr_qp_offset,
+		  __entry->slice_beta_offset_div2,
+		  __entry->slice_tc_offset_div2,
+		  __entry->pic_struct,
+		  __entry->slice_segment_addr,
+		  __print_array(__entry->ref_idx_l0,
+				ARRAY_SIZE(__entry->ref_idx_l0),
+				sizeof(__entry->ref_idx_l0[0])),
+		  __print_array(__entry->ref_idx_l1,
+				ARRAY_SIZE(__entry->ref_idx_l1),
+				sizeof(__entry->ref_idx_l1[0])),
+		  __entry->short_term_ref_pic_set_size,
+		  __entry->long_term_ref_pic_set_size,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA, "SLICE_SAO_LUMA"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA, "SLICE_SAO_CHROMA"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED, "SLICE_TEMPORAL_MVP_ENABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED,
+		   "SLICE_TEMPORAL_MVP_ENABLED"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO, "MVD_L1_ZERO"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT, "CABAC_INIT"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0, "COLLOCATED_FROM_L0"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV, "USE_INTEGER_MV"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, "SLICE_DEBLOCKING_FILTER_DISABLED"},
-		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, "SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED,
+		   "SLICE_DEBLOCKING_FILTER_DISABLED"},
+		  {V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED,
+		   "SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED"},
 		  {V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, "DEPENDENT_SLICE_SEGMENT"}
 
 	))
@@ -909,8 +1456,35 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_pred_weight_table, p)),
-	TP_fast_assign(__entry->p = *p),
+	TP_STRUCT__entry(__array(__s8, delta_luma_weight_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__s8, luma_offset_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__s8, delta_chroma_weight_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
+			 __array(__s8, chroma_offset_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
+			 __array(__s8, delta_luma_weight_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__s8, luma_offset_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__s8, delta_chroma_weight_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
+			 __array(__s8, chroma_offset_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
+			 __field(__u8, luma_log2_weight_denom)
+			 __field(__s8, delta_chroma_log2_weight_denom)),
+	TP_fast_assign(memcpy(__entry->delta_luma_weight_l0, p->delta_luma_weight_l0,
+			      sizeof(__entry->delta_luma_weight_l0));
+		       memcpy(__entry->luma_offset_l0, p->luma_offset_l0,
+			      sizeof(__entry->luma_offset_l0));
+		       memcpy(__entry->delta_chroma_weight_l0, p->delta_chroma_weight_l0,
+			      sizeof(__entry->delta_chroma_weight_l0));
+		       memcpy(__entry->chroma_offset_l0, p->chroma_offset_l0,
+			      sizeof(__entry->chroma_offset_l0));
+		       memcpy(__entry->delta_luma_weight_l1, p->delta_luma_weight_l1,
+			      sizeof(__entry->delta_luma_weight_l1));
+		       memcpy(__entry->luma_offset_l1, p->luma_offset_l1,
+			      sizeof(__entry->luma_offset_l1));
+		       memcpy(__entry->delta_chroma_weight_l1, p->delta_chroma_weight_l1,
+			      sizeof(__entry->delta_chroma_weight_l1));
+		       memcpy(__entry->chroma_offset_l1, p->chroma_offset_l1,
+			      sizeof(__entry->chroma_offset_l1));
+		       __entry->luma_log2_weight_denom = p->luma_log2_weight_denom;
+		       __entry->delta_chroma_log2_weight_denom =
+				p->delta_chroma_log2_weight_denom;),
 	TP_printk("\ndelta_luma_weight_l0 %s\n"
 		  "luma_offset_l0 %s\n"
 		  "delta_chroma_weight_l0 {%s}\n"
@@ -921,44 +1495,62 @@ DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 		  "chroma_offset_l1 {%s}\n"
 		  "luma_log2_weight_denom %d\n"
 		  "delta_chroma_log2_weight_denom %d\n",
-		  __print_array(__entry->p.delta_luma_weight_l0,
-				ARRAY_SIZE(__entry->p.delta_luma_weight_l0),
-				sizeof(__entry->p.delta_luma_weight_l0[0])),
-		  __print_array(__entry->p.luma_offset_l0,
-				ARRAY_SIZE(__entry->p.luma_offset_l0),
-				sizeof(__entry->p.luma_offset_l0[0])),
+		  __print_array(__entry->delta_luma_weight_l0,
+				ARRAY_SIZE(__entry->delta_luma_weight_l0),
+				sizeof(__entry->delta_luma_weight_l0[0])),
+		  __print_array(__entry->luma_offset_l0,
+				ARRAY_SIZE(__entry->luma_offset_l0),
+				sizeof(__entry->luma_offset_l0[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.delta_chroma_weight_l0,
-				   sizeof(__entry->p.delta_chroma_weight_l0),
+				   __entry->delta_chroma_weight_l0,
+				   sizeof(__entry->delta_chroma_weight_l0),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.chroma_offset_l0,
-				   sizeof(__entry->p.chroma_offset_l0),
+				   __entry->chroma_offset_l0,
+				   sizeof(__entry->chroma_offset_l0),
 				   false),
-		  __print_array(__entry->p.delta_luma_weight_l1,
-				ARRAY_SIZE(__entry->p.delta_luma_weight_l1),
-				sizeof(__entry->p.delta_luma_weight_l1[0])),
-		  __print_array(__entry->p.luma_offset_l1,
-				ARRAY_SIZE(__entry->p.luma_offset_l1),
-				sizeof(__entry->p.luma_offset_l1[0])),
+		  __print_array(__entry->delta_luma_weight_l1,
+				ARRAY_SIZE(__entry->delta_luma_weight_l1),
+				sizeof(__entry->delta_luma_weight_l1[0])),
+		  __print_array(__entry->luma_offset_l1,
+				ARRAY_SIZE(__entry->luma_offset_l1),
+				sizeof(__entry->luma_offset_l1[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.delta_chroma_weight_l1,
-				   sizeof(__entry->p.delta_chroma_weight_l1),
+				   __entry->delta_chroma_weight_l1,
+				   sizeof(__entry->delta_chroma_weight_l1),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.chroma_offset_l1,
-				   sizeof(__entry->p.chroma_offset_l1),
+				   __entry->chroma_offset_l1,
+				   sizeof(__entry->chroma_offset_l1),
 				   false),
-		__entry->p.luma_log2_weight_denom,
-		__entry->p.delta_chroma_log2_weight_denom
+		__entry->luma_log2_weight_denom,
+		__entry->delta_chroma_log2_weight_denom
 
 	))
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_scaling_matrix, s)),
-	TP_fast_assign(__entry->s = *s),
+	TP_STRUCT__entry(__array(__u8, scaling_list_4x4, 6 * 16)
+			 __array(__u8, scaling_list_8x8, 6 * 64)
+			 __array(__u8, scaling_list_16x16, 6 * 64)
+			 __array(__u8, scaling_list_32x32, 2 * 64)
+			 __array(__u8, scaling_list_dc_coef_16x16, 6)
+			 __array(__u8, scaling_list_dc_coef_32x32, 2)),
+	TP_fast_assign(memcpy(__entry->scaling_list_4x4,
+			      s->scaling_list_4x4, sizeof(__entry->scaling_list_4x4));
+		       memcpy(__entry->scaling_list_8x8,
+			      s->scaling_list_8x8, sizeof(__entry->scaling_list_8x8));
+		       memcpy(__entry->scaling_list_16x16,
+			      s->scaling_list_16x16, sizeof(__entry->scaling_list_16x16));
+		       memcpy(__entry->scaling_list_32x32,
+			      s->scaling_list_32x32, sizeof(__entry->scaling_list_32x32));
+		       memcpy(__entry->scaling_list_dc_coef_16x16,
+			      s->scaling_list_dc_coef_16x16,
+			      sizeof(__entry->scaling_list_dc_coef_16x16));
+		       memcpy(__entry->scaling_list_dc_coef_32x32,
+			      s->scaling_list_dc_coef_32x32,
+			      sizeof(__entry->scaling_list_dc_coef_32x32));),
 	TP_printk("\nscaling_list_4x4 {%s}\n"
 		  "scaling_list_8x8 {%s}\n"
 		  "scaling_list_16x16 {%s}\n"
@@ -966,34 +1558,56 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
 		  "scaling_list_dc_coef_16x16 %s\n"
 		  "scaling_list_dc_coef_32x32 %s\n",
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_4x4,
-				   sizeof(__entry->s.scaling_list_4x4),
+				   __entry->scaling_list_4x4,
+				   sizeof(__entry->scaling_list_4x4),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_8x8,
-				   sizeof(__entry->s.scaling_list_8x8),
+				   __entry->scaling_list_8x8,
+				   sizeof(__entry->scaling_list_8x8),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_16x16,
-				   sizeof(__entry->s.scaling_list_16x16),
+				   __entry->scaling_list_16x16,
+				   sizeof(__entry->scaling_list_16x16),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->s.scaling_list_32x32,
-				   sizeof(__entry->s.scaling_list_32x32),
+				   __entry->scaling_list_32x32,
+				   sizeof(__entry->scaling_list_32x32),
 				   false),
-		  __print_array(__entry->s.scaling_list_dc_coef_16x16,
-				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_16x16),
-				sizeof(__entry->s.scaling_list_dc_coef_16x16[0])),
-		  __print_array(__entry->s.scaling_list_dc_coef_32x32,
-				ARRAY_SIZE(__entry->s.scaling_list_dc_coef_32x32),
-				sizeof(__entry->s.scaling_list_dc_coef_32x32[0]))
+		  __print_array(__entry->scaling_list_dc_coef_16x16,
+				ARRAY_SIZE(__entry->scaling_list_dc_coef_16x16),
+				sizeof(__entry->scaling_list_dc_coef_16x16[0])),
+		  __print_array(__entry->scaling_list_dc_coef_32x32,
+				ARRAY_SIZE(__entry->scaling_list_dc_coef_32x32),
+				sizeof(__entry->scaling_list_dc_coef_32x32[0]))
 	))
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
 	TP_ARGS(d),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_hevc_decode_params, d)),
-	TP_fast_assign(__entry->d = *d),
+	TP_STRUCT__entry(__field(__s32, pic_order_cnt_val)
+			 __field(__u16, short_term_ref_pic_set_size)
+			 __field(__u16, long_term_ref_pic_set_size)
+			 __field(__u8, num_active_dpb_entries)
+			 __field(__u8, num_poc_st_curr_before)
+			 __field(__u8, num_poc_st_curr_after)
+			 __field(__u8, num_poc_lt_curr)
+			 __array(__u8, poc_st_curr_before, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__u8, poc_st_curr_after, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __array(__u8, poc_lt_curr, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+			 __field(__u64, flags)),
+	TP_fast_assign(__entry->pic_order_cnt_val = d->pic_order_cnt_val;
+		       __entry->short_term_ref_pic_set_size = d->short_term_ref_pic_set_size;
+		       __entry->long_term_ref_pic_set_size = d->long_term_ref_pic_set_size;
+		       __entry->num_active_dpb_entries = d->num_active_dpb_entries;
+		       __entry->num_poc_st_curr_before = d->num_poc_st_curr_before;
+		       __entry->num_poc_st_curr_after = d->num_poc_st_curr_after;
+		       __entry->num_poc_lt_curr = d->num_poc_lt_curr;
+		       memcpy(__entry->poc_st_curr_before, d->poc_st_curr_before,
+			      sizeof(__entry->poc_st_curr_before));
+		       memcpy(__entry->poc_st_curr_after, d->poc_st_curr_after,
+			      sizeof(__entry->poc_st_curr_after));
+		       memcpy(__entry->poc_lt_curr, d->poc_lt_curr, sizeof(__entry->poc_lt_curr));
+		       __entry->flags = d->flags;),
 	TP_printk("\npic_order_cnt_val %d\n"
 		  "short_term_ref_pic_set_size %u\n"
 		  "long_term_ref_pic_set_size %u\n"
@@ -1005,23 +1619,23 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 		  "poc_st_curr_after %s\n"
 		  "poc_lt_curr %s\n"
 		  "flags %s",
-		  __entry->d.pic_order_cnt_val,
-		  __entry->d.short_term_ref_pic_set_size,
-		  __entry->d.long_term_ref_pic_set_size,
-		  __entry->d.num_active_dpb_entries,
-		  __entry->d.num_poc_st_curr_before,
-		  __entry->d.num_poc_st_curr_after,
-		  __entry->d.num_poc_lt_curr,
-		  __print_array(__entry->d.poc_st_curr_before,
-				ARRAY_SIZE(__entry->d.poc_st_curr_before),
-				sizeof(__entry->d.poc_st_curr_before[0])),
-		  __print_array(__entry->d.poc_st_curr_after,
-				ARRAY_SIZE(__entry->d.poc_st_curr_after),
-				sizeof(__entry->d.poc_st_curr_after[0])),
-		  __print_array(__entry->d.poc_lt_curr,
-				ARRAY_SIZE(__entry->d.poc_lt_curr),
-				sizeof(__entry->d.poc_lt_curr[0])),
-		  __print_flags(__entry->d.flags, "|",
+		  __entry->pic_order_cnt_val,
+		  __entry->short_term_ref_pic_set_size,
+		  __entry->long_term_ref_pic_set_size,
+		  __entry->num_active_dpb_entries,
+		  __entry->num_poc_st_curr_before,
+		  __entry->num_poc_st_curr_after,
+		  __entry->num_poc_lt_curr,
+		  __print_array(__entry->poc_st_curr_before,
+				ARRAY_SIZE(__entry->poc_st_curr_before),
+				sizeof(__entry->poc_st_curr_before[0])),
+		  __print_array(__entry->poc_st_curr_after,
+				ARRAY_SIZE(__entry->poc_st_curr_after),
+				sizeof(__entry->poc_st_curr_after[0])),
+		  __print_array(__entry->poc_lt_curr,
+				ARRAY_SIZE(__entry->poc_lt_curr),
+				sizeof(__entry->poc_lt_curr[0])),
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC, "IRAP_PIC"},
 		  {V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC, "IDR_PIC"},
 		  {V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR, "NO_OUTPUT_OF_PRIOR"}
@@ -1031,22 +1645,44 @@ 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_STRUCT__entry(__field(__u8, flags)
+			 __field(__u32, lt_ref_pic_poc_lsb_sps)),
+	TP_fast_assign(__entry->flags = lt->flags;
+		       __entry->lt_ref_pic_poc_lsb_sps = lt->lt_ref_pic_poc_lsb_sps;),
 	TP_printk("\nflags %s\n"
 		  "lt_ref_pic_poc_lsb_sps %x\n",
-		  __print_flags(__entry->lt.flags, "|",
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT, "USED_LT"}
 		  ),
-		  __entry->lt.lt_ref_pic_poc_lsb_sps
+		  __entry->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_STRUCT__entry(__field(__u8, flags)
+			 __field(__u8, delta_idx_minus1)
+			 __field(__u8, delta_rps_sign)
+			 __field(__u16, abs_delta_rps_minus1)
+			 __field(__u8, num_negative_pics)
+			 __field(__u8, num_positive_pics)
+			 __field(__u32, used_by_curr_pic)
+			 __field(__u32, use_delta_flag)
+			 __array(__u32, delta_poc_s0_minus1, 16)
+			 __array(__u32, delta_poc_s1_minus1, 16)),
+	TP_fast_assign(__entry->flags = st->flags;
+		       __entry->delta_idx_minus1 = st->delta_idx_minus1;
+		       __entry->delta_rps_sign = st->delta_rps_sign;
+		       __entry->abs_delta_rps_minus1 = st->abs_delta_rps_minus1;
+		       __entry->num_negative_pics = st->num_negative_pics;
+		       __entry->num_positive_pics = st->num_positive_pics;
+		       __entry->used_by_curr_pic = st->used_by_curr_pic;
+		       __entry->use_delta_flag = st->use_delta_flag;
+		       memcpy(__entry->delta_poc_s0_minus1, st->delta_poc_s0_minus1,
+			      sizeof(__entry->delta_poc_s0_minus1));
+		       memcpy(__entry->delta_poc_s1_minus1, st->delta_poc_s1_minus1,
+			      sizeof(__entry->delta_poc_s1_minus1));),
 	TP_printk("\nflags %s\n"
 		  "delta_idx_minus1: %u\n"
 		  "delta_rps_sign: %u\n"
@@ -1057,40 +1693,46 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
 		  "use_delta_flag: %08x\n"
 		  "delta_poc_s0_minus1: %s\n"
 		  "delta_poc_s1_minus1: %s\n",
-		  __print_flags(__entry->st.flags, "|",
+		  __print_flags(__entry->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]))
+		  __entry->delta_idx_minus1,
+		  __entry->delta_rps_sign,
+		  __entry->abs_delta_rps_minus1,
+		  __entry->num_negative_pics,
+		  __entry->num_positive_pics,
+		  __entry->used_by_curr_pic,
+		  __entry->use_delta_flag,
+		  __print_array(__entry->delta_poc_s0_minus1,
+				ARRAY_SIZE(__entry->delta_poc_s0_minus1),
+				sizeof(__entry->delta_poc_s0_minus1[0])),
+		  __print_array(__entry->delta_poc_s1_minus1,
+				ARRAY_SIZE(__entry->delta_poc_s1_minus1),
+				sizeof(__entry->delta_poc_s1_minus1[0]))
 	)
 );
 
 DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
 	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
 	TP_ARGS(e),
-	TP_STRUCT__entry(__field_struct(struct v4l2_hevc_dpb_entry, e)),
-	TP_fast_assign(__entry->e = *e),
+	TP_STRUCT__entry(__field(__u64, timestamp)
+			 __field(__u8, flags)
+			 __field(__u8, field_pic)
+			 __field(__s32, pic_order_cnt_val)),
+	TP_fast_assign(__entry->timestamp = e->timestamp;
+		       __entry->flags = e->flags;
+		       __entry->field_pic = e->field_pic;
+		       __entry->pic_order_cnt_val = e->pic_order_cnt_val;),
 	TP_printk("\ntimestamp %llu\n"
 		  "flags %s\n"
 		  "field_pic %u\n"
 		  "pic_order_cnt_val %d\n",
-		__entry->e.timestamp,
-		__print_flags(__entry->e.flags, "|",
+		__entry->timestamp,
+		__print_flags(__entry->flags, "|",
 		{V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE, "LONG_TERM_REFERENCE"}
 		  ),
-		__entry->e.field_pic,
-		__entry->e.pic_order_cnt_val
+		__entry->field_pic,
+		__entry->pic_order_cnt_val
 	))
 
 DEFINE_EVENT(v4l2_ctrl_hevc_sps_tmpl, v4l2_ctrl_hevc_sps,
@@ -1143,16 +1785,26 @@ DEFINE_EVENT(v4l2_hevc_dpb_entry_tmpl, v4l2_hevc_dpb_entry,
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
 	TP_ARGS(s),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_sequence, s)),
-	TP_fast_assign(__entry->s = *s;),
+	TP_STRUCT__entry(__field(__u16, horizontal_size)
+			 __field(__u16, vertical_size)
+			 __field(__u32, vbv_buffer_size)
+			 __field(__u16, profile_and_level_indication)
+			 __field(__u8, chroma_format)
+			 __field(__u8, flags)),
+	TP_fast_assign(__entry->horizontal_size = s->horizontal_size;
+		       __entry->vertical_size = s->vertical_size;
+		       __entry->vbv_buffer_size = s->vbv_buffer_size;
+		       __entry->profile_and_level_indication = s->profile_and_level_indication;
+		       __entry->chroma_format = s->chroma_format;
+		       __entry->flags = s->flags;),
 	TP_printk("\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
 		  "profile_and_level_indication %u\nchroma_format %u\nflags %s\n",
-		  __entry->s.horizontal_size,
-		  __entry->s.vertical_size,
-		  __entry->s.vbv_buffer_size,
-		  __entry->s.profile_and_level_indication,
-		  __entry->s.chroma_format,
-		  __print_flags(__entry->s.flags, "|",
+		  __entry->horizontal_size,
+		  __entry->vertical_size,
+		  __entry->vbv_buffer_size,
+		  __entry->profile_and_level_indication,
+		  __entry->chroma_format,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE, "PROGRESSIVE"})
 	)
 );
@@ -1160,13 +1812,25 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_picture, p)),
-	TP_fast_assign(__entry->p = *p;),
+	TP_STRUCT__entry(__field(__u64, backward_ref_ts)
+			 __field(__u64, forward_ref_ts)
+			 __field(__u32, flags)
+			 __array(__u8, f_code, 4)
+			 __field(__u8, picture_coding_type)
+			 __field(__u8, picture_structure)
+			 __field(__u8, intra_dc_precision)),
+	TP_fast_assign(__entry->backward_ref_ts = p->backward_ref_ts;
+		       __entry->forward_ref_ts = p->forward_ref_ts;
+		       __entry->flags = p->flags;
+		       memcpy(__entry->f_code, p->f_code, sizeof(__entry->f_code));
+		       __entry->picture_coding_type = p->picture_coding_type;
+		       __entry->picture_structure = p->picture_structure;
+		       __entry->intra_dc_precision = p->intra_dc_precision;),
 	TP_printk("\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
 		  "picture_coding_type: %u\npicture_structure %u\nintra_dc_precision %u\n",
-		  __entry->p.backward_ref_ts,
-		  __entry->p.forward_ref_ts,
-		  __print_flags(__entry->p.flags, "|",
+		  __entry->backward_ref_ts,
+		  __entry->forward_ref_ts,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST, "TOP_FIELD_FIRST"},
 		  {V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT, "FRAME_PRED_DCT"},
 		  {V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV, "CONCEALMENT_MV"},
@@ -1176,34 +1840,46 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
 		  {V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST, "REPEAT_FIRST"},
 		  {V4L2_MPEG2_PIC_FLAG_PROGRESSIVE, "PROGRESSIVE"}),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.f_code,
-				   sizeof(__entry->p.f_code),
+				   __entry->f_code,
+				   sizeof(__entry->f_code),
 				   false),
-		  __entry->p.picture_coding_type,
-		  __entry->p.picture_structure,
-		  __entry->p.intra_dc_precision
+		  __entry->picture_coding_type,
+		  __entry->picture_structure,
+		  __entry->intra_dc_precision
 	)
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
 	TP_ARGS(q),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_mpeg2_quantisation, q)),
-	TP_fast_assign(__entry->q = *q;),
+	TP_STRUCT__entry(__array(__u8, intra_quantiser_matrix, 64)
+			 __array(__u8, non_intra_quantiser_matrix, 64)
+			 __array(__u8, chroma_intra_quantiser_matrix, 64)
+			 __array(__u8, chroma_non_intra_quantiser_matrix, 64)),
+	TP_fast_assign(memcpy(__entry->intra_quantiser_matrix, q->intra_quantiser_matrix,
+			      sizeof(__entry->intra_quantiser_matrix));
+		       memcpy(__entry->non_intra_quantiser_matrix, q->non_intra_quantiser_matrix,
+			      sizeof(__entry->non_intra_quantiser_matrix));
+		       memcpy(__entry->chroma_intra_quantiser_matrix,
+			      q->chroma_intra_quantiser_matrix,
+			      sizeof(__entry->chroma_intra_quantiser_matrix));
+		       memcpy(__entry->chroma_non_intra_quantiser_matrix,
+			      q->chroma_non_intra_quantiser_matrix,
+			      sizeof(__entry->chroma_non_intra_quantiser_matrix));),
 	TP_printk("\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
 		  "chroma_intra_quantiser_matrix %s\nchroma_non_intra_quantiser_matrix %s\n",
-		  __print_array(__entry->q.intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.intra_quantiser_matrix),
-				sizeof(__entry->q.intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.non_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.non_intra_quantiser_matrix),
-				sizeof(__entry->q.non_intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.chroma_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.chroma_intra_quantiser_matrix),
-				sizeof(__entry->q.chroma_intra_quantiser_matrix[0])),
-		  __print_array(__entry->q.chroma_non_intra_quantiser_matrix,
-				ARRAY_SIZE(__entry->q.chroma_non_intra_quantiser_matrix),
-				sizeof(__entry->q.chroma_non_intra_quantiser_matrix[0]))
+		  __print_array(__entry->intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->intra_quantiser_matrix),
+				sizeof(__entry->intra_quantiser_matrix[0])),
+		  __print_array(__entry->non_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->non_intra_quantiser_matrix),
+				sizeof(__entry->non_intra_quantiser_matrix[0])),
+		  __print_array(__entry->chroma_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->chroma_intra_quantiser_matrix),
+				sizeof(__entry->chroma_intra_quantiser_matrix[0])),
+		  __print_array(__entry->chroma_non_intra_quantiser_matrix,
+				ARRAY_SIZE(__entry->chroma_non_intra_quantiser_matrix),
+				sizeof(__entry->chroma_non_intra_quantiser_matrix[0]))
 		  )
 )
 
@@ -1227,25 +1903,35 @@ DEFINE_EVENT(v4l2_ctrl_mpeg2_quant_tmpl, v4l2_ctrl_mpeg2_quantisation,
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
 	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
+	TP_STRUCT__entry(__array(__u8, entropy_coeff_probs, 4 * 8 * 3 * V4L2_VP8_COEFF_PROB_CNT)
+			 __array(__u8, entropy_y_mode_probs, 4)
+			 __array(__u8, entropy_uv_mode_probs, 3)
+			 __array(__u8, entropy_mv_probs, 2 * 19)),
+	TP_fast_assign(memcpy(__entry->entropy_coeff_probs, f->entropy.coeff_probs,
+			      sizeof(__entry->entropy_coeff_probs));
+		       memcpy(__entry->entropy_y_mode_probs, f->entropy.y_mode_probs,
+			      sizeof(__entry->entropy_y_mode_probs));
+		       memcpy(__entry->entropy_uv_mode_probs, f->entropy.uv_mode_probs,
+			      sizeof(__entry->entropy_uv_mode_probs));
+		       memcpy(__entry->entropy_mv_probs, f->entropy.mv_probs,
+			      sizeof(__entry->entropy_mv_probs));),
 	TP_printk("\nentropy.coeff_probs {%s}\n"
 		  "entropy.y_mode_probs %s\n"
 		  "entropy.uv_mode_probs %s\n"
 		  "entropy.mv_probs {%s}",
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.entropy.coeff_probs,
-				   sizeof(__entry->f.entropy.coeff_probs),
+				   __entry->entropy_coeff_probs,
+				   sizeof(__entry->entropy_coeff_probs),
 				   false),
-		  __print_array(__entry->f.entropy.y_mode_probs,
-				ARRAY_SIZE(__entry->f.entropy.y_mode_probs),
-				sizeof(__entry->f.entropy.y_mode_probs[0])),
-		  __print_array(__entry->f.entropy.uv_mode_probs,
-				ARRAY_SIZE(__entry->f.entropy.uv_mode_probs),
-				sizeof(__entry->f.entropy.uv_mode_probs[0])),
+		  __print_array(__entry->entropy_y_mode_probs,
+				ARRAY_SIZE(__entry->entropy_y_mode_probs),
+				sizeof(__entry->entropy_y_mode_probs[0])),
+		  __print_array(__entry->entropy_uv_mode_probs,
+				ARRAY_SIZE(__entry->entropy_uv_mode_probs),
+				sizeof(__entry->entropy_uv_mode_probs[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.entropy.mv_probs,
-				   sizeof(__entry->f.entropy.mv_probs),
+				   __entry->entropy_mv_probs,
+				   sizeof(__entry->entropy_mv_probs),
 				   false)
 		  )
 )
@@ -1253,8 +1939,82 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
 	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp8_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
+	TP_STRUCT__entry(__array(__s8, segment_quant_update, 4)
+			 __array(__s8, segment_lf_update, 4)
+			 __array(__u8, segment_segment_probs, 3)
+			 __field(__u32, segment_flags)
+			 __array(__s8, lf_ref_frm_delta, 4)
+			 __array(__s8, lf_mb_mode_delta, 4)
+			 __field(__u8, lf_sharpness_level)
+			 __field(__u8, lf_level)
+			 __field(__u32, lf_flags)
+			 __field(__u8, quant_y_ac_qi)
+			 __field(__s8, quant_y_dc_delta)
+			 __field(__s8, quant_y2_dc_delta)
+			 __field(__s8, quant_y2_ac_delta)
+			 __field(__s8, quant_uv_dc_delta)
+			 __field(__s8, quant_uv_ac_delta)
+			 __field(__u8, coder_state_range)
+			 __field(__u8, coder_state_value)
+			 __field(__u8, coder_state_bit_count)
+			 __field(__u16, width)
+			 __field(__u16, height)
+			 __field(__u8, horizontal_scale)
+			 __field(__u8, vertical_scale)
+			 __field(__u8, version)
+			 __field(__u8, prob_skip_false)
+			 __field(__u8, prob_intra)
+			 __field(__u8, prob_last)
+			 __field(__u8, prob_gf)
+			 __field(__u8, num_dct_parts)
+			 __field(__u32, first_part_size)
+			 __field(__u32, first_part_header_bits)
+			 __array(__u32, dct_part_sizes, 8)
+			 __field(__u64, last_frame_ts)
+			 __field(__u64, golden_frame_ts)
+			 __field(__u64, alt_frame_ts)
+			 __field(__u64, flags)),
+	TP_fast_assign(memcpy(__entry->segment_quant_update, f->segment.quant_update,
+			      sizeof(__entry->segment_quant_update));
+		       memcpy(__entry->segment_lf_update, f->segment.lf_update,
+			      sizeof(__entry->segment_lf_update));
+		       memcpy(__entry->segment_segment_probs, f->segment.segment_probs,
+			      sizeof(__entry->segment_segment_probs));
+		       __entry->segment_flags = f->segment.flags;
+		       memcpy(__entry->lf_ref_frm_delta, f->lf.ref_frm_delta,
+			      sizeof(__entry->lf_ref_frm_delta));
+		       memcpy(__entry->lf_mb_mode_delta, f->lf.mb_mode_delta,
+			      sizeof(__entry->lf_mb_mode_delta));
+		       __entry->lf_sharpness_level = f->lf.sharpness_level;
+		       __entry->lf_level = f->lf.level;
+		       __entry->lf_flags = f->lf.flags;
+		       __entry->quant_y_ac_qi = f->quant.y_ac_qi;
+		       __entry->quant_y_dc_delta = f->quant.y_dc_delta;
+		       __entry->quant_y2_dc_delta = f->quant.y2_dc_delta;
+		       __entry->quant_y2_ac_delta = f->quant.y2_ac_delta;
+		       __entry->quant_uv_dc_delta = f->quant.uv_dc_delta;
+		       __entry->quant_uv_ac_delta = f->quant.uv_ac_delta;
+		       __entry->coder_state_range = f->coder_state.range;
+		       __entry->coder_state_value = f->coder_state.value;
+		       __entry->coder_state_bit_count = f->coder_state.bit_count;
+		       __entry->width = f->width;
+		       __entry->height = f->height;
+		       __entry->horizontal_scale = f->horizontal_scale;
+		       __entry->vertical_scale = f->vertical_scale;
+		       __entry->version = f->version;
+		       __entry->prob_skip_false = f->prob_skip_false;
+		       __entry->prob_intra = f->prob_intra;
+		       __entry->prob_last = f->prob_last;
+		       __entry->prob_gf = f->prob_gf;
+		       __entry->num_dct_parts = f->num_dct_parts;
+		       __entry->first_part_size = f->first_part_size;
+		       __entry->first_part_header_bits = f->first_part_header_bits;
+		       memcpy(__entry->dct_part_sizes, f->dct_part_sizes,
+			      sizeof(__entry->dct_part_sizes));
+		       __entry->last_frame_ts = f->last_frame_ts;
+		       __entry->golden_frame_ts = f->golden_frame_ts;
+		       __entry->alt_frame_ts = f->alt_frame_ts;
+		       __entry->flags = f->flags;),
 	TP_printk("\nsegment.quant_update %s\n"
 		  "segment.lf_update %s\n"
 		  "segment.segment_probs %s\n"
@@ -1290,60 +2050,60 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 		  "golden_frame_ts %llu\n"
 		  "alt_frame_ts %llu\n"
 		  "flags %s",
-		  __print_array(__entry->f.segment.quant_update,
-				ARRAY_SIZE(__entry->f.segment.quant_update),
-				sizeof(__entry->f.segment.quant_update[0])),
-		  __print_array(__entry->f.segment.lf_update,
-				ARRAY_SIZE(__entry->f.segment.lf_update),
-				sizeof(__entry->f.segment.lf_update[0])),
-		  __print_array(__entry->f.segment.segment_probs,
-				ARRAY_SIZE(__entry->f.segment.segment_probs),
-				sizeof(__entry->f.segment.segment_probs[0])),
-		  __print_flags(__entry->f.segment.flags, "|",
+		  __print_array(__entry->segment_quant_update,
+				ARRAY_SIZE(__entry->segment_quant_update),
+				sizeof(__entry->segment_quant_update[0])),
+		  __print_array(__entry->segment_lf_update,
+				ARRAY_SIZE(__entry->segment_lf_update),
+				sizeof(__entry->segment_lf_update[0])),
+		  __print_array(__entry->segment_segment_probs,
+				ARRAY_SIZE(__entry->segment_segment_probs),
+				sizeof(__entry->segment_segment_probs[0])),
+		  __print_flags(__entry->segment_flags, "|",
 		  {V4L2_VP8_SEGMENT_FLAG_ENABLED, "SEGMENT_ENABLED"},
 		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP, "SEGMENT_UPDATE_MAP"},
 		  {V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA, "SEGMENT_UPDATE_FEATURE_DATA"},
 		  {V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE, "SEGMENT_DELTA_VALUE_MODE"}),
-		  __print_array(__entry->f.lf.ref_frm_delta,
-				ARRAY_SIZE(__entry->f.lf.ref_frm_delta),
-				sizeof(__entry->f.lf.ref_frm_delta[0])),
-		  __print_array(__entry->f.lf.mb_mode_delta,
-				ARRAY_SIZE(__entry->f.lf.mb_mode_delta),
-				sizeof(__entry->f.lf.mb_mode_delta[0])),
-		  __entry->f.lf.sharpness_level,
-		  __entry->f.lf.level,
-		  __print_flags(__entry->f.lf.flags, "|",
+		  __print_array(__entry->lf_ref_frm_delta,
+				ARRAY_SIZE(__entry->lf_ref_frm_delta),
+				sizeof(__entry->lf_ref_frm_delta[0])),
+		  __print_array(__entry->lf_mb_mode_delta,
+				ARRAY_SIZE(__entry->lf_mb_mode_delta),
+				sizeof(__entry->lf_mb_mode_delta[0])),
+		  __entry->lf_sharpness_level,
+		  __entry->lf_level,
+		  __print_flags(__entry->lf_flags, "|",
 		  {V4L2_VP8_LF_ADJ_ENABLE, "LF_ADJ_ENABLED"},
 		  {V4L2_VP8_LF_DELTA_UPDATE, "LF_DELTA_UPDATE"},
 		  {V4L2_VP8_LF_FILTER_TYPE_SIMPLE, "LF_FILTER_TYPE_SIMPLE"}),
-		  __entry->f.quant.y_ac_qi,
-		  __entry->f.quant.y_dc_delta,
-		  __entry->f.quant.y2_dc_delta,
-		  __entry->f.quant.y2_ac_delta,
-		  __entry->f.quant.uv_dc_delta,
-		  __entry->f.quant.uv_ac_delta,
-		  __entry->f.coder_state.range,
-		  __entry->f.coder_state.value,
-		  __entry->f.coder_state.bit_count,
-		  __entry->f.width,
-		  __entry->f.height,
-		  __entry->f.horizontal_scale,
-		  __entry->f.vertical_scale,
-		  __entry->f.version,
-		  __entry->f.prob_skip_false,
-		  __entry->f.prob_intra,
-		  __entry->f.prob_last,
-		  __entry->f.prob_gf,
-		  __entry->f.num_dct_parts,
-		  __entry->f.first_part_size,
-		  __entry->f.first_part_header_bits,
-		  __print_array(__entry->f.dct_part_sizes,
-				ARRAY_SIZE(__entry->f.dct_part_sizes),
-				sizeof(__entry->f.dct_part_sizes[0])),
-		  __entry->f.last_frame_ts,
-		  __entry->f.golden_frame_ts,
-		  __entry->f.alt_frame_ts,
-		  __print_flags(__entry->f.flags, "|",
+		  __entry->quant_y_ac_qi,
+		  __entry->quant_y_dc_delta,
+		  __entry->quant_y2_dc_delta,
+		  __entry->quant_y2_ac_delta,
+		  __entry->quant_uv_dc_delta,
+		  __entry->quant_uv_ac_delta,
+		  __entry->coder_state_range,
+		  __entry->coder_state_value,
+		  __entry->coder_state_bit_count,
+		  __entry->width,
+		  __entry->height,
+		  __entry->horizontal_scale,
+		  __entry->vertical_scale,
+		  __entry->version,
+		  __entry->prob_skip_false,
+		  __entry->prob_intra,
+		  __entry->prob_last,
+		  __entry->prob_gf,
+		  __entry->num_dct_parts,
+		  __entry->first_part_size,
+		  __entry->first_part_header_bits,
+		  __print_array(__entry->dct_part_sizes,
+				ARRAY_SIZE(__entry->dct_part_sizes),
+				sizeof(__entry->dct_part_sizes[0])),
+		  __entry->last_frame_ts,
+		  __entry->golden_frame_ts,
+		  __entry->alt_frame_ts,
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_VP8_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
 		  {V4L2_VP8_FRAME_FLAG_EXPERIMENTAL, "EXPERIMENTAL"},
 		  {V4L2_VP8_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
@@ -1368,8 +2128,78 @@ DEFINE_EVENT(v4l2_ctrl_vp8_entropy_tmpl, v4l2_ctrl_vp8_entropy,
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
 	TP_ARGS(f),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_frame, f)),
-	TP_fast_assign(__entry->f = *f;),
+	TP_STRUCT__entry(__array(__s8, lf_ref_deltas, 4)
+			 __array(__s8, lf_mode_deltas, 2)
+			 __field(__u8, lf_level)
+			 __field(__u8, lf_sharpness)
+			 __field(__u8, lf_flags)
+			 __field(__u8, quant_base_q_idx)
+			 __field(__s8, quant_delta_q_y_dc)
+			 __field(__s8, quant_delta_q_uv_dc)
+			 __field(__s8, quant_delta_q_uv_ac)
+			 __array(__u8, seg_feature_data, sizeof(__s16) * 8 * 4)
+			 __array(__u8, seg_feature_enabled, 8)
+			 __array(__u8, seg_tree_probs, 7)
+			 __array(__u8, seg_pred_probs, 3)
+			 __field(__u8, seg_flags)
+			 __field(__u32, flags)
+			 __field(__u16, compressed_header_size)
+			 __field(__u16, uncompressed_header_size)
+			 __field(__u16, frame_width_minus_1)
+			 __field(__u16, frame_height_minus_1)
+			 __field(__u16, render_width_minus_1)
+			 __field(__u16, render_height_minus_1)
+			 __field(__u64, last_frame_ts)
+			 __field(__u64, golden_frame_ts)
+			 __field(__u64, alt_frame_ts)
+			 __field(__u8, ref_frame_sign_bias)
+			 __field(__u8, reset_frame_context)
+			 __field(__u8, frame_context_idx)
+			 __field(__u8, profile)
+			 __field(__u8, bit_depth)
+			 __field(__u8, interpolation_filter)
+			 __field(__u8, tile_cols_log2)
+			 __field(__u8, tile_rows_log2)
+			 __field(__u8, reference_mode)),
+	TP_fast_assign(memcpy(__entry->lf_ref_deltas, f->lf.ref_deltas,
+			      sizeof(__entry->lf_ref_deltas));
+		       memcpy(__entry->lf_mode_deltas, f->lf.mode_deltas,
+			      sizeof(__entry->lf_mode_deltas));
+		       __entry->lf_level = f->lf.level;
+		       __entry->lf_sharpness = f->lf.sharpness;
+		       __entry->lf_flags = f->lf.flags;
+		       __entry->quant_base_q_idx = f->quant.base_q_idx;
+		       __entry->quant_delta_q_y_dc = f->quant.delta_q_y_dc;
+		       __entry->quant_delta_q_uv_dc = f->quant.delta_q_uv_dc;
+		       __entry->quant_delta_q_uv_ac = f->quant.delta_q_uv_ac;
+		       memcpy(__entry->seg_feature_data, f->seg.feature_data,
+			      sizeof(__entry->seg_feature_data));
+		       memcpy(__entry->seg_feature_enabled, f->seg.feature_enabled,
+			      sizeof(__entry->seg_feature_enabled));
+		       memcpy(__entry->seg_tree_probs, f->seg.tree_probs,
+			      sizeof(__entry->seg_tree_probs));
+		       memcpy(__entry->seg_pred_probs, f->seg.pred_probs,
+			      sizeof(__entry->seg_pred_probs));
+		       __entry->seg_flags = f->seg.flags;
+		       __entry->flags = f->flags;
+		       __entry->compressed_header_size = f->compressed_header_size;
+		       __entry->uncompressed_header_size = f->uncompressed_header_size;
+		       __entry->frame_width_minus_1 = f->frame_width_minus_1;
+		       __entry->frame_height_minus_1 = f->frame_height_minus_1;
+		       __entry->render_width_minus_1 = f->render_width_minus_1;
+		       __entry->render_height_minus_1 = f->render_height_minus_1;
+		       __entry->last_frame_ts = f->last_frame_ts;
+		       __entry->golden_frame_ts = f->golden_frame_ts;
+		       __entry->alt_frame_ts = f->alt_frame_ts;
+		       __entry->ref_frame_sign_bias = f->ref_frame_sign_bias;
+		       __entry->reset_frame_context = f->reset_frame_context;
+		       __entry->frame_context_idx = f->frame_context_idx;
+		       __entry->profile = f->profile;
+		       __entry->bit_depth = f->bit_depth;
+		       __entry->interpolation_filter = f->interpolation_filter;
+		       __entry->tile_cols_log2 = f->tile_cols_log2;
+		       __entry->tile_rows_log2 = f->tile_rows_log2;
+		       __entry->reference_mode = f->reference_mode;),
 	TP_printk("\nlf.ref_deltas %s\n"
 		  "lf.mode_deltas %s\n"
 		  "lf.level %u\n"
@@ -1403,41 +2233,41 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 		  "tile_cols_log2 %u\n"
 		  "tile_rows_log_2 %u\n"
 		  "reference_mode %s\n",
-		  __print_array(__entry->f.lf.ref_deltas,
-				ARRAY_SIZE(__entry->f.lf.ref_deltas),
-				sizeof(__entry->f.lf.ref_deltas[0])),
-		  __print_array(__entry->f.lf.mode_deltas,
-				ARRAY_SIZE(__entry->f.lf.mode_deltas),
-				sizeof(__entry->f.lf.mode_deltas[0])),
-		  __entry->f.lf.level,
-		  __entry->f.lf.sharpness,
-		  __print_flags(__entry->f.lf.flags, "|",
+		  __print_array(__entry->lf_ref_deltas,
+				ARRAY_SIZE(__entry->lf_ref_deltas),
+				sizeof(__entry->lf_ref_deltas[0])),
+		  __print_array(__entry->lf_mode_deltas,
+				ARRAY_SIZE(__entry->lf_mode_deltas),
+				sizeof(__entry->lf_mode_deltas[0])),
+		  __entry->lf_level,
+		  __entry->lf_sharpness,
+		  __print_flags(__entry->lf_flags, "|",
 		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
 		  {V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"}),
-		  __entry->f.quant.base_q_idx,
-		  __entry->f.quant.delta_q_y_dc,
-		  __entry->f.quant.delta_q_uv_dc,
-		  __entry->f.quant.delta_q_uv_ac,
+		  __entry->quant_base_q_idx,
+		  __entry->quant_delta_q_y_dc,
+		  __entry->quant_delta_q_uv_dc,
+		  __entry->quant_delta_q_uv_ac,
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->f.seg.feature_data,
-				   sizeof(__entry->f.seg.feature_data),
+				   __entry->seg_feature_data,
+				   sizeof(__entry->seg_feature_data),
 				   false),
-		  __print_array(__entry->f.seg.feature_enabled,
-				ARRAY_SIZE(__entry->f.seg.feature_enabled),
-				sizeof(__entry->f.seg.feature_enabled[0])),
-		  __print_array(__entry->f.seg.tree_probs,
-				ARRAY_SIZE(__entry->f.seg.tree_probs),
-				sizeof(__entry->f.seg.tree_probs[0])),
-		  __print_array(__entry->f.seg.pred_probs,
-				ARRAY_SIZE(__entry->f.seg.pred_probs),
-				sizeof(__entry->f.seg.pred_probs[0])),
-		  __print_flags(__entry->f.seg.flags, "|",
+		  __print_array(__entry->seg_feature_enabled,
+				ARRAY_SIZE(__entry->seg_feature_enabled),
+				sizeof(__entry->seg_feature_enabled[0])),
+		  __print_array(__entry->seg_tree_probs,
+				ARRAY_SIZE(__entry->seg_tree_probs),
+				sizeof(__entry->seg_tree_probs[0])),
+		  __print_array(__entry->seg_pred_probs,
+				ARRAY_SIZE(__entry->seg_pred_probs),
+				sizeof(__entry->seg_pred_probs[0])),
+		  __print_flags(__entry->seg_flags, "|",
 		  {V4L2_VP9_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
 		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
 		  {V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
 		  {V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
 		  {V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE, "ABS_OR_DELTA_UPDATE"}),
-		  __print_flags(__entry->f.flags, "|",
+		  __print_flags(__entry->flags, "|",
 		  {V4L2_VP9_FRAME_FLAG_KEY_FRAME, "KEY_FRAME"},
 		  {V4L2_VP9_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
 		  {V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT, "ERROR_RESILIENT"},
@@ -1448,35 +2278,35 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 		  {V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING, "X_SUBSAMPLING"},
 		  {V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING, "Y_SUBSAMPLING"},
 		  {V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING, "COLOR_RANGE_FULL_SWING"}),
-		  __entry->f.compressed_header_size,
-		  __entry->f.uncompressed_header_size,
-		  __entry->f.frame_width_minus_1,
-		  __entry->f.frame_height_minus_1,
-		  __entry->f.render_width_minus_1,
-		  __entry->f.render_height_minus_1,
-		  __entry->f.last_frame_ts,
-		  __entry->f.golden_frame_ts,
-		  __entry->f.alt_frame_ts,
-		  __print_symbolic(__entry->f.ref_frame_sign_bias,
+		  __entry->compressed_header_size,
+		  __entry->uncompressed_header_size,
+		  __entry->frame_width_minus_1,
+		  __entry->frame_height_minus_1,
+		  __entry->render_width_minus_1,
+		  __entry->render_height_minus_1,
+		  __entry->last_frame_ts,
+		  __entry->golden_frame_ts,
+		  __entry->alt_frame_ts,
+		  __print_symbolic(__entry->ref_frame_sign_bias,
 		  {V4L2_VP9_SIGN_BIAS_LAST, "SIGN_BIAS_LAST"},
 		  {V4L2_VP9_SIGN_BIAS_GOLDEN, "SIGN_BIAS_GOLDEN"},
 		  {V4L2_VP9_SIGN_BIAS_ALT, "SIGN_BIAS_ALT"}),
-		  __print_symbolic(__entry->f.reset_frame_context,
+		  __print_symbolic(__entry->reset_frame_context,
 		  {V4L2_VP9_RESET_FRAME_CTX_NONE, "RESET_FRAME_CTX_NONE"},
 		  {V4L2_VP9_RESET_FRAME_CTX_SPEC, "RESET_FRAME_CTX_SPEC"},
 		  {V4L2_VP9_RESET_FRAME_CTX_ALL, "RESET_FRAME_CTX_ALL"}),
-		  __entry->f.frame_context_idx,
-		  __entry->f.profile,
-		  __entry->f.bit_depth,
-		  __print_symbolic(__entry->f.interpolation_filter,
+		  __entry->frame_context_idx,
+		  __entry->profile,
+		  __entry->bit_depth,
+		  __print_symbolic(__entry->interpolation_filter,
 		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP, "INTERP_FILTER_EIGHTTAP"},
 		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH, "INTERP_FILTER_EIGHTTAP_SMOOTH"},
 		  {V4L2_VP9_INTERP_FILTER_EIGHTTAP_SHARP, "INTERP_FILTER_EIGHTTAP_SHARP"},
 		  {V4L2_VP9_INTERP_FILTER_BILINEAR, "INTERP_FILTER_BILINEAR"},
 		  {V4L2_VP9_INTERP_FILTER_SWITCHABLE, "INTERP_FILTER_SWITCHABLE"}),
-		  __entry->f.tile_cols_log2,
-		  __entry->f.tile_rows_log2,
-		  __print_symbolic(__entry->f.reference_mode,
+		  __entry->tile_cols_log2,
+		  __entry->tile_rows_log2,
+		  __print_symbolic(__entry->reference_mode,
 		  {V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, "REFERENCE_MODE_SINGLE_REFERENCE"},
 		  {V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE, "REFERENCE_MODE_COMPOUND_REFERENCE"},
 		  {V4L2_VP9_REFERENCE_MODE_SELECT, "REFERENCE_MODE_SELECT"}))
@@ -1485,8 +2315,35 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
 	TP_ARGS(h),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
-	TP_fast_assign(__entry->h = *h;),
+	TP_STRUCT__entry(__field(__u8, tx_mode)
+			 __array(__u8, tx8, 2 * 1)
+			 __array(__u8, tx16, 2 * 2)
+			 __array(__u8, tx32, 2 * 3)
+			 __array(__u8, skip, 3)
+			 __array(__u8, inter_mode, 7 * 3)
+			 __array(__u8, interp_filter, 4 * 2)
+			 __array(__u8, is_inter, 4)
+			 __array(__u8, comp_mode, 5)
+			 __array(__u8, single_ref, 5 * 2)
+			 __array(__u8, comp_ref, 5)
+			 __array(__u8, y_mode, 4 * 9)
+			 __array(__u8, uv_mode, 10 * 9)
+			 __array(__u8, partition, 16 * 3)),
+	TP_fast_assign(__entry->tx_mode = h->tx_mode;
+		       memcpy(__entry->tx8, h->tx8, sizeof(__entry->tx8));
+		       memcpy(__entry->tx16, h->tx16, sizeof(__entry->tx16));
+		       memcpy(__entry->tx32, h->tx32, sizeof(__entry->tx32));
+		       memcpy(__entry->skip, h->skip, sizeof(__entry->skip));
+		       memcpy(__entry->inter_mode, h->inter_mode, sizeof(__entry->inter_mode));
+		       memcpy(__entry->interp_filter, h->interp_filter,
+			      sizeof(__entry->interp_filter));
+		       memcpy(__entry->is_inter, h->is_inter, sizeof(__entry->is_inter));
+		       memcpy(__entry->comp_mode, h->comp_mode, sizeof(__entry->comp_mode));
+		       memcpy(__entry->single_ref, h->single_ref, sizeof(__entry->single_ref));
+		       memcpy(__entry->comp_ref, h->comp_ref, sizeof(__entry->comp_ref));
+		       memcpy(__entry->y_mode, h->y_mode, sizeof(__entry->y_mode));
+		       memcpy(__entry->uv_mode, h->uv_mode, sizeof(__entry->uv_mode));
+		       memcpy(__entry->partition, h->partition, sizeof(__entry->partition));),
 	TP_printk("\ntx_mode %s\n"
 		  "tx8 {%s}\n"
 		  "tx16 {%s}\n"
@@ -1501,59 +2358,59 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 		  "y_mode {%s}\n"
 		  "uv_mode {%s}\n"
 		  "partition {%s}\n",
-		  __print_symbolic(__entry->h.tx_mode,
+		  __print_symbolic(__entry->tx_mode,
 		  {V4L2_VP9_TX_MODE_ONLY_4X4, "TX_MODE_ONLY_4X4"},
 		  {V4L2_VP9_TX_MODE_ALLOW_8X8, "TX_MODE_ALLOW_8X8"},
 		  {V4L2_VP9_TX_MODE_ALLOW_16X16, "TX_MODE_ALLOW_16X16"},
 		  {V4L2_VP9_TX_MODE_ALLOW_32X32, "TX_MODE_ALLOW_32X32"},
 		  {V4L2_VP9_TX_MODE_SELECT, "TX_MODE_SELECT"}),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx8,
-				   sizeof(__entry->h.tx8),
+				   __entry->tx8,
+				   sizeof(__entry->tx8),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx16,
-				   sizeof(__entry->h.tx16),
+				   __entry->tx16,
+				   sizeof(__entry->tx16),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.tx32,
-				   sizeof(__entry->h.tx32),
+				   __entry->tx32,
+				   sizeof(__entry->tx32),
 				   false),
-		  __print_array(__entry->h.skip,
-				ARRAY_SIZE(__entry->h.skip),
-				sizeof(__entry->h.skip[0])),
+		  __print_array(__entry->skip,
+				ARRAY_SIZE(__entry->skip),
+				sizeof(__entry->skip[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.inter_mode,
-				   sizeof(__entry->h.inter_mode),
+				   __entry->inter_mode,
+				   sizeof(__entry->inter_mode),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.interp_filter,
-				   sizeof(__entry->h.interp_filter),
+				   __entry->interp_filter,
+				   sizeof(__entry->interp_filter),
 				   false),
-		  __print_array(__entry->h.is_inter,
-				ARRAY_SIZE(__entry->h.is_inter),
-				sizeof(__entry->h.is_inter[0])),
-		  __print_array(__entry->h.comp_mode,
-				ARRAY_SIZE(__entry->h.comp_mode),
-				sizeof(__entry->h.comp_mode[0])),
+		  __print_array(__entry->is_inter,
+				ARRAY_SIZE(__entry->is_inter),
+				sizeof(__entry->is_inter[0])),
+		  __print_array(__entry->comp_mode,
+				ARRAY_SIZE(__entry->comp_mode),
+				sizeof(__entry->comp_mode[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.single_ref,
-				   sizeof(__entry->h.single_ref),
+				   __entry->single_ref,
+				   sizeof(__entry->single_ref),
 				   false),
-		  __print_array(__entry->h.comp_ref,
-				ARRAY_SIZE(__entry->h.comp_ref),
-				sizeof(__entry->h.comp_ref[0])),
+		  __print_array(__entry->comp_ref,
+				ARRAY_SIZE(__entry->comp_ref),
+				sizeof(__entry->comp_ref[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.y_mode,
-				   sizeof(__entry->h.y_mode),
+				   __entry->y_mode,
+				   sizeof(__entry->y_mode),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.uv_mode,
-				   sizeof(__entry->h.uv_mode),
+				   __entry->uv_mode,
+				   sizeof(__entry->uv_mode),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.partition,
-				   sizeof(__entry->h.partition),
+				   __entry->partition,
+				   sizeof(__entry->partition),
 				   false)
 	)
 );
@@ -1561,12 +2418,12 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
 	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
 	TP_ARGS(h),
-	TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_vp9_compressed_hdr, h)),
-	TP_fast_assign(__entry->h = *h;),
+	TP_STRUCT__entry(__array(__u8, coef, 4 * 2 * 2 * 6 * 6 * 3)),
+	TP_fast_assign(memcpy(__entry->coef, h->coef, sizeof(__entry->coef));),
 	TP_printk("\n coef {%s}",
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->h.coef,
-				   sizeof(__entry->h.coef),
+				   __entry->coef,
+				   sizeof(__entry->coef),
 				   false)
 	)
 );
@@ -1574,8 +2431,24 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
 DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
 	TP_ARGS(p),
-	TP_STRUCT__entry(__field_struct(struct v4l2_vp9_mv_probs, p)),
-	TP_fast_assign(__entry->p = *p;),
+	TP_STRUCT__entry(__array(__u8, joint, 3)
+			 __array(__u8, sign, 2)
+			 __array(__u8, classes, 2 * 10)
+			 __array(__u8, class0_bit, 2)
+			 __array(__u8, bits, 2 * 10)
+			 __array(__u8, class0_fr, 2 * 2 * 3)
+			 __array(__u8, fr, 2 * 3)
+			 __array(__u8, class0_hp, 2)
+			 __array(__u8, hp, 2)),
+	TP_fast_assign(memcpy(__entry->joint, p->joint, sizeof(__entry->joint));
+		       memcpy(__entry->sign, p->sign, sizeof(__entry->sign));
+		       memcpy(__entry->classes, p->classes, sizeof(__entry->classes));
+		       memcpy(__entry->class0_bit, p->class0_bit, sizeof(__entry->class0_bit));
+		       memcpy(__entry->bits, p->bits, sizeof(__entry->bits));
+		       memcpy(__entry->class0_fr, p->class0_fr, sizeof(__entry->class0_fr));
+		       memcpy(__entry->fr, p->fr, sizeof(__entry->fr));
+		       memcpy(__entry->class0_hp, p->class0_hp, sizeof(__entry->class0_hp));
+		       memcpy(__entry->hp, p->hp, sizeof(__entry->hp));),
 	TP_printk("\n joint %s\n"
 		  "sign %s\n"
 		  "classes {%s}\n"
@@ -1585,37 +2458,37 @@ DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 		  "fr {%s}\n"
 		  "class0_hp %s\n"
 		  "hp %s\n",
-		  __print_array(__entry->p.joint,
-				ARRAY_SIZE(__entry->p.joint),
-				sizeof(__entry->p.joint[0])),
-		  __print_array(__entry->p.sign,
-				ARRAY_SIZE(__entry->p.sign),
-				sizeof(__entry->p.sign[0])),
+		  __print_array(__entry->joint,
+				ARRAY_SIZE(__entry->joint),
+				sizeof(__entry->joint[0])),
+		  __print_array(__entry->sign,
+				ARRAY_SIZE(__entry->sign),
+				sizeof(__entry->sign[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.classes,
-				   sizeof(__entry->p.classes),
+				   __entry->classes,
+				   sizeof(__entry->classes),
 				   false),
-		  __print_array(__entry->p.class0_bit,
-				ARRAY_SIZE(__entry->p.class0_bit),
-				sizeof(__entry->p.class0_bit[0])),
+		  __print_array(__entry->class0_bit,
+				ARRAY_SIZE(__entry->class0_bit),
+				sizeof(__entry->class0_bit[0])),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.bits,
-				   sizeof(__entry->p.bits),
+				   __entry->bits,
+				   sizeof(__entry->bits),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.class0_fr,
-				   sizeof(__entry->p.class0_fr),
+				   __entry->class0_fr,
+				   sizeof(__entry->class0_fr),
 				   false),
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
-				   __entry->p.fr,
-				   sizeof(__entry->p.fr),
+				   __entry->fr,
+				   sizeof(__entry->fr),
 				   false),
-		  __print_array(__entry->p.class0_hp,
-				ARRAY_SIZE(__entry->p.class0_hp),
-				sizeof(__entry->p.class0_hp[0])),
-		  __print_array(__entry->p.hp,
-				ARRAY_SIZE(__entry->p.hp),
-				sizeof(__entry->p.hp[0]))
+		  __print_array(__entry->class0_hp,
+				ARRAY_SIZE(__entry->class0_hp),
+				sizeof(__entry->class0_hp[0])),
+		  __print_array(__entry->hp,
+				ARRAY_SIZE(__entry->hp),
+				sizeof(__entry->hp[0]))
 	)
 );
 

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:33 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:33 -0400
Subject: [PATCH v2 3/9] media: Add tgid and fd fields in v4l2_fh struct
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-3-9756edf72ac1@collabora.com>

These fields will be used in traces to help userspace tracing tools
identify streams.

The tgid field will keep the PID of the process that opened the video
file.
That is needed because trace calls can happen in IRQs, for which there is
no current PID.

The fd field helps identify the context in case the same process opens the
video device multiple times.
Note that the fd field is set in the __video_do_ioctl() function.
That is because the file descriptor has not been allocated yet when
v4l2_open() is called.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
 drivers/media/v4l2-core/v4l2-fh.c    |  1 +
 drivers/media/v4l2-core/v4l2-ioctl.c | 17 +++++++++++++++++
 include/media/v4l2-fh.h              |  4 ++++
 3 files changed, 22 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c
index b184bed8aca9..9c2ddd1c2137 100644
--- a/drivers/media/v4l2-core/v4l2-fh.c
+++ b/drivers/media/v4l2-core/v4l2-fh.c
@@ -37,6 +37,7 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev)
 	INIT_LIST_HEAD(&fh->available);
 	INIT_LIST_HEAD(&fh->subscribed);
 	fh->sequence = -1;
+	fh->tgid = current->tgid;
 	mutex_init(&fh->subscribe_lock);
 }
 EXPORT_SYMBOL_GPL(v4l2_fh_init);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index a2b650f4ec3c..c8746a1637f5 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -9,6 +9,7 @@
  */
 
 #include <linux/compat.h>
+#include <linux/fdtable.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -3061,6 +3062,16 @@ void v4l_printk_ioctl(const char *prefix, unsigned int cmd)
 }
 EXPORT_SYMBOL(v4l_printk_ioctl);
 
+static int _file_iterate(const void *priv, struct file *filp, unsigned int fd)
+{
+	const struct file *fh_filp = priv;
+
+	if (fh_filp == filp)
+		return fd;
+
+	return 0;
+}
+
 static long __video_do_ioctl(struct file *file,
 		unsigned int cmd, void *arg)
 {
@@ -3081,6 +3092,12 @@ static long __video_do_ioctl(struct file *file,
 		return ret;
 	}
 
+	if (unlikely(!vfh->fd)) {
+		vfh->fd = iterate_fd(current->files, 0, _file_iterate, file);
+		if (!vfh->fd)
+			vfh->fd = -1;
+	}
+
 	/*
 	 * We need to serialize streamon/off/reqbufs with queueing new requests.
 	 * These ioctls may trigger the cancellation of a streaming
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
index aad4b3689d7e..4ef4e58ab8d1 100644
--- a/include/media/v4l2-fh.h
+++ b/include/media/v4l2-fh.h
@@ -28,6 +28,8 @@ struct v4l2_ctrl_handler;
  * @vdev: pointer to &struct video_device
  * @ctrl_handler: pointer to &struct v4l2_ctrl_handler
  * @prio: priority of the file handler, as defined by &enum v4l2_priority
+ * @tgid: process id that initialized the v4l2_fh
+ * @fd: file descriptor associated to this v4l2_fh for the process id in tgid
  *
  * @wait: event' s wait queue
  * @subscribe_lock: serialise changes to the subscribed list; guarantee that
@@ -44,6 +46,8 @@ struct v4l2_fh {
 	struct video_device	*vdev;
 	struct v4l2_ctrl_handler *ctrl_handler;
 	enum v4l2_priority	prio;
+	uint32_t		tgid;
+	int			fd;
 
 	/* Events */
 	wait_queue_head_t	wait;

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:34 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:34 -0400
Subject: [PATCH v2 4/9] media: Add tgid and fd to the v4l2-requests trace
 fields
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-4-9756edf72ac1@collabora.com>

With these fields, userspace can better track which trace event matches
with a given stream.

Even though the trace shows the PID (based on current->tgid), trace
functions could be called from other contexts, therefore showing the wrong
PID, or none at all.

These will ensure that the trace event can be matched with the PID/FD that
opened and configured the video device file.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
---
 drivers/media/test-drivers/visl/visl-dec.c |  68 ++--
 include/trace/events/v4l2_controls.h       | 628 +++++++++++++++++++----------
 2 files changed, 445 insertions(+), 251 deletions(-)

diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index 1c66a1b8d78f..2a065a6249ad 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -489,67 +489,71 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
 static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
 {
 	int i;
+	struct v4l2_fh *fh = &ctx->fh;
 
 	switch (ctx->current_codec) {
 	default:
 	case VISL_CODEC_NONE:
 		break;
 	case VISL_CODEC_FWHT:
-		trace_v4l2_ctrl_fwht_params(run->fwht.params);
+		trace_v4l2_ctrl_fwht_params(fh->tgid, fh->fd, run->fwht.params);
 		break;
 	case VISL_CODEC_MPEG2:
-		trace_v4l2_ctrl_mpeg2_sequence(run->mpeg2.seq);
-		trace_v4l2_ctrl_mpeg2_picture(run->mpeg2.pic);
-		trace_v4l2_ctrl_mpeg2_quantisation(run->mpeg2.quant);
+		trace_v4l2_ctrl_mpeg2_sequence(fh->tgid, fh->fd, run->mpeg2.seq);
+		trace_v4l2_ctrl_mpeg2_picture(fh->tgid, fh->fd, run->mpeg2.pic);
+		trace_v4l2_ctrl_mpeg2_quantisation(fh->tgid, fh->fd, run->mpeg2.quant);
 		break;
 	case VISL_CODEC_VP8:
-		trace_v4l2_ctrl_vp8_frame(run->vp8.frame);
-		trace_v4l2_ctrl_vp8_entropy(run->vp8.frame);
+		trace_v4l2_ctrl_vp8_frame(fh->tgid, fh->fd, run->vp8.frame);
+		trace_v4l2_ctrl_vp8_entropy(fh->tgid, fh->fd, run->vp8.frame);
 		break;
 	case VISL_CODEC_VP9:
-		trace_v4l2_ctrl_vp9_frame(run->vp9.frame);
-		trace_v4l2_ctrl_vp9_compressed_hdr(run->vp9.probs);
-		trace_v4l2_ctrl_vp9_compressed_coeff(run->vp9.probs);
-		trace_v4l2_vp9_mv_probs(&run->vp9.probs->mv);
+		trace_v4l2_ctrl_vp9_frame(fh->tgid, fh->fd, run->vp9.frame);
+		trace_v4l2_ctrl_vp9_compressed_hdr(fh->tgid, fh->fd, run->vp9.probs);
+		trace_v4l2_ctrl_vp9_compressed_coeff(fh->tgid, fh->fd, run->vp9.probs);
+		trace_v4l2_vp9_mv_probs(fh->tgid, fh->fd, &run->vp9.probs->mv);
 		break;
 	case VISL_CODEC_H264:
-		trace_v4l2_ctrl_h264_sps(run->h264.sps);
-		trace_v4l2_ctrl_h264_pps(run->h264.pps);
-		trace_v4l2_ctrl_h264_scaling_matrix(run->h264.sm);
-		trace_v4l2_ctrl_h264_slice_params(run->h264.spram);
+		trace_v4l2_ctrl_h264_sps(fh->tgid, fh->fd, run->h264.sps);
+		trace_v4l2_ctrl_h264_pps(fh->tgid, fh->fd, run->h264.pps);
+		trace_v4l2_ctrl_h264_scaling_matrix(fh->tgid, fh->fd, run->h264.sm);
+		trace_v4l2_ctrl_h264_slice_params(fh->tgid, fh->fd, run->h264.spram);
 
 		for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
-			trace_v4l2_h264_ref_pic_list0(&run->h264.spram->ref_pic_list0[i], i);
+			trace_v4l2_h264_ref_pic_list0(fh->tgid, fh->fd,
+						      &run->h264.spram->ref_pic_list0[i], i);
 		for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
-			trace_v4l2_h264_ref_pic_list1(&run->h264.spram->ref_pic_list1[i], i);
+			trace_v4l2_h264_ref_pic_list1(fh->tgid, fh->fd,
+						      &run->h264.spram->ref_pic_list1[i], i);
 
-		trace_v4l2_ctrl_h264_decode_params(run->h264.dpram);
+		trace_v4l2_ctrl_h264_decode_params(fh->tgid, fh->fd, run->h264.dpram);
 
 		for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++)
-			trace_v4l2_h264_dpb_entry(&run->h264.dpram->dpb[i], i);
+			trace_v4l2_h264_dpb_entry(fh->tgid, fh->fd, &run->h264.dpram->dpb[i], i);
 
-		trace_v4l2_ctrl_h264_pred_weights(run->h264.pwht);
+		trace_v4l2_ctrl_h264_pred_weights(fh->tgid, fh->fd, run->h264.pwht);
 		break;
 	case VISL_CODEC_HEVC:
-		trace_v4l2_ctrl_hevc_sps(run->hevc.sps);
-		trace_v4l2_ctrl_hevc_pps(run->hevc.pps);
-		trace_v4l2_ctrl_hevc_slice_params(run->hevc.spram);
-		trace_v4l2_ctrl_hevc_scaling_matrix(run->hevc.sm);
-		trace_v4l2_ctrl_hevc_decode_params(run->hevc.dpram);
+		trace_v4l2_ctrl_hevc_sps(fh->tgid, fh->fd, run->hevc.sps);
+		trace_v4l2_ctrl_hevc_pps(fh->tgid, fh->fd, run->hevc.pps);
+		trace_v4l2_ctrl_hevc_slice_params(fh->tgid, fh->fd, run->hevc.spram);
+		trace_v4l2_ctrl_hevc_scaling_matrix(fh->tgid, fh->fd, run->hevc.sm);
+		trace_v4l2_ctrl_hevc_decode_params(fh->tgid, fh->fd, run->hevc.dpram);
 
 		for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++)
-			trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);
+			trace_v4l2_hevc_dpb_entry(fh->tgid, fh->fd, &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);
 
+		trace_v4l2_hevc_pred_weight_table(fh->tgid, fh->fd,
+						  &run->hevc.spram->pred_weight_table);
+		trace_v4l2_ctrl_hevc_ext_sps_lt_rps(fh->tgid, fh->fd, run->hevc.rps_lt);
+		trace_v4l2_ctrl_hevc_ext_sps_st_rps(fh->tgid, fh->fd, run->hevc.rps_st);
 		break;
 	case VISL_CODEC_AV1:
-		trace_v4l2_ctrl_av1_sequence(run->av1.seq);
-		trace_v4l2_ctrl_av1_frame(run->av1.frame);
-		trace_v4l2_ctrl_av1_film_grain(run->av1.grain);
-		trace_v4l2_ctrl_av1_tile_group_entry(run->av1.tge);
+		trace_v4l2_ctrl_av1_sequence(fh->tgid, fh->fd, run->av1.seq);
+		trace_v4l2_ctrl_av1_frame(fh->tgid, fh->fd, run->av1.frame);
+		trace_v4l2_ctrl_av1_film_grain(fh->tgid, fh->fd, run->av1.grain);
+		trace_v4l2_ctrl_av1_tile_group_entry(fh->tgid, fh->fd, run->av1.tge);
 		break;
 	}
 }
diff --git a/include/trace/events/v4l2_controls.h b/include/trace/events/v4l2_controls.h
index 3a9bc75752bf..a7c61c36a025 100644
--- a/include/trace/events/v4l2_controls.h
+++ b/include/trace/events/v4l2_controls.h
@@ -14,27 +14,39 @@
  * They can be identified by the name of the event. All control fields are copied in a TP_STRUCT
  * field so that they can be filtered separately in userspace.
  *
+ * In addition to the controls fields, tgid and fd are also added in each trace events.
+ * This allows to identify controls set by a specific process and to match them with other events
+ * from the same process.
+ * tgid contains the process id that opened the video device.
+ * fd is the file descriptor in the tgid, used in case a process opens multiple video devices.
+ *
  * Currently only the codec controls are supported.
  */
 
 /* AV1 controls */
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(__u32, flags)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_sequence *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u32, flags)
 			 __field(__u8, seq_profile)
 			 __field(__u8, order_hint_bits)
 			 __field(__u8, bit_depth)
 			 __field(__u16, max_frame_width_minus_1)
 			 __field(__u16, max_frame_height_minus_1)),
-	TP_fast_assign(__entry->flags = s->flags;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->flags = s->flags;
 		       __entry->seq_profile = s->seq_profile;
 		       __entry->order_hint_bits = s->order_hint_bits;
 		       __entry->bit_depth = s->bit_depth;
 		       __entry->max_frame_width_minus_1 = s->max_frame_width_minus_1;
 		       __entry->max_frame_height_minus_1 = s->max_frame_height_minus_1;),
-	TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
 		  "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n",
+		  __entry->tgid, __entry->fd,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"},
 		  {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"},
@@ -65,17 +77,23 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
-	TP_ARGS(t),
-	TP_STRUCT__entry(__field(__u32, tile_offset)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_tile_group_entry *t),
+	TP_ARGS(tgid, fd, t),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u32, tile_offset)
 			 __field(__u32, tile_size)
 			 __field(__u32, tile_row)
 			 __field(__u32, tile_col)),
-	TP_fast_assign(__entry->tile_offset = t->tile_offset;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->tile_offset = t->tile_offset;
 		       __entry->tile_size = t->tile_size;
 		       __entry->tile_row = t->tile_row;
 		       __entry->tile_col = t->tile_col;),
-	TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
+	TP_printk("tgid = %u, fd = %u, "
+		  "\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
+		  __entry->tgid, __entry->fd,
 		  __entry->tile_offset,
 		  __entry->tile_size,
 		  __entry->tile_row,
@@ -84,9 +102,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field(u8, tile_info_flags)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_frame *f),
+	TP_ARGS(tgid, fd, f),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u8, tile_info_flags)
 			 __field(u8, tile_info_context_update_tile_id)
 			 __field(u8, tile_info_tile_cols)
 			 __field(u8, tile_info_tile_rows)
@@ -144,7 +164,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 			 __array(u64, reference_frame_ts, V4L2_AV1_TOTAL_REFS_PER_FRAME)
 			 __array(s8, ref_frame_idx, V4L2_AV1_REFS_PER_FRAME)
 			 __field(u8, refresh_frame_flags)),
-	TP_fast_assign(__entry->tile_info_flags = f->tile_info.flags;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->tile_info_flags = f->tile_info.flags;
 		       __entry->tile_info_context_update_tile_id =
 				f->tile_info.context_update_tile_id;
 		       __entry->tile_info_tile_cols = f->tile_info.tile_cols;
@@ -226,7 +248,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 		       memcpy(__entry->ref_frame_idx, f->ref_frame_idx,
 			      sizeof(__entry->ref_frame_idx));
 		       __entry->refresh_frame_flags = f->refresh_frame_flags;),
-	TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
 		  "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n"
 		  "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n"
 		  "tile_info.width_in_sbs_minus_1: %s\ntile_info.height_in_sbs_minus_1: %s\n"
@@ -250,6 +273,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 		  "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n"
 		  "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n"
 		  "ref_frame_idx: %s\nrefresh_frame_flags: %u\n",
+		  __entry->tgid, __entry->fd,
 		  __print_flags(__entry->tile_info_flags, "|",
 		  {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}),
 		  __entry->tile_info_context_update_tile_id,
@@ -385,9 +409,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
 
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__field(__u8, flags)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_film_grain *f),
+	TP_ARGS(tgid, fd, f),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, flags)
 			 __field(__u8, cr_mult)
 			 __field(__u16, grain_seed)
 			 __field(__u8, film_grain_params_ref_idx)
@@ -412,7 +438,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 			 __field(__u8, cr_luma_mult)
 			 __field(__u16, cb_offset)
 			 __field(__u16, cr_offset)),
-	TP_fast_assign(__entry->flags = f->flags;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->flags = f->flags;
 		       __entry->cr_mult = f->cr_mult;
 		       __entry->grain_seed = f->grain_seed;
 		       __entry->film_grain_params_ref_idx = f->film_grain_params_ref_idx;
@@ -446,7 +474,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 		       __entry->cr_luma_mult = f->cr_luma_mult;
 		       __entry->cb_offset = f->cb_offset;
 		       __entry->cr_offset = f->cr_offset;),
-	TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
 		  "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n"
 		  "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n"
 		  "point_cb_scaling: %s\nnum_cr_points: %u\npoint_cr_value: %s\n"
@@ -455,6 +484,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 		  "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n"
 		  "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n"
 		  "cb_offset: %u\ncr_offset: %u\n",
+		  __entry->tgid, __entry->fd,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"},
 		  {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"},
@@ -507,31 +537,32 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
 )
 
 DEFINE_EVENT(v4l2_ctrl_av1_seq_tmpl, v4l2_ctrl_av1_sequence,
-	TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_sequence *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_av1_frame_tmpl, v4l2_ctrl_av1_frame,
-	TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
-	TP_ARGS(f)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_frame *f),
+	TP_ARGS(tgid, fd, f)
 );
 
 DEFINE_EVENT(v4l2_ctrl_av1_tge_tmpl, v4l2_ctrl_av1_tile_group_entry,
-	TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
-	TP_ARGS(t)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_tile_group_entry *t),
+	TP_ARGS(tgid, fd, t)
 );
 
 DEFINE_EVENT(v4l2_ctrl_av1_film_grain_tmpl, v4l2_ctrl_av1_film_grain,
-	TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
-	TP_ARGS(f)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_av1_film_grain *f),
+	TP_ARGS(tgid, fd, f)
 );
 
 /* FWHT controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_fwht_params *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
 			 __field(u64, backward_ref_ts)
 			 __field(u32, version)
 			 __field(u32, width)
@@ -542,7 +573,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
 			 __field(u32, ycbcr_enc)
 			 __field(u32, quantization)
 			 ),
-	TP_fast_assign(
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
 		       __entry->backward_ref_ts = p->backward_ref_ts;
 		       __entry->version = p->version;
 		       __entry->width = p->width;
@@ -553,8 +585,10 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
 		       __entry->ycbcr_enc = p->ycbcr_enc;
 		       __entry->quantization = p->quantization;
 		       ),
-	TP_printk("backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u "
+	TP_printk("tgid = %u, fd = %u, "
+		  "backward_ref_ts %llu version %u width %u height %u flags %s colorspace %u "
 		  "xfer_func %u ycbcr_enc %u quantization %u",
+		  __entry->tgid, __entry->fd,
 		  __entry->backward_ref_ts, __entry->version, __entry->width, __entry->height,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_FWHT_FL_IS_INTERLACED, "IS_INTERLACED"},
@@ -574,16 +608,18 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_fwht_params_tmpl,
 );
 
 DEFINE_EVENT(v4l2_ctrl_fwht_params_tmpl, v4l2_ctrl_fwht_params,
-	TP_PROTO(const struct v4l2_ctrl_fwht_params *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_fwht_params *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 /* H264 controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(u8, profile_idc)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_sps *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u8, profile_idc)
 			 __field(u8, constraint_set_flags)
 			 __field(u8, level_idc)
 			 __field(u8, seq_parameter_set_id)
@@ -601,7 +637,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 			 __field(u16, pic_width_in_mbs_minus1)
 			 __field(u16, pic_height_in_map_units_minus1)
 			 __field(u32, flags)),
-	TP_fast_assign(__entry->profile_idc = s->profile_idc;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->profile_idc = s->profile_idc;
 		       __entry->constraint_set_flags = s->constraint_set_flags;
 		       __entry->level_idc = s->level_idc;
 		       __entry->seq_parameter_set_id = s->seq_parameter_set_id;
@@ -622,7 +660,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 		       __entry->pic_width_in_mbs_minus1 = s->pic_width_in_mbs_minus1;
 		       __entry->pic_height_in_map_units_minus1 = s->pic_height_in_map_units_minus1;
 		       __entry->flags = s->flags),
-	TP_printk("\nprofile_idc %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nprofile_idc %u\n"
 		  "constraint_set_flags %s\n"
 		  "level_idc %u\n"
 		  "seq_parameter_set_id %u\n"
@@ -640,6 +679,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 		  "pic_width_in_mbs_minus1 %u\n"
 		  "pic_height_in_map_units_minus1 %u\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->profile_idc,
 		  __print_flags(__entry->constraint_set_flags, "|",
 		  {V4L2_H264_SPS_CONSTRAINT_SET0_FLAG, "CONSTRAINT_SET0_FLAG"},
@@ -679,9 +719,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_sps_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field(u8, pic_parameter_set_id)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_pps *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u8, pic_parameter_set_id)
 			 __field(u8, seq_parameter_set_id)
 			 __field(u8, num_slice_groups_minus1)
 			 __field(u8, num_ref_idx_l0_default_active_minus1)
@@ -692,7 +734,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 			 __field(__s8, chroma_qp_index_offset)
 			 __field(__s8, second_chroma_qp_index_offset)
 			 __field(u16, flags)),
-	TP_fast_assign(__entry->pic_parameter_set_id = p->pic_parameter_set_id;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->pic_parameter_set_id = p->pic_parameter_set_id;
 		       __entry->seq_parameter_set_id = p->seq_parameter_set_id;
 		       __entry->num_slice_groups_minus1 = p->num_slice_groups_minus1;
 		       __entry->num_ref_idx_l0_default_active_minus1 =
@@ -705,7 +749,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 		       __entry->chroma_qp_index_offset = p->chroma_qp_index_offset;
 		       __entry->second_chroma_qp_index_offset = p->second_chroma_qp_index_offset;
 		       __entry->flags = p->flags),
-	TP_printk("\npic_parameter_set_id %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\npic_parameter_set_id %u\n"
 		  "seq_parameter_set_id %u\n"
 		  "num_slice_groups_minus1 %u\n"
 		  "num_ref_idx_l0_default_active_minus1 %u\n"
@@ -716,6 +761,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 		  "chroma_qp_index_offset %d\n"
 		  "second_chroma_qp_index_offset %d\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->pic_parameter_set_id,
 		  __entry->seq_parameter_set_id,
 		  __entry->num_slice_groups_minus1,
@@ -741,15 +787,21 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pps_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__array(u8, scaling_list_4x4, 6 * 16)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_scaling_matrix *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(u8, scaling_list_4x4, 6 * 16)
 			 __array(u8, scaling_list_8x8, 6 * 64)),
-	TP_fast_assign(memcpy(__entry->scaling_list_4x4, s->scaling_list_4x4,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->scaling_list_4x4, s->scaling_list_4x4,
 			      sizeof(__entry->scaling_list_4x4));
 		       memcpy(__entry->scaling_list_8x8, s->scaling_list_8x8,
 			      sizeof(__entry->scaling_list_8x8))),
-	TP_printk("\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nscaling_list_4x4 {%s}\nscaling_list_8x8 {%s}",
+		  __entry->tgid, __entry->fd,
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
 				   __entry->scaling_list_4x4,
 				   sizeof(__entry->scaling_list_4x4),
@@ -762,9 +814,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_scaling_matrix_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field(u16, luma_log2_weight_denom)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_pred_weights *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u16, luma_log2_weight_denom)
 			 __field(u16, chroma_log2_weight_denom)
 			 __array(__s16, weight_factors_0_luma_weight, 32)
 			 __array(__s16, weight_factors_0_luma_offset, 32)
@@ -774,7 +828,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 			 __array(__s16, weight_factors_1_luma_offset, 32)
 			 __array(__s16, weight_factors_1_chroma_weight, 32 * 2)
 			 __array(__s16, weight_factors_1_chroma_offset, 32 * 2)),
-	TP_fast_assign(__entry->luma_log2_weight_denom = p->luma_log2_weight_denom;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->luma_log2_weight_denom = p->luma_log2_weight_denom;
 		       __entry->chroma_log2_weight_denom = p->chroma_log2_weight_denom;
 		       memcpy(__entry->weight_factors_0_luma_weight,
 			      p->weight_factors[0].luma_weight,
@@ -800,7 +856,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 		       memcpy(__entry->weight_factors_1_chroma_offset,
 			      p->weight_factors[1].chroma_offset,
 			      sizeof(__entry->weight_factors_1_chroma_offset))),
-	TP_printk("\nluma_log2_weight_denom %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nluma_log2_weight_denom %u\n"
 		  "chroma_log2_weight_denom %u\n"
 		  "weight_factor[0].luma_weight %s\n"
 		  "weight_factor[0].luma_offset %s\n"
@@ -810,6 +867,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 		  "weight_factor[1].luma_offset %s\n"
 		  "weight_factor[1].chroma_weight {%s}\n"
 		  "weight_factor[1].chroma_offset {%s}\n",
+		  __entry->tgid, __entry->fd,
 		  __entry->luma_log2_weight_denom,
 		  __entry->chroma_log2_weight_denom,
 		  __print_array(__entry->weight_factors_0_luma_weight,
@@ -844,9 +902,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_pred_weights_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(u32, header_bit_size)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_slice_params *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u32, header_bit_size)
 			 __field(u32, first_mb_in_slice)
 			 __field(u8, slice_type)
 			 __field(u8, colour_plane_id)
@@ -860,7 +920,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 			 __field(u8, num_ref_idx_l0_active_minus1)
 			 __field(u8, num_ref_idx_l1_active_minus1)
 			 __field(u32, flags)),
-	TP_fast_assign(__entry->header_bit_size = s->header_bit_size;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->header_bit_size = s->header_bit_size;
 		       __entry->first_mb_in_slice = s->first_mb_in_slice;
 		       __entry->slice_type = s->slice_type;
 		       __entry->colour_plane_id = s->colour_plane_id;
@@ -874,7 +936,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 		       __entry->num_ref_idx_l0_active_minus1 = s->num_ref_idx_l0_active_minus1;
 		       __entry->num_ref_idx_l1_active_minus1 = s->num_ref_idx_l1_active_minus1;
 		       __entry->flags = s->flags),
-	TP_printk("\nheader_bit_size %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nheader_bit_size %u\n"
 		  "first_mb_in_slice %u\n"
 		  "slice_type %s\n"
 		  "colour_plane_id %u\n"
@@ -888,6 +951,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 		  "num_ref_idx_l0_active_minus1 %u\n"
 		  "num_ref_idx_l1_active_minus1 %u\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->header_bit_size,
 		  __entry->first_mb_in_slice,
 		  __print_symbolic(__entry->slice_type,
@@ -913,15 +977,21 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_slice_params_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i),
-	TP_STRUCT__entry(__field(u8, fields)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(tgid, fd, r, i),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u8, fields)
 			 __field(u8, index)
 			 __field(int, i)),
-	TP_fast_assign(__entry->fields = r->fields;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->fields = r->fields;
 		       __entry->index = r->index;
 		       __entry->i = i;),
-	TP_printk("[%d]: fields %s index %u",
+	TP_printk("tgid = %u, fd = %u, "
+		  "[%d]: fields %s index %u",
+		  __entry->tgid, __entry->fd,
 		  __entry->i,
 		  __print_flags(__entry->fields, "|",
 		  {V4L2_H264_TOP_FIELD_REF, "TOP_FIELD_REF"},
@@ -932,9 +1002,11 @@ DECLARE_EVENT_CLASS(v4l2_h264_reference_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
-	TP_ARGS(d),
-	TP_STRUCT__entry(__field(u16, nal_ref_idc)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_decode_params *d),
+	TP_ARGS(tgid, fd, d),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u16, nal_ref_idc)
 			 __field(u16, frame_num)
 			 __field(__s32, top_field_order_cnt)
 			 __field(__s32, bottom_field_order_cnt)
@@ -947,7 +1019,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 			 __field(u32, pic_order_cnt_bit_size)
 			 __field(u32, slice_group_change_cycle)
 			 __field(u32, flags)),
-	TP_fast_assign(__entry->nal_ref_idc = d->nal_ref_idc;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->nal_ref_idc = d->nal_ref_idc;
 		       __entry->frame_num = d->frame_num;
 		       __entry->top_field_order_cnt = d->top_field_order_cnt;
 		       __entry->bottom_field_order_cnt = d->bottom_field_order_cnt;
@@ -960,7 +1034,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 		       __entry->pic_order_cnt_bit_size = d->pic_order_cnt_bit_size;
 		       __entry->slice_group_change_cycle = d->slice_group_change_cycle;
 		       __entry->flags = d->flags),
-	TP_printk("\nnal_ref_idc %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nnal_ref_idc %u\n"
 		  "frame_num %u\n"
 		  "top_field_order_cnt %d\n"
 		  "bottom_field_order_cnt %d\n"
@@ -973,6 +1048,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 		  "pic_order_cnt_bit_size %u\n"
 		  "slice_group_change_cycle %u\n"
 		  "flags %s\n",
+		  __entry->tgid, __entry->fd,
 		  __entry->nal_ref_idc,
 		  __entry->frame_num,
 		  __entry->top_field_order_cnt,
@@ -995,9 +1071,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_h264_decode_params_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
-	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
-	TP_ARGS(e, i),
-	TP_STRUCT__entry(__field(u64, reference_ts)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_h264_dpb_entry *e, int i),
+	TP_ARGS(tgid, fd, e, i),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(u64, reference_ts)
 			 __field(u32, pic_num)
 			 __field(u16, frame_num)
 			 __field(u8, fields)
@@ -1005,7 +1083,9 @@ DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
 			 __field(__s32, bottom_field_order_cnt)
 			 __field(u32, flags)
 			 __field(int, i)),
-	TP_fast_assign(__entry->reference_ts = e->reference_ts;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->reference_ts = e->reference_ts;
 		       __entry->pic_num = e->pic_num;
 		       __entry->frame_num = e->frame_num;
 		       __entry->fields = e->fields;
@@ -1013,8 +1093,10 @@ DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
 		       __entry->bottom_field_order_cnt = e->bottom_field_order_cnt;
 		       __entry->flags = e->flags;
 		       __entry->i = i;),
-	TP_printk("[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
+	TP_printk("tgid = %u, fd = %u, "
+		  "[%d]: reference_ts %llu, pic_num %u frame_num %u fields %s "
 		  "top_field_order_cnt %d bottom_field_order_cnt %d flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->i,
 		  __entry->reference_ts,
 		  __entry->pic_num,
@@ -1035,56 +1117,58 @@ DECLARE_EVENT_CLASS(v4l2_h264_dpb_entry_tmpl,
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_sps_tmpl, v4l2_ctrl_h264_sps,
-	TP_PROTO(const struct v4l2_ctrl_h264_sps *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_sps *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_pps_tmpl, v4l2_ctrl_h264_pps,
-	TP_PROTO(const struct v4l2_ctrl_h264_pps *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_pps *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_scaling_matrix_tmpl, v4l2_ctrl_h264_scaling_matrix,
-	TP_PROTO(const struct v4l2_ctrl_h264_scaling_matrix *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_scaling_matrix *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_pred_weights_tmpl, v4l2_ctrl_h264_pred_weights,
-	TP_PROTO(const struct v4l2_ctrl_h264_pred_weights *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_pred_weights *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_slice_params_tmpl, v4l2_ctrl_h264_slice_params,
-	TP_PROTO(const struct v4l2_ctrl_h264_slice_params *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_slice_params *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list0,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(tgid, fd, r, i)
 );
 
 DEFINE_EVENT(v4l2_h264_reference_tmpl, v4l2_h264_ref_pic_list1,
-	TP_PROTO(const struct v4l2_h264_reference *r, int i),
-	TP_ARGS(r, i)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_h264_reference *r, int i),
+	TP_ARGS(tgid, fd, r, i)
 );
 
 DEFINE_EVENT(v4l2_ctrl_h264_decode_params_tmpl, v4l2_ctrl_h264_decode_params,
-	TP_PROTO(const struct v4l2_ctrl_h264_decode_params *d),
-	TP_ARGS(d)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_h264_decode_params *d),
+	TP_ARGS(tgid, fd, d)
 );
 
 DEFINE_EVENT(v4l2_h264_dpb_entry_tmpl, v4l2_h264_dpb_entry,
-	TP_PROTO(const struct v4l2_h264_dpb_entry *e, int i),
-	TP_ARGS(e, i)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_h264_dpb_entry *e, int i),
+	TP_ARGS(tgid, fd, e, i)
 );
 
 /* HEVC controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(__u8, video_parameter_set_id)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_sps *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, video_parameter_set_id)
 			 __field(__u8, seq_parameter_set_id)
 			 __field(__u16, pic_width_in_luma_samples)
 			 __field(__u16, pic_height_in_luma_samples)
@@ -1109,7 +1193,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 			 __field(__u8, chroma_format_idc)
 			 __field(__u8, sps_max_sub_layers_minus1)
 			 __field(__u64, flags)),
-	TP_fast_assign(__entry->video_parameter_set_id = s->video_parameter_set_id;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->video_parameter_set_id = s->video_parameter_set_id;
 		       __entry->seq_parameter_set_id = s->seq_parameter_set_id;
 		       __entry->pic_width_in_luma_samples = s->pic_width_in_luma_samples;
 		       __entry->pic_height_in_luma_samples = s->pic_height_in_luma_samples;
@@ -1146,7 +1232,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 		       __entry->chroma_format_idc = s->chroma_format_idc;
 		       __entry->sps_max_sub_layers_minus1 = s->sps_max_sub_layers_minus1;
 		       __entry->flags = s->flags;),
-	TP_printk("\nvideo_parameter_set_id %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nvideo_parameter_set_id %u\n"
 		  "seq_parameter_set_id %u\n"
 		  "pic_width_in_luma_samples %u\n"
 		  "pic_height_in_luma_samples %u\n"
@@ -1171,6 +1258,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 		  "chroma_format_idc %u\n"
 		  "sps_max_sub_layers_minus1 %u\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->video_parameter_set_id,
 		  __entry->seq_parameter_set_id,
 		  __entry->pic_width_in_luma_samples,
@@ -1213,9 +1301,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_sps_tmpl,
 
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field(__u8, pic_parameter_set_id)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_pps *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, pic_parameter_set_id)
 			 __field(__u8, num_extra_slice_header_bits)
 			 __field(__u8, num_ref_idx_l0_default_active_minus1)
 			 __field(__u8, num_ref_idx_l1_default_active_minus1)
@@ -1231,7 +1321,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 			 __field(__s8, pps_tc_offset_div2)
 			 __field(__u8, log2_parallel_merge_level_minus2)
 			 __field(__u64, flags)),
-	TP_fast_assign(__entry->pic_parameter_set_id = p->pic_parameter_set_id;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->pic_parameter_set_id = p->pic_parameter_set_id;
 		       __entry->num_extra_slice_header_bits = p->num_extra_slice_header_bits;
 		       __entry->num_ref_idx_l0_default_active_minus1 =
 				p->num_ref_idx_l0_default_active_minus1;
@@ -1252,7 +1344,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 		       __entry->log2_parallel_merge_level_minus2 =
 				p->log2_parallel_merge_level_minus2;
 		       __entry->flags = p->flags;),
-	TP_printk("\npic_parameter_set_id %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\npic_parameter_set_id %u\n"
 		  "num_extra_slice_header_bits %u\n"
 		  "num_ref_idx_l0_default_active_minus1 %u\n"
 		  "num_ref_idx_l1_default_active_minus1 %u\n"
@@ -1268,6 +1361,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 		  "pps_tc_offset_div2 %d\n"
 		  "log2_parallel_merge_level_minus2 %u\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->pic_parameter_set_id,
 		  __entry->num_extra_slice_header_bits,
 		  __entry->num_ref_idx_l0_default_active_minus1,
@@ -1322,9 +1416,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_pps_tmpl,
 
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(__u32, bit_size)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_slice_params *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u32, bit_size)
 			 __field(__u32, data_byte_offset)
 			 __field(__u32, num_entry_point_offsets)
 			 __field(__u8, nal_unit_type)
@@ -1351,7 +1447,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 			 __field(__u16, short_term_ref_pic_set_size)
 			 __field(__u16, long_term_ref_pic_set_size)
 			 __field(__u64, flags)),
-	TP_fast_assign(__entry->bit_size = s->bit_size;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->bit_size = s->bit_size;
 		       __entry->data_byte_offset = s->data_byte_offset;
 		       __entry->num_entry_point_offsets = s->num_entry_point_offsets;
 		       __entry->nal_unit_type = s->nal_unit_type;
@@ -1378,7 +1476,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 		       __entry->short_term_ref_pic_set_size = s->short_term_ref_pic_set_size;
 		       __entry->long_term_ref_pic_set_size = s->long_term_ref_pic_set_size;
 		       __entry->flags = s->flags;),
-	TP_printk("\nbit_size %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nbit_size %u\n"
 		  "data_byte_offset %u\n"
 		  "num_entry_point_offsets %u\n"
 		  "nal_unit_type %u\n"
@@ -1405,6 +1504,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 		  "short_term_ref_pic_set_size %u\n"
 		  "long_term_ref_pic_set_size %u\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->bit_size,
 		  __entry->data_byte_offset,
 		  __entry->num_entry_point_offsets,
@@ -1454,9 +1554,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_slice_params_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
-	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__array(__s8, delta_luma_weight_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_hevc_pred_weight_table *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__s8, delta_luma_weight_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
 			 __array(__s8, luma_offset_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
 			 __array(__s8, delta_chroma_weight_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
 			 __array(__s8, chroma_offset_l0, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
@@ -1466,7 +1568,9 @@ DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 			 __array(__s8, chroma_offset_l1, V4L2_HEVC_DPB_ENTRIES_NUM_MAX * 2)
 			 __field(__u8, luma_log2_weight_denom)
 			 __field(__s8, delta_chroma_log2_weight_denom)),
-	TP_fast_assign(memcpy(__entry->delta_luma_weight_l0, p->delta_luma_weight_l0,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->delta_luma_weight_l0, p->delta_luma_weight_l0,
 			      sizeof(__entry->delta_luma_weight_l0));
 		       memcpy(__entry->luma_offset_l0, p->luma_offset_l0,
 			      sizeof(__entry->luma_offset_l0));
@@ -1485,7 +1589,8 @@ DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 		       __entry->luma_log2_weight_denom = p->luma_log2_weight_denom;
 		       __entry->delta_chroma_log2_weight_denom =
 				p->delta_chroma_log2_weight_denom;),
-	TP_printk("\ndelta_luma_weight_l0 %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\ndelta_luma_weight_l0 %s\n"
 		  "luma_offset_l0 %s\n"
 		  "delta_chroma_weight_l0 {%s}\n"
 		  "chroma_offset_l0 {%s}\n"
@@ -1495,6 +1600,7 @@ DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 		  "chroma_offset_l1 {%s}\n"
 		  "luma_log2_weight_denom %d\n"
 		  "delta_chroma_log2_weight_denom %d\n",
+		  __entry->tgid, __entry->fd,
 		  __print_array(__entry->delta_luma_weight_l0,
 				ARRAY_SIZE(__entry->delta_luma_weight_l0),
 				sizeof(__entry->delta_luma_weight_l0[0])),
@@ -1529,15 +1635,19 @@ DECLARE_EVENT_CLASS(v4l2_hevc_pred_weight_table_tmpl,
 	))
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__array(__u8, scaling_list_4x4, 6 * 16)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_scaling_matrix *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__u8, scaling_list_4x4, 6 * 16)
 			 __array(__u8, scaling_list_8x8, 6 * 64)
 			 __array(__u8, scaling_list_16x16, 6 * 64)
 			 __array(__u8, scaling_list_32x32, 2 * 64)
 			 __array(__u8, scaling_list_dc_coef_16x16, 6)
 			 __array(__u8, scaling_list_dc_coef_32x32, 2)),
-	TP_fast_assign(memcpy(__entry->scaling_list_4x4,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->scaling_list_4x4,
 			      s->scaling_list_4x4, sizeof(__entry->scaling_list_4x4));
 		       memcpy(__entry->scaling_list_8x8,
 			      s->scaling_list_8x8, sizeof(__entry->scaling_list_8x8));
@@ -1551,12 +1661,14 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
 		       memcpy(__entry->scaling_list_dc_coef_32x32,
 			      s->scaling_list_dc_coef_32x32,
 			      sizeof(__entry->scaling_list_dc_coef_32x32));),
-	TP_printk("\nscaling_list_4x4 {%s}\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nscaling_list_4x4 {%s}\n"
 		  "scaling_list_8x8 {%s}\n"
 		  "scaling_list_16x16 {%s}\n"
 		  "scaling_list_32x32 {%s}\n"
 		  "scaling_list_dc_coef_16x16 %s\n"
 		  "scaling_list_dc_coef_32x32 %s\n",
+		  __entry->tgid, __entry->fd,
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
 				   __entry->scaling_list_4x4,
 				   sizeof(__entry->scaling_list_4x4),
@@ -1582,9 +1694,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_scaling_matrix_tmpl,
 	))
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
-	TP_ARGS(d),
-	TP_STRUCT__entry(__field(__s32, pic_order_cnt_val)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_decode_params *d),
+	TP_ARGS(tgid, fd, d),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__s32, pic_order_cnt_val)
 			 __field(__u16, short_term_ref_pic_set_size)
 			 __field(__u16, long_term_ref_pic_set_size)
 			 __field(__u8, num_active_dpb_entries)
@@ -1595,7 +1709,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 			 __array(__u8, poc_st_curr_after, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
 			 __array(__u8, poc_lt_curr, V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
 			 __field(__u64, flags)),
-	TP_fast_assign(__entry->pic_order_cnt_val = d->pic_order_cnt_val;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->pic_order_cnt_val = d->pic_order_cnt_val;
 		       __entry->short_term_ref_pic_set_size = d->short_term_ref_pic_set_size;
 		       __entry->long_term_ref_pic_set_size = d->long_term_ref_pic_set_size;
 		       __entry->num_active_dpb_entries = d->num_active_dpb_entries;
@@ -1608,7 +1724,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 			      sizeof(__entry->poc_st_curr_after));
 		       memcpy(__entry->poc_lt_curr, d->poc_lt_curr, sizeof(__entry->poc_lt_curr));
 		       __entry->flags = d->flags;),
-	TP_printk("\npic_order_cnt_val %d\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\npic_order_cnt_val %d\n"
 		  "short_term_ref_pic_set_size %u\n"
 		  "long_term_ref_pic_set_size %u\n"
 		  "num_active_dpb_entries %u\n"
@@ -1619,6 +1736,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_decode_params_tmpl,
 		  "poc_st_curr_after %s\n"
 		  "poc_lt_curr %s\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __entry->pic_order_cnt_val,
 		  __entry->short_term_ref_pic_set_size,
 		  __entry->long_term_ref_pic_set_size,
@@ -1643,14 +1761,20 @@ 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(__u8, flags)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(tgid, fd, lt),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, flags)
 			 __field(__u32, lt_ref_pic_poc_lsb_sps)),
-	TP_fast_assign(__entry->flags = lt->flags;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->flags = lt->flags;
 		       __entry->lt_ref_pic_poc_lsb_sps = lt->lt_ref_pic_poc_lsb_sps;),
-	TP_printk("\nflags %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nflags %s\n"
 		  "lt_ref_pic_poc_lsb_sps %x\n",
+		  __entry->tgid, __entry->fd,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT, "USED_LT"}
 		  ),
@@ -1659,9 +1783,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_lt_rps_tmpl,
 );
 
 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(__u8, flags)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(tgid, fd, st),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, flags)
 			 __field(__u8, delta_idx_minus1)
 			 __field(__u8, delta_rps_sign)
 			 __field(__u16, abs_delta_rps_minus1)
@@ -1671,7 +1797,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
 			 __field(__u32, use_delta_flag)
 			 __array(__u32, delta_poc_s0_minus1, 16)
 			 __array(__u32, delta_poc_s1_minus1, 16)),
-	TP_fast_assign(__entry->flags = st->flags;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->flags = st->flags;
 		       __entry->delta_idx_minus1 = st->delta_idx_minus1;
 		       __entry->delta_rps_sign = st->delta_rps_sign;
 		       __entry->abs_delta_rps_minus1 = st->abs_delta_rps_minus1;
@@ -1683,7 +1811,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
 			      sizeof(__entry->delta_poc_s0_minus1));
 		       memcpy(__entry->delta_poc_s1_minus1, st->delta_poc_s1_minus1,
 			      sizeof(__entry->delta_poc_s1_minus1));),
-	TP_printk("\nflags %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nflags %s\n"
 		  "delta_idx_minus1: %u\n"
 		  "delta_rps_sign: %u\n"
 		  "abs_delta_rps_minus1: %u\n"
@@ -1693,6 +1822,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
 		  "use_delta_flag: %08x\n"
 		  "delta_poc_s0_minus1: %s\n"
 		  "delta_poc_s1_minus1: %s\n",
+		  __entry->tgid, __entry->fd,
 		  __print_flags(__entry->flags, "|",
 		  {V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED, "INTER_REF_PIC_SET_PRED"}
 		  ),
@@ -1713,20 +1843,26 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_hevc_ext_sps_st_rps_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
-	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
-	TP_ARGS(e),
-	TP_STRUCT__entry(__field(__u64, timestamp)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_hevc_dpb_entry *e),
+	TP_ARGS(tgid, fd, e),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u64, timestamp)
 			 __field(__u8, flags)
 			 __field(__u8, field_pic)
 			 __field(__s32, pic_order_cnt_val)),
-	TP_fast_assign(__entry->timestamp = e->timestamp;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->timestamp = e->timestamp;
 		       __entry->flags = e->flags;
 		       __entry->field_pic = e->field_pic;
 		       __entry->pic_order_cnt_val = e->pic_order_cnt_val;),
-	TP_printk("\ntimestamp %llu\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\ntimestamp %llu\n"
 		  "flags %s\n"
 		  "field_pic %u\n"
 		  "pic_order_cnt_val %d\n",
+		  __entry->tgid, __entry->fd,
 		__entry->timestamp,
 		__print_flags(__entry->flags, "|",
 		{V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE, "LONG_TERM_REFERENCE"}
@@ -1736,69 +1872,75 @@ DECLARE_EVENT_CLASS(v4l2_hevc_dpb_entry_tmpl,
 	))
 
 DEFINE_EVENT(v4l2_ctrl_hevc_sps_tmpl, v4l2_ctrl_hevc_sps,
-	TP_PROTO(const struct v4l2_ctrl_hevc_sps *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_sps *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_hevc_pps_tmpl, v4l2_ctrl_hevc_pps,
-	TP_PROTO(const struct v4l2_ctrl_hevc_pps *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_pps *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 DEFINE_EVENT(v4l2_ctrl_hevc_slice_params_tmpl, v4l2_ctrl_hevc_slice_params,
-	TP_PROTO(const struct v4l2_ctrl_hevc_slice_params *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_slice_params *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_hevc_pred_weight_table_tmpl, v4l2_hevc_pred_weight_table,
-	TP_PROTO(const struct v4l2_hevc_pred_weight_table *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_hevc_pred_weight_table *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 DEFINE_EVENT(v4l2_ctrl_hevc_scaling_matrix_tmpl, v4l2_ctrl_hevc_scaling_matrix,
-	TP_PROTO(const struct v4l2_ctrl_hevc_scaling_matrix *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_scaling_matrix *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_hevc_decode_params_tmpl, v4l2_ctrl_hevc_decode_params,
-	TP_PROTO(const struct v4l2_ctrl_hevc_decode_params *d),
-	TP_ARGS(d)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_decode_params *d),
+	TP_ARGS(tgid, fd, 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)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_ext_sps_lt_rps *lt),
+	TP_ARGS(tgid, fd, 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)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_hevc_ext_sps_st_rps *st),
+	TP_ARGS(tgid, fd, st)
 );
 
 DEFINE_EVENT(v4l2_hevc_dpb_entry_tmpl, v4l2_hevc_dpb_entry,
-	TP_PROTO(const struct v4l2_hevc_dpb_entry *e),
-	TP_ARGS(e)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_hevc_dpb_entry *e),
+	TP_ARGS(tgid, fd, e)
 );
 
 /* MPEG2 controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
-	TP_ARGS(s),
-	TP_STRUCT__entry(__field(__u16, horizontal_size)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_sequence *s),
+	TP_ARGS(tgid, fd, s),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u16, horizontal_size)
 			 __field(__u16, vertical_size)
 			 __field(__u32, vbv_buffer_size)
 			 __field(__u16, profile_and_level_indication)
 			 __field(__u8, chroma_format)
 			 __field(__u8, flags)),
-	TP_fast_assign(__entry->horizontal_size = s->horizontal_size;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->horizontal_size = s->horizontal_size;
 		       __entry->vertical_size = s->vertical_size;
 		       __entry->vbv_buffer_size = s->vbv_buffer_size;
 		       __entry->profile_and_level_indication = s->profile_and_level_indication;
 		       __entry->chroma_format = s->chroma_format;
 		       __entry->flags = s->flags;),
-	TP_printk("\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nhorizontal_size %u\nvertical_size %u\nvbv_buffer_size %u\n"
 		  "profile_and_level_indication %u\nchroma_format %u\nflags %s\n",
+		  __entry->tgid, __entry->fd,
 		  __entry->horizontal_size,
 		  __entry->vertical_size,
 		  __entry->vbv_buffer_size,
@@ -1810,24 +1952,30 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_seq_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__field(__u64, backward_ref_ts)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_picture *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u64, backward_ref_ts)
 			 __field(__u64, forward_ref_ts)
 			 __field(__u32, flags)
 			 __array(__u8, f_code, 4)
 			 __field(__u8, picture_coding_type)
 			 __field(__u8, picture_structure)
 			 __field(__u8, intra_dc_precision)),
-	TP_fast_assign(__entry->backward_ref_ts = p->backward_ref_ts;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->backward_ref_ts = p->backward_ref_ts;
 		       __entry->forward_ref_ts = p->forward_ref_ts;
 		       __entry->flags = p->flags;
 		       memcpy(__entry->f_code, p->f_code, sizeof(__entry->f_code));
 		       __entry->picture_coding_type = p->picture_coding_type;
 		       __entry->picture_structure = p->picture_structure;
 		       __entry->intra_dc_precision = p->intra_dc_precision;),
-	TP_printk("\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nbackward_ref_ts %llu\nforward_ref_ts %llu\nflags %s\nf_code {%s}\n"
 		  "picture_coding_type: %u\npicture_structure %u\nintra_dc_precision %u\n",
+		  __entry->tgid, __entry->fd,
 		  __entry->backward_ref_ts,
 		  __entry->forward_ref_ts,
 		  __print_flags(__entry->flags, "|",
@@ -1850,13 +1998,17 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_pic_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
-	TP_ARGS(q),
-	TP_STRUCT__entry(__array(__u8, intra_quantiser_matrix, 64)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_quantisation *q),
+	TP_ARGS(tgid, fd, q),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__u8, intra_quantiser_matrix, 64)
 			 __array(__u8, non_intra_quantiser_matrix, 64)
 			 __array(__u8, chroma_intra_quantiser_matrix, 64)
 			 __array(__u8, chroma_non_intra_quantiser_matrix, 64)),
-	TP_fast_assign(memcpy(__entry->intra_quantiser_matrix, q->intra_quantiser_matrix,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->intra_quantiser_matrix, q->intra_quantiser_matrix,
 			      sizeof(__entry->intra_quantiser_matrix));
 		       memcpy(__entry->non_intra_quantiser_matrix, q->non_intra_quantiser_matrix,
 			      sizeof(__entry->non_intra_quantiser_matrix));
@@ -1866,8 +2018,10 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
 		       memcpy(__entry->chroma_non_intra_quantiser_matrix,
 			      q->chroma_non_intra_quantiser_matrix,
 			      sizeof(__entry->chroma_non_intra_quantiser_matrix));),
-	TP_printk("\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nintra_quantiser_matrix %s\nnon_intra_quantiser_matrix %s\n"
 		  "chroma_intra_quantiser_matrix %s\nchroma_non_intra_quantiser_matrix %s\n",
+		  __entry->tgid, __entry->fd,
 		  __print_array(__entry->intra_quantiser_matrix,
 				ARRAY_SIZE(__entry->intra_quantiser_matrix),
 				sizeof(__entry->intra_quantiser_matrix[0])),
@@ -1884,30 +2038,34 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_mpeg2_quant_tmpl,
 )
 
 DEFINE_EVENT(v4l2_ctrl_mpeg2_seq_tmpl, v4l2_ctrl_mpeg2_sequence,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_sequence *s),
-	TP_ARGS(s)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_sequence *s),
+	TP_ARGS(tgid, fd, s)
 );
 
 DEFINE_EVENT(v4l2_ctrl_mpeg2_pic_tmpl, v4l2_ctrl_mpeg2_picture,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_picture *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_picture *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 DEFINE_EVENT(v4l2_ctrl_mpeg2_quant_tmpl, v4l2_ctrl_mpeg2_quantisation,
-	TP_PROTO(const struct v4l2_ctrl_mpeg2_quantisation *q),
-	TP_ARGS(q)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_mpeg2_quantisation *q),
+	TP_ARGS(tgid, fd, q)
 );
 
 /* VP8 controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__array(__u8, entropy_coeff_probs, 4 * 8 * 3 * V4L2_VP8_COEFF_PROB_CNT)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(tgid, fd, f),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__u8, entropy_coeff_probs, 4 * 8 * 3 * V4L2_VP8_COEFF_PROB_CNT)
 			 __array(__u8, entropy_y_mode_probs, 4)
 			 __array(__u8, entropy_uv_mode_probs, 3)
 			 __array(__u8, entropy_mv_probs, 2 * 19)),
-	TP_fast_assign(memcpy(__entry->entropy_coeff_probs, f->entropy.coeff_probs,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->entropy_coeff_probs, f->entropy.coeff_probs,
 			      sizeof(__entry->entropy_coeff_probs));
 		       memcpy(__entry->entropy_y_mode_probs, f->entropy.y_mode_probs,
 			      sizeof(__entry->entropy_y_mode_probs));
@@ -1915,10 +2073,12 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
 			      sizeof(__entry->entropy_uv_mode_probs));
 		       memcpy(__entry->entropy_mv_probs, f->entropy.mv_probs,
 			      sizeof(__entry->entropy_mv_probs));),
-	TP_printk("\nentropy.coeff_probs {%s}\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nentropy.coeff_probs {%s}\n"
 		  "entropy.y_mode_probs %s\n"
 		  "entropy.uv_mode_probs %s\n"
 		  "entropy.mv_probs {%s}",
+		  __entry->tgid, __entry->fd,
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
 				   __entry->entropy_coeff_probs,
 				   sizeof(__entry->entropy_coeff_probs),
@@ -1937,9 +2097,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_entropy_tmpl,
 )
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__array(__s8, segment_quant_update, 4)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(tgid, fd, f),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__s8, segment_quant_update, 4)
 			 __array(__s8, segment_lf_update, 4)
 			 __array(__u8, segment_segment_probs, 3)
 			 __field(__u32, segment_flags)
@@ -1974,7 +2136,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 			 __field(__u64, golden_frame_ts)
 			 __field(__u64, alt_frame_ts)
 			 __field(__u64, flags)),
-	TP_fast_assign(memcpy(__entry->segment_quant_update, f->segment.quant_update,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->segment_quant_update, f->segment.quant_update,
 			      sizeof(__entry->segment_quant_update));
 		       memcpy(__entry->segment_lf_update, f->segment.lf_update,
 			      sizeof(__entry->segment_lf_update));
@@ -2015,7 +2179,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 		       __entry->golden_frame_ts = f->golden_frame_ts;
 		       __entry->alt_frame_ts = f->alt_frame_ts;
 		       __entry->flags = f->flags;),
-	TP_printk("\nsegment.quant_update %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nsegment.quant_update %s\n"
 		  "segment.lf_update %s\n"
 		  "segment.segment_probs %s\n"
 		  "segment.flags %s\n"
@@ -2050,6 +2215,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 		  "golden_frame_ts %llu\n"
 		  "alt_frame_ts %llu\n"
 		  "flags %s",
+		  __entry->tgid, __entry->fd,
 		  __print_array(__entry->segment_quant_update,
 				ARRAY_SIZE(__entry->segment_quant_update),
 				sizeof(__entry->segment_quant_update[0])),
@@ -2114,21 +2280,23 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp8_frame_tmpl,
 );
 
 DEFINE_EVENT(v4l2_ctrl_vp8_frame_tmpl, v4l2_ctrl_vp8_frame,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(tgid, fd, f)
 );
 
 DEFINE_EVENT(v4l2_ctrl_vp8_entropy_tmpl, v4l2_ctrl_vp8_entropy,
-	TP_PROTO(const struct v4l2_ctrl_vp8_frame *f),
-	TP_ARGS(f)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp8_frame *f),
+	TP_ARGS(tgid, fd, f)
 );
 
 /* VP9 controls */
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
-	TP_ARGS(f),
-	TP_STRUCT__entry(__array(__s8, lf_ref_deltas, 4)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_frame *f),
+	TP_ARGS(tgid, fd, f),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__s8, lf_ref_deltas, 4)
 			 __array(__s8, lf_mode_deltas, 2)
 			 __field(__u8, lf_level)
 			 __field(__u8, lf_sharpness)
@@ -2161,7 +2329,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 			 __field(__u8, tile_cols_log2)
 			 __field(__u8, tile_rows_log2)
 			 __field(__u8, reference_mode)),
-	TP_fast_assign(memcpy(__entry->lf_ref_deltas, f->lf.ref_deltas,
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->lf_ref_deltas, f->lf.ref_deltas,
 			      sizeof(__entry->lf_ref_deltas));
 		       memcpy(__entry->lf_mode_deltas, f->lf.mode_deltas,
 			      sizeof(__entry->lf_mode_deltas));
@@ -2200,7 +2370,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 		       __entry->tile_cols_log2 = f->tile_cols_log2;
 		       __entry->tile_rows_log2 = f->tile_rows_log2;
 		       __entry->reference_mode = f->reference_mode;),
-	TP_printk("\nlf.ref_deltas %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\nlf.ref_deltas %s\n"
 		  "lf.mode_deltas %s\n"
 		  "lf.level %u\n"
 		  "lf.sharpness %u\n"
@@ -2233,6 +2404,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 		  "tile_cols_log2 %u\n"
 		  "tile_rows_log_2 %u\n"
 		  "reference_mode %s\n",
+		  __entry->tgid, __entry->fd,
 		  __print_array(__entry->lf_ref_deltas,
 				ARRAY_SIZE(__entry->lf_ref_deltas),
 				sizeof(__entry->lf_ref_deltas[0])),
@@ -2313,9 +2485,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_frame_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h),
-	TP_STRUCT__entry(__field(__u8, tx_mode)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(tgid, fd, h),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __field(__u8, tx_mode)
 			 __array(__u8, tx8, 2 * 1)
 			 __array(__u8, tx16, 2 * 2)
 			 __array(__u8, tx32, 2 * 3)
@@ -2329,7 +2503,9 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 			 __array(__u8, y_mode, 4 * 9)
 			 __array(__u8, uv_mode, 10 * 9)
 			 __array(__u8, partition, 16 * 3)),
-	TP_fast_assign(__entry->tx_mode = h->tx_mode;
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       __entry->tx_mode = h->tx_mode;
 		       memcpy(__entry->tx8, h->tx8, sizeof(__entry->tx8));
 		       memcpy(__entry->tx16, h->tx16, sizeof(__entry->tx16));
 		       memcpy(__entry->tx32, h->tx32, sizeof(__entry->tx32));
@@ -2344,7 +2520,8 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 		       memcpy(__entry->y_mode, h->y_mode, sizeof(__entry->y_mode));
 		       memcpy(__entry->uv_mode, h->uv_mode, sizeof(__entry->uv_mode));
 		       memcpy(__entry->partition, h->partition, sizeof(__entry->partition));),
-	TP_printk("\ntx_mode %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\ntx_mode %s\n"
 		  "tx8 {%s}\n"
 		  "tx16 {%s}\n"
 		  "tx32 {%s}\n"
@@ -2358,6 +2535,7 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 		  "y_mode {%s}\n"
 		  "uv_mode {%s}\n"
 		  "partition {%s}\n",
+		  __entry->tgid, __entry->fd,
 		  __print_symbolic(__entry->tx_mode,
 		  {V4L2_VP9_TX_MODE_ONLY_4X4, "TX_MODE_ONLY_4X4"},
 		  {V4L2_VP9_TX_MODE_ALLOW_8X8, "TX_MODE_ALLOW_8X8"},
@@ -2416,11 +2594,17 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_hdr_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h),
-	TP_STRUCT__entry(__array(__u8, coef, 4 * 2 * 2 * 6 * 6 * 3)),
-	TP_fast_assign(memcpy(__entry->coef, h->coef, sizeof(__entry->coef));),
-	TP_printk("\n coef {%s}",
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(tgid, fd, h),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__u8, coef, 4 * 2 * 2 * 6 * 6 * 3)),
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->coef, h->coef, sizeof(__entry->coef));),
+	TP_printk("tgid = %u, fd = %u, "
+		  "\n coef {%s}",
+		  __entry->tgid, __entry->fd,
 		  __print_hex_dump("", DUMP_PREFIX_NONE, 32, 1,
 				   __entry->coef,
 				   sizeof(__entry->coef),
@@ -2429,9 +2613,11 @@ DECLARE_EVENT_CLASS(v4l2_ctrl_vp9_compressed_coef_tmpl,
 );
 
 DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
-	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
-	TP_ARGS(p),
-	TP_STRUCT__entry(__array(__u8, joint, 3)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_vp9_mv_probs *p),
+	TP_ARGS(tgid, fd, p),
+	TP_STRUCT__entry(__field(u32, tgid)
+			 __field(u32, fd)
+			 __array(__u8, joint, 3)
 			 __array(__u8, sign, 2)
 			 __array(__u8, classes, 2 * 10)
 			 __array(__u8, class0_bit, 2)
@@ -2440,7 +2626,9 @@ DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 			 __array(__u8, fr, 2 * 3)
 			 __array(__u8, class0_hp, 2)
 			 __array(__u8, hp, 2)),
-	TP_fast_assign(memcpy(__entry->joint, p->joint, sizeof(__entry->joint));
+	TP_fast_assign(__entry->tgid = tgid;
+		       __entry->fd = fd;
+		       memcpy(__entry->joint, p->joint, sizeof(__entry->joint));
 		       memcpy(__entry->sign, p->sign, sizeof(__entry->sign));
 		       memcpy(__entry->classes, p->classes, sizeof(__entry->classes));
 		       memcpy(__entry->class0_bit, p->class0_bit, sizeof(__entry->class0_bit));
@@ -2449,7 +2637,8 @@ DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 		       memcpy(__entry->fr, p->fr, sizeof(__entry->fr));
 		       memcpy(__entry->class0_hp, p->class0_hp, sizeof(__entry->class0_hp));
 		       memcpy(__entry->hp, p->hp, sizeof(__entry->hp));),
-	TP_printk("\n joint %s\n"
+	TP_printk("tgid = %u, fd = %u, "
+		  "\n joint %s\n"
 		  "sign %s\n"
 		  "classes {%s}\n"
 		  "class0_bit %s\n"
@@ -2458,6 +2647,7 @@ DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 		  "fr {%s}\n"
 		  "class0_hp %s\n"
 		  "hp %s\n",
+		  __entry->tgid, __entry->fd,
 		  __print_array(__entry->joint,
 				ARRAY_SIZE(__entry->joint),
 				sizeof(__entry->joint[0])),
@@ -2493,24 +2683,24 @@ DECLARE_EVENT_CLASS(v4l2_vp9_mv_probs_tmpl,
 );
 
 DEFINE_EVENT(v4l2_ctrl_vp9_frame_tmpl, v4l2_ctrl_vp9_frame,
-	TP_PROTO(const struct v4l2_ctrl_vp9_frame *f),
-	TP_ARGS(f)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_frame *f),
+	TP_ARGS(tgid, fd, f)
 );
 
 DEFINE_EVENT(v4l2_ctrl_vp9_compressed_hdr_tmpl, v4l2_ctrl_vp9_compressed_hdr,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(tgid, fd, h)
 );
 
 DEFINE_EVENT(v4l2_ctrl_vp9_compressed_coef_tmpl, v4l2_ctrl_vp9_compressed_coeff,
-	TP_PROTO(const struct v4l2_ctrl_vp9_compressed_hdr *h),
-	TP_ARGS(h)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_ctrl_vp9_compressed_hdr *h),
+	TP_ARGS(tgid, fd, h)
 );
 
 
 DEFINE_EVENT(v4l2_vp9_mv_probs_tmpl, v4l2_vp9_mv_probs,
-	TP_PROTO(const struct v4l2_vp9_mv_probs *p),
-	TP_ARGS(p)
+	TP_PROTO(u32 tgid, u32 fd, const struct v4l2_vp9_mv_probs *p),
+	TP_ARGS(tgid, fd, p)
 );
 
 #endif /* if !defined(_TRACE_V4L2_CONTROLS_H_) || defined(TRACE_HEADER_MULTI_READ) */

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:35 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:35 -0400
Subject: [PATCH v2 5/9] media: Add missing types to v4l2_ctrl_ptr
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-5-9756edf72ac1@collabora.com>

The v4l2_ctrl_ptr union contains pointers for all control types, but
v4l2_ctrl_hevc_decode_params and v4l2_ctrl_hevc_scaling_matrix are missing.

Add them.

Reviewed-by: Nicolas Dufresne <nicolas.dufresne at collabora.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 include/media/v4l2-ctrls.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 327976b14d50..a2b4c96a9a6f 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -49,6 +49,8 @@ struct video_device;
  * @p_hevc_sps:			Pointer to an HEVC sequence parameter set structure.
  * @p_hevc_pps:			Pointer to an HEVC picture parameter set structure.
  * @p_hevc_slice_params:	Pointer to an HEVC slice parameters structure.
+ * @p_hevc_decode_params:	Pointer to an HEVC decode parameters structure.
+ * @p_hevc_scaling_matrix	Pointer to an HEVC scaling matrix structure.
  * @p_hdr10_cll:		Pointer to an HDR10 Content Light Level structure.
  * @p_hdr10_mastering:		Pointer to an HDR10 Mastering Display structure.
  * @p_area:			Pointer to an area.
@@ -81,6 +83,8 @@ union v4l2_ctrl_ptr {
 	struct v4l2_ctrl_hevc_sps *p_hevc_sps;
 	struct v4l2_ctrl_hevc_pps *p_hevc_pps;
 	struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
+	struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
+	struct v4l2_ctrl_hevc_scaling_matrix *p_hevc_scaling_matrix;
 	struct v4l2_ctrl_vp9_compressed_hdr *p_vp9_compressed_hdr_probs;
 	struct v4l2_ctrl_vp9_frame *p_vp9_frame;
 	struct v4l2_ctrl_hdr10_cll_info *p_hdr10_cll;

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:36 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:36 -0400
Subject: [PATCH v2 6/9] media: Trace the stateless controls when set in
 v4l2-ctrls-core.c
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-6-9756edf72ac1@collabora.com>

Also remove the trace from visl as the generic v4l2-requests traces can
now be used instead.

It allows all stateless drivers to inherit traceability, with just a small
overhead when disabled in userspace.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/test-drivers/visl/visl-dec.c |  74 -------------------
 drivers/media/v4l2-core/v4l2-ctrls-api.c   |  10 +++
 drivers/media/v4l2-core/v4l2-ctrls-core.c  | 114 +++++++++++++++++++++++++++++
 include/media/v4l2-ctrls.h                 |  15 ++++
 4 files changed, 139 insertions(+), 74 deletions(-)

diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index 2a065a6249ad..9517830fb3e8 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -12,7 +12,6 @@
 #include <linux/workqueue.h>
 #include <media/v4l2-mem2mem.h>
 #include <media/tpg/v4l2-tpg.h>
-#include <trace/events/v4l2_controls.h>
 
 #define LAST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
 #define LAST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
@@ -486,78 +485,6 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
 	}
 }
 
-static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
-{
-	int i;
-	struct v4l2_fh *fh = &ctx->fh;
-
-	switch (ctx->current_codec) {
-	default:
-	case VISL_CODEC_NONE:
-		break;
-	case VISL_CODEC_FWHT:
-		trace_v4l2_ctrl_fwht_params(fh->tgid, fh->fd, run->fwht.params);
-		break;
-	case VISL_CODEC_MPEG2:
-		trace_v4l2_ctrl_mpeg2_sequence(fh->tgid, fh->fd, run->mpeg2.seq);
-		trace_v4l2_ctrl_mpeg2_picture(fh->tgid, fh->fd, run->mpeg2.pic);
-		trace_v4l2_ctrl_mpeg2_quantisation(fh->tgid, fh->fd, run->mpeg2.quant);
-		break;
-	case VISL_CODEC_VP8:
-		trace_v4l2_ctrl_vp8_frame(fh->tgid, fh->fd, run->vp8.frame);
-		trace_v4l2_ctrl_vp8_entropy(fh->tgid, fh->fd, run->vp8.frame);
-		break;
-	case VISL_CODEC_VP9:
-		trace_v4l2_ctrl_vp9_frame(fh->tgid, fh->fd, run->vp9.frame);
-		trace_v4l2_ctrl_vp9_compressed_hdr(fh->tgid, fh->fd, run->vp9.probs);
-		trace_v4l2_ctrl_vp9_compressed_coeff(fh->tgid, fh->fd, run->vp9.probs);
-		trace_v4l2_vp9_mv_probs(fh->tgid, fh->fd, &run->vp9.probs->mv);
-		break;
-	case VISL_CODEC_H264:
-		trace_v4l2_ctrl_h264_sps(fh->tgid, fh->fd, run->h264.sps);
-		trace_v4l2_ctrl_h264_pps(fh->tgid, fh->fd, run->h264.pps);
-		trace_v4l2_ctrl_h264_scaling_matrix(fh->tgid, fh->fd, run->h264.sm);
-		trace_v4l2_ctrl_h264_slice_params(fh->tgid, fh->fd, run->h264.spram);
-
-		for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
-			trace_v4l2_h264_ref_pic_list0(fh->tgid, fh->fd,
-						      &run->h264.spram->ref_pic_list0[i], i);
-		for (i = 0; i < ARRAY_SIZE(run->h264.spram->ref_pic_list0); i++)
-			trace_v4l2_h264_ref_pic_list1(fh->tgid, fh->fd,
-						      &run->h264.spram->ref_pic_list1[i], i);
-
-		trace_v4l2_ctrl_h264_decode_params(fh->tgid, fh->fd, run->h264.dpram);
-
-		for (i = 0; i < ARRAY_SIZE(run->h264.dpram->dpb); i++)
-			trace_v4l2_h264_dpb_entry(fh->tgid, fh->fd, &run->h264.dpram->dpb[i], i);
-
-		trace_v4l2_ctrl_h264_pred_weights(fh->tgid, fh->fd, run->h264.pwht);
-		break;
-	case VISL_CODEC_HEVC:
-		trace_v4l2_ctrl_hevc_sps(fh->tgid, fh->fd, run->hevc.sps);
-		trace_v4l2_ctrl_hevc_pps(fh->tgid, fh->fd, run->hevc.pps);
-		trace_v4l2_ctrl_hevc_slice_params(fh->tgid, fh->fd, run->hevc.spram);
-		trace_v4l2_ctrl_hevc_scaling_matrix(fh->tgid, fh->fd, run->hevc.sm);
-		trace_v4l2_ctrl_hevc_decode_params(fh->tgid, fh->fd, run->hevc.dpram);
-
-		for (i = 0; i < ARRAY_SIZE(run->hevc.dpram->dpb); i++)
-			trace_v4l2_hevc_dpb_entry(fh->tgid, fh->fd, &run->hevc.dpram->dpb[i]);
-
-
-		trace_v4l2_hevc_pred_weight_table(fh->tgid, fh->fd,
-						  &run->hevc.spram->pred_weight_table);
-		trace_v4l2_ctrl_hevc_ext_sps_lt_rps(fh->tgid, fh->fd, run->hevc.rps_lt);
-		trace_v4l2_ctrl_hevc_ext_sps_st_rps(fh->tgid, fh->fd, run->hevc.rps_st);
-		break;
-	case VISL_CODEC_AV1:
-		trace_v4l2_ctrl_av1_sequence(fh->tgid, fh->fd, run->av1.seq);
-		trace_v4l2_ctrl_av1_frame(fh->tgid, fh->fd, run->av1.frame);
-		trace_v4l2_ctrl_av1_film_grain(fh->tgid, fh->fd, run->av1.grain);
-		trace_v4l2_ctrl_av1_tile_group_entry(fh->tgid, fh->fd, run->av1.tge);
-		break;
-	}
-}
-
 void visl_device_run(void *priv)
 {
 	struct visl_ctx *ctx = priv;
@@ -634,7 +561,6 @@ void visl_device_run(void *priv)
 		      run.dst->sequence, run.dst->vb2_buf.timestamp);
 
 	visl_tpg_fill(ctx, &run);
-	visl_trace_ctrls(ctx, &run);
 
 	if (bitstream_trace_frame_start > -1 &&
 	    run.dst->sequence >= bitstream_trace_frame_start &&
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index 93d8d4012d0f..c44578828b21 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -523,6 +523,12 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
 }
 EXPORT_SYMBOL(v4l2_g_ext_ctrls);
 
+static void trace_ext_ctrl(struct v4l2_fh *fh, const struct v4l2_ctrl *ctrl)
+{
+	if (ctrl->type_ops->trace)
+		ctrl->type_ops->trace(fh, ctrl, ctrl->p_cur);
+}
+
 /* Validate a new control */
 static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
 {
@@ -711,6 +717,10 @@ int try_set_ext_ctrls_common(struct v4l2_fh *fh,
 				idx = helpers[idx].next;
 			} while (!ret && idx);
 		}
+
+		if (set)
+			trace_ext_ctrl(fh, master);
+
 		v4l2_ctrl_unlock(master);
 	}
 
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6b375720e395..d8a8dc7896c5 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -10,8 +10,11 @@
 #include <linux/slab.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
 #include <media/v4l2-fwnode.h>
 
+#include <trace/events/v4l2_controls.h>
+
 #include "v4l2-ctrls-priv.h"
 
 static const union v4l2_ctrl_ptr ptr_null;
@@ -1462,12 +1465,123 @@ int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl,
 }
 EXPORT_SYMBOL(v4l2_ctrl_type_op_validate);
 
+void v4l2_ctrl_type_op_trace(const struct v4l2_fh *fh,
+				    const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr)
+{
+	int i = 0;
+
+	switch ((u32)ctrl->type) {
+	case V4L2_CTRL_TYPE_FWHT_PARAMS:
+		trace_v4l2_ctrl_fwht_params(fh->tgid, fh->fd, ptr.p_fwht_params);
+		break;
+	case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
+		trace_v4l2_ctrl_mpeg2_sequence(fh->tgid, fh->fd, ptr.p_mpeg2_sequence);
+		break;
+	case V4L2_CTRL_TYPE_MPEG2_PICTURE:
+		trace_v4l2_ctrl_mpeg2_picture(fh->tgid, fh->fd, ptr.p_mpeg2_picture);
+		break;
+	case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
+		trace_v4l2_ctrl_mpeg2_quantisation(fh->tgid, fh->fd, ptr.p_mpeg2_quantisation);
+		break;
+	case V4L2_CTRL_TYPE_VP8_FRAME:
+		trace_v4l2_ctrl_vp8_frame(fh->tgid, fh->fd, ptr.p_vp8_frame);
+		trace_v4l2_ctrl_vp8_entropy(fh->tgid, fh->fd, ptr.p_vp8_frame);
+		break;
+	case V4L2_CTRL_TYPE_VP9_FRAME:
+		trace_v4l2_ctrl_vp9_frame(fh->tgid, fh->fd, ptr.p_vp9_frame);
+		break;
+	case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR:
+		trace_v4l2_ctrl_vp9_compressed_hdr(fh->tgid, fh->fd,
+						   ptr.p_vp9_compressed_hdr_probs);
+		trace_v4l2_ctrl_vp9_compressed_coeff(fh->tgid, fh->fd,
+						     ptr.p_vp9_compressed_hdr_probs);
+		trace_v4l2_vp9_mv_probs(fh->tgid, fh->fd, &ptr.p_vp9_compressed_hdr_probs->mv);
+		break;
+	case V4L2_CTRL_TYPE_H264_SPS:
+		trace_v4l2_ctrl_h264_sps(fh->tgid, fh->fd, ptr.p_h264_sps);
+		break;
+	case V4L2_CTRL_TYPE_H264_PPS:
+		trace_v4l2_ctrl_h264_pps(fh->tgid, fh->fd, ptr.p_h264_pps);
+		break;
+	case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+		trace_v4l2_ctrl_h264_scaling_matrix(fh->tgid, fh->fd, ptr.p_h264_scaling_matrix);
+		break;
+	case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+	{
+		struct v4l2_ctrl_h264_slice_params *sp = ptr.p_h264_slice_params;
+
+		trace_v4l2_ctrl_h264_slice_params(fh->tgid, fh->fd, sp);
+
+		for (i = 0; i < ARRAY_SIZE(sp->ref_pic_list0); i++)
+			trace_v4l2_h264_ref_pic_list0(fh->tgid, fh->fd, &sp->ref_pic_list0[i], i);
+		for (i = 0; i < ARRAY_SIZE(sp->ref_pic_list1); i++)
+			trace_v4l2_h264_ref_pic_list1(fh->tgid, fh->fd, &sp->ref_pic_list1[i], i);
+
+		break;
+	}
+	case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+	{
+		struct v4l2_ctrl_h264_decode_params *dp = ptr.p_h264_decode_params;
+
+		trace_v4l2_ctrl_h264_decode_params(fh->tgid, fh->fd, dp);
+
+		for (i = 0; i < ARRAY_SIZE(dp->dpb); i++)
+			trace_v4l2_h264_dpb_entry(fh->tgid, fh->fd, &dp->dpb[i], i);
+
+		break;
+	}
+	case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+		trace_v4l2_ctrl_h264_pred_weights(fh->tgid, fh->fd, ptr.p_h264_pred_weights);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_SPS:
+		trace_v4l2_ctrl_hevc_sps(fh->tgid, fh->fd, ptr.p_hevc_sps);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_PPS:
+		trace_v4l2_ctrl_hevc_pps(fh->tgid, fh->fd, ptr.p_hevc_pps);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+		trace_v4l2_ctrl_hevc_slice_params(fh->tgid, fh->fd, ptr.p_hevc_slice_params);
+		trace_v4l2_hevc_pred_weight_table(fh->tgid, fh->fd,
+						  &ptr.p_hevc_slice_params->pred_weight_table);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+		trace_v4l2_ctrl_hevc_scaling_matrix(fh->tgid, fh->fd, ptr.p_hevc_scaling_matrix);
+		break;
+	case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+	{
+		struct v4l2_ctrl_hevc_decode_params *dp = ptr.p_hevc_decode_params;
+
+		trace_v4l2_ctrl_hevc_decode_params(fh->tgid, fh->fd, dp);
+
+		for (i = 0; i < ARRAY_SIZE(dp->dpb); i++)
+			trace_v4l2_hevc_dpb_entry(fh->tgid, fh->fd, &dp->dpb[i]);
+
+		break;
+	}
+	case V4L2_CTRL_TYPE_AV1_SEQUENCE:
+		trace_v4l2_ctrl_av1_sequence(fh->tgid, fh->fd, ptr.p_av1_sequence);
+		break;
+	case V4L2_CTRL_TYPE_AV1_FRAME:
+		trace_v4l2_ctrl_av1_frame(fh->tgid, fh->fd, ptr.p_av1_frame);
+		break;
+	case V4L2_CTRL_TYPE_AV1_FILM_GRAIN:
+		trace_v4l2_ctrl_av1_film_grain(fh->tgid, fh->fd, ptr.p_av1_film_grain);
+		break;
+	case V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY:
+		trace_v4l2_ctrl_av1_tile_group_entry(fh->tgid, fh->fd, ptr.p_av1_tile_group_entry);
+		break;
+	}
+
+}
+EXPORT_SYMBOL(v4l2_ctrl_type_op_trace);
+
 static const struct v4l2_ctrl_type_ops std_type_ops = {
 	.equal = v4l2_ctrl_type_op_equal,
 	.init = v4l2_ctrl_type_op_init,
 	.minimum = v4l2_ctrl_type_op_minimum,
 	.maximum = v4l2_ctrl_type_op_maximum,
 	.log = v4l2_ctrl_type_op_log,
+	.trace = v4l2_ctrl_type_op_trace,
 	.validate = v4l2_ctrl_type_op_validate,
 };
 
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index a2b4c96a9a6f..57c4bb999b7b 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -140,6 +140,7 @@ struct v4l2_ctrl_ops {
  * @minimum: set the value to the minimum value of the control.
  * @maximum: set the value to the maximum value of the control.
  * @log: log the value.
+ * @trace: trace the value of the control with Ftrace.
  * @validate: validate the value for ctrl->new_elems array elements.
  *	Return 0 on success and a negative value otherwise.
  */
@@ -153,6 +154,8 @@ struct v4l2_ctrl_type_ops {
 	void (*maximum)(const struct v4l2_ctrl *ctrl, u32 idx,
 			union v4l2_ctrl_ptr ptr);
 	void (*log)(const struct v4l2_ctrl *ctrl);
+	void (*trace)(const struct v4l2_fh *fh,
+		      const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr);
 	int (*validate)(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr);
 };
 
@@ -1627,6 +1630,18 @@ void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
  */
 void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl);
 
+/**
+ * v4l2_ctrl_type_op_trace - Default v4l2_ctrl_type_ops trace callback.
+ *
+ * @fh: The v4l2_fh of the current context.
+ * @ctrl: The v4l2_ctrl pointer.
+ * @ptr: The v4l2 control value.
+ *
+ * Return: void
+ */
+void v4l2_ctrl_type_op_trace(const struct v4l2_fh *fh,
+			     const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr);
+
 /**
  * v4l2_ctrl_type_op_validate - Default v4l2_ctrl_type_ops validate callback.
  *

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:37 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:37 -0400
Subject: [PATCH v2 7/9] media: Add stream on/off traces and run them in the
 ioctl
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-7-9756edf72ac1@collabora.com>

This will automatically add stream on/off tracing for all v4l2 drivers.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 20 +++++++++++++++++--
 include/trace/events/v4l2.h          | 37 ++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index c8746a1637f5..b09489baff3e 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1963,13 +1963,29 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct file *file,
 static int v4l_streamon(const struct v4l2_ioctl_ops *ops, struct file *file,
 			void *arg)
 {
-	return ops->vidioc_streamon(file, NULL, *(unsigned int *)arg);
+	struct v4l2_fh *fh = file_to_v4l2_fh(file);
+	int err;
+
+	err = ops->vidioc_streamon(file, NULL, *(unsigned int *)arg);
+
+	if (!err)
+		trace_v4l2_streamon(fh->tgid, fh->fd);
+
+	return err;
 }
 
 static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, struct file *file,
 			 void *arg)
 {
-	return ops->vidioc_streamoff(file, NULL, *(unsigned int *)arg);
+	struct v4l2_fh *fh = file_to_v4l2_fh(file);
+	int err;
+
+	err = ops->vidioc_streamoff(file, NULL, *(unsigned int *)arg);
+
+	if (!err)
+		trace_v4l2_streamoff(fh->tgid, fh->fd);
+
+	return err;
 }
 
 static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, struct file *file,
diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h
index 248bc09bfc99..e5b80aeecc30 100644
--- a/include/trace/events/v4l2.h
+++ b/include/trace/events/v4l2.h
@@ -262,6 +262,43 @@ DEFINE_EVENT(vb2_v4l2_event_class, vb2_v4l2_qbuf,
 	TP_ARGS(q, vb)
 );
 
+
+/* Events for stream on/off.
+ *
+ * These events will be fired every time userspace starts or stops a stream.
+ * tgid and fd are used to identify the process that opened the video device.
+ *
+ * Note that this even can be fired multiple times for a given tgid/fd pair.
+ * E.g.: mem2mem drivers expect stream on/off on both output and capture queues.
+ */
+DECLARE_EVENT_CLASS(v4l2_stream_class,
+	TP_PROTO(u32 tgid, u32 fd),
+	TP_ARGS(tgid, fd),
+
+	TP_STRUCT__entry(
+		__field(u32, tgid)
+		__field(u32, fd)
+	),
+
+	TP_fast_assign(
+		__entry->tgid = tgid;
+		__entry->fd = fd;
+	),
+
+	TP_printk("tgid = %u, fd = %u",
+		  __entry->tgid, __entry->fd)
+);
+
+DEFINE_EVENT(v4l2_stream_class, v4l2_streamon,
+	TP_PROTO(u32 tgid, u32 fd),
+	TP_ARGS(tgid, fd)
+);
+
+DEFINE_EVENT(v4l2_stream_class, v4l2_streamoff,
+	TP_PROTO(u32 tgid, u32 fd),
+	TP_ARGS(tgid, fd)
+);
+
 #endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */
 
 /* This part must be outside protection */

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:38 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:38 -0400
Subject: [PATCH v2 8/9] media: Add HW run/done trace events
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-8-9756edf72ac1@collabora.com>

The events can be fired by drivers when the hardware is run and when it
is done.
That can be used by userspace tracers to see HW performance and usage.

The hw_done event allows setting the number of clock cycles the HW needed
to do the work, to help tools evaluate performances.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/v4l2-core/v4l2-trace.c |  3 +++
 include/trace/events/v4l2.h          | 40 ++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-trace.c b/drivers/media/v4l2-core/v4l2-trace.c
index 183d5ecb49c5..59cf6f8807ac 100644
--- a/drivers/media/v4l2-core/v4l2-trace.c
+++ b/drivers/media/v4l2-core/v4l2-trace.c
@@ -12,6 +12,9 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_buf_queue);
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_dqbuf);
 EXPORT_TRACEPOINT_SYMBOL_GPL(vb2_v4l2_qbuf);
 
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_hw_run);
+EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_hw_done);
+
 /* Export AV1 controls */
 EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_sequence);
 EXPORT_TRACEPOINT_SYMBOL_GPL(v4l2_ctrl_av1_frame);
diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h
index e5b80aeecc30..6f1bbb085cb0 100644
--- a/include/trace/events/v4l2.h
+++ b/include/trace/events/v4l2.h
@@ -299,6 +299,46 @@ DEFINE_EVENT(v4l2_stream_class, v4l2_streamoff,
 	TP_ARGS(tgid, fd)
 );
 
+
+/* Events for hardware run/done.
+ *
+ * These events will be fired respectively when the hardware is run (v4l2_hw_run) and done
+ * (v4l2_hw_done).
+ * As for other events, tgid and fd are used to identify the process that opened the video device.
+ *
+ * The v4l2_hw_done event also includes the number of hardware cycles taken by the hardware to
+ * process the command.
+ */
+DEFINE_EVENT(v4l2_stream_class, v4l2_hw_run,
+	TP_PROTO(u32 tgid, u32 fd),
+	TP_ARGS(tgid, fd)
+);
+
+DECLARE_EVENT_CLASS(v4l2_hw_done_class,
+	TP_PROTO(u32 tgid, u32 fd, u32 hw_cycles),
+	TP_ARGS(tgid, fd, hw_cycles),
+
+	TP_STRUCT__entry(
+		__field(u32, tgid)
+		__field(u32, fd)
+		__field(u32, hw_cycles)
+	),
+
+	TP_fast_assign(
+		__entry->tgid = tgid;
+		__entry->fd = fd;
+		__entry->hw_cycles = hw_cycles;
+	),
+
+	TP_printk("tgid = %u, fd = %u, hw_cycles = %u",
+		  __entry->tgid, __entry->fd, __entry->hw_cycles)
+);
+
+DEFINE_EVENT(v4l2_hw_done_class, v4l2_hw_done,
+	TP_PROTO(u32 tgid, u32 fd, u32 hw_cycles),
+	TP_ARGS(tgid, fd, hw_cycles)
+);
+
 #endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */
 
 /* This part must be outside protection */

-- 
2.54.0



From detlev.casanova at collabora.com  Wed Jun 10 07:33:39 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Wed, 10 Jun 2026 10:33:39 -0400
Subject: [PATCH v2 9/9] media: hantro: Add v4l2_hw run/done traces
In-Reply-To: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
References: <20260610-v4l2-add-ftrace-v2-0-9756edf72ac1@collabora.com>
Message-ID: <20260610-v4l2-add-ftrace-v2-9-9756edf72ac1@collabora.com>

Add the trace calls as well as retrieving the number of clock cycles for
the rockchip_vpu core.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/platform/verisilicon/hantro.h               |  1 +
 drivers/media/platform/verisilicon/hantro_drv.c           | 10 ++++++++++
 drivers/media/platform/verisilicon/rockchip_vpu981_regs.h |  1 +
 drivers/media/platform/verisilicon/rockchip_vpu_hw.c      |  4 ++++
 4 files changed, 16 insertions(+)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 0353de154a1e..d5cddc783688 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -253,6 +253,7 @@ struct hantro_ctx {
 
 	u32 sequence_cap;
 	u32 sequence_out;
+	u32 hw_cycles;
 
 	const struct hantro_fmt *vpu_src_fmt;
 	struct v4l2_pix_format_mplane src_fmt;
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 2e81877f640f..32855b14e0f1 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -25,6 +25,8 @@
 #include <media/videobuf2-core.h>
 #include <media/videobuf2-vmalloc.h>
 
+#include <trace/events/v4l2.h>
+
 #include "hantro_v4l2.h"
 #include "hantro.h"
 #include "hantro_hw.h"
@@ -103,6 +105,9 @@ void hantro_irq_done(struct hantro_dev *vpu,
 	struct hantro_ctx *ctx =
 		v4l2_m2m_get_curr_priv(vpu->m2m_dev);
 
+	if (ctx)
+		trace_v4l2_hw_done(ctx->fh.tgid, ctx->fh.fd, ctx->hw_cycles);
+
 	/*
 	 * If cancel_delayed_work returns false
 	 * the timeout expired. The watchdog is running,
@@ -125,6 +130,9 @@ void hantro_watchdog(struct work_struct *work)
 	ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
 	if (ctx) {
 		vpu_err("frame processing timed out!\n");
+
+		trace_v4l2_hw_done(ctx->fh.tgid, ctx->fh.fd, ctx->hw_cycles);
+
 		if (ctx->codec_ops->reset)
 			ctx->codec_ops->reset(ctx);
 		hantro_job_finish(vpu, ctx, VB2_BUF_STATE_ERROR);
@@ -189,6 +197,8 @@ static void device_run(void *priv)
 	if (ctx->codec_ops->run(ctx))
 		goto err_cancel_job;
 
+	trace_v4l2_hw_run(ctx->fh.tgid, ctx->fh.fd);
+
 	return;
 
 err_cancel_job:
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
index e4008da64f19..96b85470208b 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h
@@ -451,6 +451,7 @@
 #define av1_pp0_dup_ver			AV1_DEC_REG(394, 16, 0xff)
 #define av1_pp0_dup_hor			AV1_DEC_REG(394, 24, 0xff)
 
+#define AV1_CYCLE_COUNT			(AV1_SWREG(63))
 #define AV1_TILE_OUT_LU			(AV1_SWREG(65))
 #define AV1_REFERENCE_Y(i)		(AV1_SWREG(67) + ((i) * 0x8))
 #define AV1_SEGMENTATION		(AV1_SWREG(81))
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
index 02673be9878e..f959151b6645 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c
@@ -424,6 +424,8 @@ static irqreturn_t rk3588_vpu981_irq(int irq, void *dev_id)
 {
 	struct hantro_dev *vpu = dev_id;
 	enum vb2_buffer_state state;
+	struct hantro_ctx *ctx =
+		v4l2_m2m_get_curr_priv(vpu->m2m_dev);
 	u32 status;
 
 	status = vdpu_read(vpu, AV1_REG_INTERRUPT);
@@ -433,6 +435,8 @@ static irqreturn_t rk3588_vpu981_irq(int irq, void *dev_id)
 	vdpu_write(vpu, 0, AV1_REG_INTERRUPT);
 	vdpu_write(vpu, AV1_REG_CONFIG_DEC_CLK_GATE_E, AV1_REG_CONFIG);
 
+	ctx->hw_cycles = vdpu_read(vpu, AV1_CYCLE_COUNT);
+
 	hantro_irq_done(vpu, state);
 
 	return IRQ_HANDLED;

-- 
2.54.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:01 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:01 -0500
Subject: [PATCH V7 0/6] Add Anbernic RG Vita-Pro
Message-ID: <20260610144407.438846-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the Anbernic RG Vita-Pro, based on the Rockchip RK3576 SoC.

Changes Since V1:
 - Updated documentation filename to matche compatible string.
 - Corrected order of allocating IRQ in charger driver and switched
   to using devm managed function to allocate work queue.
Changes Since V2:
 - Corrected issue with naming of panel binding document and added
   fallback compatible string.
 - Switched to devm helpers in panel driver. Note that
   devm_drm_panel_add() is currently only in the drm-next branch.
 - Optimized setting GPIOs for panel driver.
Changes Since V3:
 - Fixed numerous issues identifed by Sashiko bot, mainly relating
   to unclamped or improperly clamped values from within the
   charger driver.
 - Corrected hard-coded values in the panel driver unprepare routine
   as well as correcting an improperly checked return condition.
Changes Since V4:
 - Fixed errors identified by Sashiko bot on charger driver that could
   result in an improper value being written to the registers.
 - Corrected some error handling in the panel driver.
Changes Since V5:
 - Corrected minor errors in documentation and added default values.
 - Further corrected clamping behavior in charger driver.
Changes Since V6:
 - Additional corrections as suggested by Sashiko bot to fix potential
   edge cases during probe for sgm41542.
 - Corrected an improperly shifted value being written to register for
   sgm41542.
 - Changed a MV value to UV in sgm41542 driver to simplify function.

Chris Morgan (6):
  dt-bindings: power: supply: sgm41542: document sgm41542
  power: supply: sgm41542: Add SG Micro sgm41542 charger
  dt-bindings: display: panel: Add Anbernic TD4310 panel
  drm/panel: anbernic-td4310: Add RG Vita Pro panel
  dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
  arm64: dts: rockchip: Add Anbernic RG Vita-Pro

 .../devicetree/bindings/arm/rockchip.yaml     |    6 +
 .../display/panel/anbernic,td4310.yaml        |   66 +
 .../power/supply/sgmicro,sgm41542.yaml        |   96 ++
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 drivers/gpu/drm/panel/Kconfig                 |   10 +
 drivers/gpu/drm/panel/Makefile                |    1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c |  257 ++++
 drivers/power/supply/Kconfig                  |    8 +
 drivers/power/supply/Makefile                 |    1 +
 drivers/power/supply/sgm41542_charger.c       | 1067 +++++++++++++
 11 files changed, 2840 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
 create mode 100644 drivers/power/supply/sgm41542_charger.c

-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:02 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:02 -0500
Subject: [PATCH V7 1/6] dt-bindings: power: supply: sgm41542: document sgm41542
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Document the SG Micro sgm41542 battery charger/boost converter.
The parameters of input-current-limit-microamp and
input-voltage-limit-microvolt are defined as such since they are in
common use among multiple bindings currently.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 .../power/supply/sgmicro,sgm41542.yaml        | 96 +++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
new file mode 100644
index 000000000000..af80fe528505
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml
@@ -0,0 +1,96 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/sgmicro,sgm41542.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SGM41542 Battery Charger
+
+description:
+  The SGMicro SGM41542 is a single cell battery charger/boost controller.
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+  - Xu Shengfei <xsf at rock-chips.com>
+
+allOf:
+  - $ref: power-supply.yaml#
+
+properties:
+  compatible:
+    const: sgmicro,sgm41542
+
+  input-current-limit-microamp:
+    default: 2400000
+    minimum: 100000
+    maximum: 3800000
+
+  input-voltage-limit-microvolt:
+    default: 4500000
+    minimum: 3900000
+    maximum: 12000000
+
+  interrupts:
+    maxItems: 1
+
+  monitored-battery:
+    description: |
+        The charger uses the following battery properties
+        constant-charge-current-max-microamp (default 2040000)
+        constant-charge-voltage-max-microvolt (default 4208000)
+        charge-term-current-microamp (default 180000)
+        precharge-current-microamp (default 180000)
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    properties:
+      otg-vbus:
+        type: object
+        description: OTG boost regulator
+        $ref: /schemas/regulator/regulator.yaml
+        unevaluatedProperties: false
+    additionalProperties: false
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    battery: battery {
+      compatible = "simple-battery";
+      constant-charge-current-max-microamp = <10000000>;
+      constant-charge-voltage-max-microvolt = <4350000>;
+      precharge-current-microamp = <180000>;
+      charge-term-current-microamp = <300000>;
+    };
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      charger at 3b {
+        compatible = "sgmicro,sgm41542";
+        reg = <0x3b>;
+        input-current-limit-microamp = <3000000>;
+        input-voltage-limit-microvolt = <4500000>;
+        interrupt-parent = <&gpio0>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        monitored-battery = <&battery>;
+
+        regulators {
+          otg-vbus {
+            regulator-max-microvolt = <5000000>;
+            regulator-min-microvolt = <5000000>;
+          };
+        };
+      };
+    };
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:03 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:03 -0500
Subject: [PATCH V7 2/6] power: supply: sgm41542: Add SG Micro sgm41542 charger
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the SG Micro SGM41542 charger/boost converter.
Driver was adapted from Rockchip BSP driver [1] and confirmed
with vendor datasheet [2].

[1] https://github.com/rockchip-linux/kernel/blob/develop-6.6/drivers/power/supply/sgm41542_charger.c
[2] https://www.sg-micro.de/rect/assets/1e8de70b-657e-4156-be68-a64fdbe8e418/SGM41541_SGM41542.pdf

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/power/supply/Kconfig            |    8 +
 drivers/power/supply/Makefile           |    1 +
 drivers/power/supply/sgm41542_charger.c | 1067 +++++++++++++++++++++++
 3 files changed, 1076 insertions(+)
 create mode 100644 drivers/power/supply/sgm41542_charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 83392ed6a8da..57dae0913472 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -856,6 +856,14 @@ config CHARGER_RK817
 	help
 	  Say Y to include support for Rockchip RK817 Battery Charger.
 
+config CHARGER_SGM41542
+	tristate "SGM41542 charger driver"
+	depends on I2C
+	depends on GPIOLIB || COMPILE_TEST
+	select REGMAP_I2C
+	help
+	  Say Y to enable support for the SGM41542 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB3XX Battery Charger"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7ee839dca7f3..c376889db317 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -107,6 +107,7 @@ obj-$(CONFIG_CHARGER_BQ25890)	+= bq25890_charger.o
 obj-$(CONFIG_CHARGER_BQ25980)	+= bq25980_charger.o
 obj-$(CONFIG_CHARGER_BQ256XX)	+= bq256xx_charger.o
 obj-$(CONFIG_CHARGER_RK817)	+= rk817_charger.o
+obj-$(CONFIG_CHARGER_SGM41542)	+= sgm41542_charger.o
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
diff --git a/drivers/power/supply/sgm41542_charger.c b/drivers/power/supply/sgm41542_charger.c
new file mode 100644
index 000000000000..3e8c50b6a134
--- /dev/null
+++ b/drivers/power/supply/sgm41542_charger.c
@@ -0,0 +1,1067 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Charger driver for SGM4154x
+ *
+ * Copyright (c) 2026 Rockchip Electronics Co., Ltd.
+ *
+ * Author: Xu Shengfei <xsf at rock-chips.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/types.h>
+
+#define SGM4154X_MANUFACTURER			"SGMICRO"
+#define SGM4154X_NAME				"sgm41542"
+
+#define SGM4154X_CHRG_CTRL_0			0x00
+#define SGM4154X_HIZ_EN				BIT(7)
+#define SGM4154X_IINDPM_I_MASK			GENMASK(4, 0)
+#define SGM4154X_IINDPM_I_MIN_UA		100000
+#define SGM4154X_IINDPM_I_MAX_UA		3800000
+#define SGM4154X_IINDPM_STEP_UA			100000
+#define SGM4154X_IINDPM_DEF_UA			2400000
+
+#define SGM4154X_CHRG_CTRL_1			0x01
+#define SGM4154X_WDT_RST			BIT(6)
+#define SGM4154X_OTG_EN				BIT(5)
+#define SGM4154X_CHRG_EN			BIT(4)
+
+#define SGM4154X_CHRG_CTRL_2			0x02
+#define SGM4154X_BOOST_LIM			BIT(7)
+#define SGM4154X_ICHRG_CUR_MASK			GENMASK(5, 0)
+#define SGM4154X_ICHRG_I_STEP_UA		60000
+#define SGM4154X_ICHRG_I_MIN_UA			0
+#define SGM4154X_ICHRG_I_MAX_UA			3780000
+#define SGM4154X_ICHRG_I_DEF_UA			2040000
+
+#define SGM4154X_CHRG_CTRL_3			0x03
+#define SGM4154X_PRECHRG_CUR_MASK		GENMASK(7, 4)
+#define SGM4154X_PRECHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_PRECHRG_I_MIN_UA		60000
+#define SGM4154X_PRECHRG_I_MAX_UA		780000
+#define SGM4154X_PRECHRG_I_DEF_UA		180000
+#define SGM4154X_TERMCHRG_CUR_MASK		GENMASK(3, 0)
+#define SGM4154X_TERMCHRG_CURRENT_STEP_UA	60000
+#define SGM4154X_TERMCHRG_I_MIN_UA		60000
+#define SGM4154X_TERMCHRG_I_MAX_UA		960000
+#define SGM4154X_TERMCHRG_I_DEF_UA		180000
+
+#define SGM4154X_CHRG_CTRL_4			0x04
+#define SGM4154X_VREG_V_MASK			GENMASK(7, 3)
+#define SGM4154X_VREG_V_MAX_UV			4624000
+#define SGM4154X_VREG_V_MIN_UV			3856000
+#define SGM4154X_VREG_V_DEF_UV			4208000
+#define SGM4154X_VREG_V_STEP_UV			32000
+#define SGM4154X_VRECHARGE			BIT(0)
+#define SGM4154X_VRECHRG_STEP_UV		100000
+#define SGM4154X_VRECHRG_OFFSET_UV		100000
+
+#define SGM4154X_CHRG_CTRL_5			0x05
+#define SGM4154X_TERM_EN			BIT(7)
+#define SGM4154X_WDT_TIMER_MASK			GENMASK(5, 4)
+
+#define SGM4154X_CHRG_CTRL_6			0x06
+#define SGM4154X_VAC_OVP_MASK			GENMASK(7, 6)
+#define SGM4154X_OVP_14V			(BIT(7) | BIT(6))
+#define SGM4154X_OVP_10_5V			BIT(7)
+#define SGM4154X_OVP_6_5V			BIT(6)
+#define SGM4154X_OVP_5_5V			0
+#define SGM4154X_OVP_DEFAULT			SGM4154X_OVP_14V
+#define SGM4154X_BOOSTV				GENMASK(5, 4)
+#define SGM4154X_VINDPM_V_MASK			GENMASK(3, 0)
+#define SGM4154X_VINDPM_V_MIN_UV		3900000
+#define SGM4154X_VINDPM_V_MAX_UV		12000000
+#define SGM4154X_VINDPM_STEP_UV			100000
+#define SGM4154X_VINDPM_DEF_UV			4500000
+
+#define SGM4154X_CHRG_CTRL_7			0x07
+
+#define SGM4154X_CHRG_STAT		0x08
+#define SGM4154X_VBUS_STAT_MASK		GENMASK(7, 5)
+#define SGM4154X_OTG_MODE		(BIT(7) | BIT(6) | BIT(5))
+#define SGM4154X_NON_STANDARD		(BIT(7) | BIT(6))
+#define SGM4154X_UNKNOWN		(BIT(7) | BIT(5))
+#define SGM4154X_USB_DCP		(BIT(6) | BIT(5))
+#define SGM4154X_USB_CDP		BIT(6)
+#define SGM4154X_USB_SDP		BIT(5)
+#define SGM4154X_NOT_CHRGING		0
+#define SGM4154X_CHG_STAT_MASK		GENMASK(4, 3)
+#define SGM4154X_TERM_CHRG		(BIT(4) | BIT(3))
+#define SGM4154X_FAST_CHRG		BIT(4)
+#define SGM4154X_PRECHRG		BIT(3)
+#define SGM4154X_PG_STAT		BIT(2)
+#define SGM4154X_THERM_STAT		BIT(1)
+#define SGM4154X_VSYS_STAT		BIT(0)
+
+#define SGM4154X_CHRG_FAULT		0x09
+#define SGM4154X_TEMP_MASK		GENMASK(2, 0)
+#define SGM4154X_TEMP_HOT		(BIT(2) | BIT(1))
+#define SGM4154X_TEMP_COLD		(BIT(2) | BIT(0))
+#define SGM4154X_TEMP_COOL		(BIT(1) | BIT(0))
+#define SGM4154X_TEMP_WARM		BIT(1)
+#define SGM4154X_TEMP_NORMAL		BIT(0)
+
+#define SGM4154X_CHRG_CTRL_A		0x0a
+#define SGM4154X_VBUS_GOOD		BIT(7)
+#define SGM4154X_VINDPM_INT_MASK	BIT(1)
+#define SGM4154X_IINDPM_INT_MASK	BIT(0)
+
+#define SGM4154X_CHRG_CTRL_B		0x0b
+#define SGM4154X_PN_ID			(BIT(6) | BIT(5) | BIT(3))
+#define SGM4154X_PN_MASK		GENMASK(6, 3)
+
+#define SGM4154X_CHRG_CTRL_C		0x0c
+
+#define SGM4154X_CHRG_CTRL_D		0x0d
+#define SGM4154X_JEITA_EN		BIT(0)
+
+#define SGM4154X_INPUT_DET		0x0e
+#define SGM4154X_DPDM_ONGOING		BIT(7)
+
+#define SGM4154X_CHRG_CTRL_F		0x0f
+#define SGM4154X_VINDPM_OS_MASK	 GENMASK(1, 0)
+
+#define SGM4154X_DEFAULT_INPUT_CUR	(500 * 1000)
+
+struct sgm4154x_init_data {
+	int ilim;	/* input current limit */
+	int vlim;	/* minimum system voltage limit */
+	int iterm;	/* termination current */
+	int iprechg;	/* precharge current */
+	int max_ichg;	/* maximum charge current */
+	int max_vreg;	/* maximum charge voltage */
+};
+
+struct sgm4154x_state {
+	bool vsys_stat;
+	bool therm_stat;
+	bool online;
+	u8 chrg_stat;
+	bool chrg_en;
+	bool vbus_gd;
+	u8 chrg_type;
+	u8 health;
+	u8 chrg_fault;
+	u8 ntc_fault;
+};
+
+struct sgm4154x_device {
+	struct device *dev;
+	struct power_supply *charger;
+	struct regmap *regmap;
+	struct sgm4154x_init_data init_data;
+	struct sgm4154x_state state;
+	struct regulator_dev *otg_rdev;
+	bool watchdog_enable;
+	struct workqueue_struct *sgm_monitor_wq;
+	struct delayed_work sgm_delay_work;
+};
+
+enum SGM4154X_VINDPM_OS {
+	VINDPM_OS_3900MV,
+	VINDPM_OS_5900MV,
+	VINDPM_OS_7500MV,
+	VINDPM_OS_10500MV,
+};
+
+enum sgm4154x_wdt_values {
+	SGM4154X_WDT_TIMER_DISABLE = 0,
+	SGM4154X_WDT_TIMER_40S = 1,
+	SGM4154X_WDT_TIMER_80S = 2,
+	SGM4154X_WDT_TIMER_160S = 3,
+};
+
+static int sgm4154x_set_term_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_TERMCHRG_I_MIN_UA, SGM4154X_TERMCHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_TERMCHRG_I_MIN_UA) / SGM4154X_TERMCHRG_CURRENT_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_TERMCHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set term current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_prechrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_PRECHRG_I_MIN_UA, SGM4154X_PRECHRG_I_MAX_UA);
+	reg_val = (cur_ua - SGM4154X_PRECHRG_I_MIN_UA) / SGM4154X_PRECHRG_CURRENT_STEP_UA;
+
+	reg_val = FIELD_PREP(SGM4154X_PRECHRG_CUR_MASK, reg_val);
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_3,
+				 SGM4154X_PRECHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set precharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_ichrg_curr(struct sgm4154x_device *sgm, int cur_ua)
+{
+	int reg_val;
+	int ret;
+
+	cur_ua = clamp(cur_ua, SGM4154X_ICHRG_I_MIN_UA, sgm->init_data.max_ichg);
+	reg_val = cur_ua / SGM4154X_ICHRG_I_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_2,
+				 SGM4154X_ICHRG_CUR_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set icharge current error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_ichrg_curr(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_2, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge current error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_ICHRG_CUR_MASK, reg);
+
+	return val * SGM4154X_ICHRG_I_STEP_UA;
+}
+
+static int sgm4154x_set_chrg_volt(struct sgm4154x_device *sgm, int chrg_volt)
+{
+	int reg_val;
+	int ret;
+
+	/*
+	 * Note that the value of 0x01111 represents a "special value"
+	 * corresponding to 4352000uV instead of the expected 4336000uV,
+	 * per the datasheet. All other values are as expected. So not
+	 * only do we need to clamp between max and min values, but
+	 * also clamp anything below 4352000uv to 4304000uv to prevent
+	 * overcharging.
+	 */
+	chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, sgm->init_data.max_vreg);
+	if (chrg_volt < 4352000)
+		chrg_volt = clamp(chrg_volt, SGM4154X_VREG_V_MIN_UV, 4304000);
+	reg_val = (chrg_volt - SGM4154X_VREG_V_MIN_UV) / SGM4154X_VREG_V_STEP_UV;
+	reg_val = FIELD_PREP(SGM4154X_VREG_V_MASK, reg_val);
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VREG_V_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set charge voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_chrg_volt(struct sgm4154x_device *sgm)
+{
+	u32 reg;
+	int ret, val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_4, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "get charge voltage error!\n");
+		return ret;
+	}
+
+	val = FIELD_GET(SGM4154X_VREG_V_MASK, reg);
+
+	/*
+	 * 0x01111 is a special value meaning 4352000uV, all other
+	 * values are as expected based on the offset and step values.
+	 */
+	if (val == 0x0f)
+		return 4352000;
+
+	return val * SGM4154X_VREG_V_STEP_UV + SGM4154X_VREG_V_MIN_UV;
+}
+
+static int sgm4154x_set_input_volt_lim(struct sgm4154x_device *sgm,
+				       unsigned int vindpm)
+{
+	enum SGM4154X_VINDPM_OS os_val;
+	unsigned int offset;
+	u8 reg_val;
+	int ret;
+
+
+	if (vindpm < SGM4154X_VINDPM_V_MIN_UV ||
+	    vindpm > SGM4154X_VINDPM_V_MAX_UV) {
+		dev_err(sgm->dev, "input voltage limit %u outside range\n", vindpm);
+		return -EINVAL;
+	}
+
+	/*
+	 * Supported ranges per the datasheet are as follows:
+	 * 3.9v - 5.4v with a 3.9v offset
+	 * 5.9v - 7.4v with a 5.9v offset
+	 * 7.5v - 9.0v with a 7.5v offset
+	 * 10.5v - 12.0v with a 10.5v offset
+	 * Step size is a constant 100mv
+	 */
+	if (vindpm < 5900000) {
+		offset = 3900000;
+		vindpm = clamp(vindpm, offset, 5400000);
+		os_val = VINDPM_OS_3900MV;
+	} else if (vindpm < 7500000) {
+		offset = 5900000;
+		vindpm = clamp(vindpm, offset, 7400000);
+		os_val = VINDPM_OS_5900MV;
+	} else if (vindpm < 10500000) {
+		offset = 7500000;
+		vindpm = clamp(vindpm, offset, 9000000);
+		os_val = VINDPM_OS_7500MV;
+	} else {
+		offset = 10500000;
+		vindpm = clamp(vindpm, offset, 12000000);
+		os_val = VINDPM_OS_10500MV;
+	}
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_F,
+				 SGM4154X_VINDPM_OS_MASK,
+				 os_val);
+	if (ret) {
+		dev_err(sgm->dev, "set vin dpm error!\n");
+		return ret;
+	}
+
+	reg_val = (vindpm - offset) / SGM4154X_VINDPM_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap, SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VINDPM_V_MASK, reg_val);
+	if (ret)
+		dev_err(sgm->dev, "input voltage error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_input_curr_lim(struct sgm4154x_device *sgm, int iindpm)
+{
+	int reg_val;
+	int ret;
+
+	if (iindpm < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Protect against a timing-issue edge case if a sysfs write occurs in the middle
+	 * of a probe (very unlikely).
+	 */
+	if (sgm->init_data.ilim < SGM4154X_IINDPM_I_MIN_UA)
+		return -EINVAL;
+
+	/*
+	 * Per the datasheet, values between 100000uA and 3100000uA work
+	 * as expected with the register defined as having a step of
+	 * 100000 and a min/max of 100000 (0x00) through 3100000 (0x1e).
+	 * The register value of 0x1f however corresponds to 3800000uA not
+	 * 3200000uA as one would expect.
+	 */
+	if ((iindpm > SGM4154X_IINDPM_I_MAX_UA) || (iindpm > sgm->init_data.ilim))
+		iindpm = min(SGM4154X_IINDPM_I_MAX_UA, sgm->init_data.ilim);
+
+	if (iindpm > 3100000 && iindpm < SGM4154X_IINDPM_I_MAX_UA)
+		iindpm = 3100000;
+
+	if (iindpm == SGM4154X_IINDPM_I_MAX_UA)
+		reg_val = 0x1f;
+	else
+		reg_val = (iindpm - SGM4154X_IINDPM_I_MIN_UA) / SGM4154X_IINDPM_STEP_UA;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_0,
+				 SGM4154X_IINDPM_I_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set input current limit error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_input_curr_lim(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int ilim;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_0, &ilim);
+	if (ret) {
+		dev_err(sgm->dev, "get input current limit error!\n");
+		return ret;
+	}
+
+	ilim &= SGM4154X_IINDPM_I_MASK;
+
+	/* Max value is not 3200000uA as expected but is 3800000uA */
+	if (ilim == SGM4154X_IINDPM_I_MASK)
+		return SGM4154X_IINDPM_I_MAX_UA;
+
+	ilim = ilim * SGM4154X_IINDPM_STEP_UA + SGM4154X_IINDPM_I_MIN_UA;
+
+	return ilim;
+}
+
+static int sgm4154x_watchdog_timer_reset(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_WDT_RST,
+				 SGM4154X_WDT_RST);
+
+	if (ret)
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_watchdog_timer(struct sgm4154x_device *sgm, u8 time)
+{
+	int ret;
+
+	if (time > SGM4154X_WDT_TIMER_160S)
+		return -EINVAL;
+
+	time = FIELD_PREP(SGM4154X_WDT_TIMER_MASK, time);
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_5,
+				 SGM4154X_WDT_TIMER_MASK,
+				 time);
+
+	if (ret) {
+		dev_err(sgm->dev, "set watchdog timer error!\n");
+		return ret;
+	}
+
+	if (time) {
+		if (!sgm->watchdog_enable)
+			queue_delayed_work(sgm->sgm_monitor_wq,
+					   &sgm->sgm_delay_work,
+					   msecs_to_jiffies(1000 * 5));
+		sgm->watchdog_enable = true;
+	} else {
+		sgm->watchdog_enable = false;
+		sgm4154x_watchdog_timer_reset(sgm);
+	}
+
+	return ret;
+}
+
+static int sgm4154x_enable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 SGM4154X_CHRG_EN);
+	if (ret)
+		dev_err(sgm->dev, "enable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_disable_charger(struct sgm4154x_device *sgm)
+{
+	int ret;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_1,
+				 SGM4154X_CHRG_EN,
+				 0);
+	if (ret)
+		dev_err(sgm->dev, "disable charger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_vac_ovp(struct sgm4154x_device *sgm)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = SGM4154X_OVP_DEFAULT & SGM4154X_VAC_OVP_MASK;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_6,
+				 SGM4154X_VAC_OVP_MASK,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set vac ovp error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_set_recharge_volt_ua(struct sgm4154x_device *sgm, int recharge_volt)
+{
+	int reg_val;
+	int ret;
+
+	reg_val = (recharge_volt - SGM4154X_VRECHRG_OFFSET_UV) / SGM4154X_VRECHRG_STEP_UV;
+
+	ret = regmap_update_bits(sgm->regmap,
+				 SGM4154X_CHRG_CTRL_4,
+				 SGM4154X_VRECHARGE,
+				 reg_val);
+	if (ret)
+		dev_err(sgm->dev, "set recharger error!\n");
+
+	return ret;
+}
+
+static int sgm4154x_get_state(struct sgm4154x_device *sgm,
+			      struct sgm4154x_state *state)
+{
+	int reg, ret;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_STAT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_STAT fail\n");
+		return ret;
+	}
+	state->chrg_type = reg & SGM4154X_VBUS_STAT_MASK;
+	state->chrg_stat = reg & SGM4154X_CHG_STAT_MASK;
+	state->online = !!(reg & SGM4154X_PG_STAT);
+	state->therm_stat = !!(reg & SGM4154X_THERM_STAT);
+	state->vsys_stat = !!(reg & SGM4154X_VSYS_STAT);
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_FAULT, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_FAULT fail\n");
+		return ret;
+	}
+	state->chrg_fault = reg;
+	state->ntc_fault = reg & SGM4154X_TEMP_MASK;
+	state->health = state->ntc_fault;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_A, &reg);
+	if (ret) {
+		dev_err(sgm->dev, "read SGM4154X_CHRG_CTRL_A fail\n");
+		return ret;
+	}
+	state->vbus_gd = !!(reg & SGM4154X_VBUS_GOOD);
+
+	return ret;
+}
+
+static int sgm4154x_property_is_writeable(struct power_supply *psy,
+					  enum power_supply_property prop)
+{
+	switch (prop) {
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_ONLINE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int sgm4154x_charger_set_property(struct power_supply *psy,
+					 enum power_supply_property prop,
+					 const union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	int ret = -EINVAL;
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			ret = sgm4154x_enable_charger(sgm);
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_40S);
+		} else {
+			sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_DISABLE);
+			ret = sgm4154x_disable_charger(sgm);
+		}
+		break;
+
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = sgm4154x_set_input_curr_lim(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = sgm4154x_set_ichrg_curr(sgm, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = sgm4154x_set_chrg_volt(sgm, val->intval);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int sgm4154x_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *val)
+{
+	struct sgm4154x_device *sgm = power_supply_get_drvdata(psy);
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm, &state);
+	if (ret) {
+		dev_err(sgm->dev, "get state error!\n");
+		return ret;
+	}
+	sgm->state = state;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (!state.chrg_type || (state.chrg_type == SGM4154X_OTG_MODE))
+			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		else if (!state.chrg_stat)
+			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		else if (state.chrg_stat == SGM4154X_TERM_CHRG)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else
+			val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		switch (state.chrg_stat) {
+		case SGM4154X_PRECHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_FAST_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+			break;
+		case SGM4154X_TERM_CHRG:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+			break;
+		case SGM4154X_NOT_CHRGING:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+			break;
+		default:
+			val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+		}
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = SGM4154X_MANUFACTURER;
+		break;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = SGM4154X_NAME;
+		break;
+
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = state.online;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = state.vbus_gd;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		val->intval = sgm4154x_get_chrg_volt(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		val->intval = sgm4154x_get_ichrg_curr(sgm);
+		if (val->intval < 0)
+			return -EINVAL;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		val->intval = sgm->init_data.vlim;
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		val->intval = sgm4154x_get_input_curr_lim(sgm);
+		if (val->intval < 0)
+			return  -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static irqreturn_t sgm4154x_irq_handler_thread(int irq, void *private)
+{
+	struct sgm4154x_device *sgm4154x = private;
+	struct sgm4154x_state state;
+	int ret;
+
+	ret = sgm4154x_get_state(sgm4154x, &state);
+	if (ret) {
+		dev_err(sgm4154x->dev, "get state error!\n");
+		return IRQ_NONE;
+	}
+	sgm4154x->state = state;
+	if (state.vbus_gd) {
+		if (sgm4154x->init_data.ilim >= SGM4154X_DEFAULT_INPUT_CUR) {
+			ret = sgm4154x_set_input_curr_lim(sgm4154x, sgm4154x->init_data.ilim);
+			if (ret) {
+				dev_err(sgm4154x->dev, "set input current error!\n");
+				/* Reading IRQ clears interrupt, so return handled */
+				return IRQ_HANDLED;
+			}
+		}
+	}
+	power_supply_changed(sgm4154x->charger);
+
+	return IRQ_HANDLED;
+}
+
+static enum power_supply_property sgm4154x_power_supply_props[] = {
+	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_PRESENT
+};
+
+static struct power_supply_desc sgm4154x_power_supply_desc = {
+	.name = "sgm4154x-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = sgm4154x_power_supply_props,
+	.num_properties = ARRAY_SIZE(sgm4154x_power_supply_props),
+	.get_property = sgm4154x_charger_get_property,
+	.set_property = sgm4154x_charger_set_property,
+	.property_is_writeable = sgm4154x_property_is_writeable,
+};
+
+static const struct regmap_config sgm4154x_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = SGM4154X_CHRG_CTRL_F,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sgm4154x_power_supply_init(struct sgm4154x_device *sgm,
+				      struct device *dev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = sgm,
+					       .fwnode = dev->fwnode, };
+
+	sgm->charger = devm_power_supply_register(sgm->dev,
+						  &sgm4154x_power_supply_desc,
+						  &psy_cfg);
+	if (IS_ERR(sgm->charger))
+		return PTR_ERR(sgm->charger);
+
+	return 0;
+}
+
+static int sgm4154x_hw_init(struct sgm4154x_device *sgm)
+{
+	struct power_supply_battery_info *bat_info;
+	int ret;
+	u32 val;
+
+	/*
+	 * If unable to read devicetree info, use default/reset
+	 * values from hardware. If the devicetree info has data out
+	 * of range for any of the values, use the default value.
+	 */
+	sgm->init_data.iprechg = SGM4154X_PRECHRG_I_DEF_UA;
+	sgm->init_data.iterm = SGM4154X_TERMCHRG_I_DEF_UA;
+	sgm->init_data.max_ichg = SGM4154X_ICHRG_I_DEF_UA;
+	sgm->init_data.max_vreg = SGM4154X_VREG_V_DEF_UV;
+	sgm->init_data.vlim = SGM4154X_VINDPM_DEF_UV;
+	sgm->init_data.ilim = SGM4154X_IINDPM_DEF_UA;
+
+	ret = power_supply_get_battery_info(sgm->charger, &bat_info);
+	if (ret)
+		dev_warn(sgm->dev, "sgm4154x: cannot read battery info\n");
+	else {
+		if ((bat_info->constant_charge_current_max_ua >= SGM4154X_ICHRG_I_MIN_UA) &&
+			(bat_info->constant_charge_current_max_ua <= SGM4154X_ICHRG_I_MAX_UA))
+			sgm->init_data.max_ichg = bat_info->constant_charge_current_max_ua;
+		if ((bat_info->constant_charge_voltage_max_uv >= SGM4154X_VREG_V_MIN_UV) &&
+			(bat_info->constant_charge_voltage_max_uv <= SGM4154X_VREG_V_MAX_UV))
+			sgm->init_data.max_vreg = bat_info->constant_charge_voltage_max_uv;
+		if ((bat_info->charge_term_current_ua >= SGM4154X_TERMCHRG_I_MIN_UA) &&
+			(bat_info->charge_term_current_ua <= SGM4154X_TERMCHRG_I_MAX_UA))
+			sgm->init_data.iterm = bat_info->charge_term_current_ua;
+		if ((bat_info->precharge_current_ua >= SGM4154X_PRECHRG_I_MIN_UA) &&
+			(bat_info->precharge_current_ua <= SGM4154X_PRECHRG_I_MAX_UA))
+			sgm->init_data.iprechg = bat_info->precharge_current_ua;
+
+		power_supply_put_battery_info(sgm->charger, bat_info);
+	}
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-voltage-limit-microvolt",
+				       &val);
+	if (!ret)
+		sgm->init_data.vlim = clamp(val, SGM4154X_VINDPM_V_MIN_UV,
+					    SGM4154X_VINDPM_V_MAX_UV);
+
+	ret = device_property_read_u32(sgm->dev,
+				       "input-current-limit-microamp",
+				       &val);
+	if (!ret)
+		sgm->init_data.ilim = clamp(val, SGM4154X_IINDPM_I_MIN_UA,
+					    SGM4154X_IINDPM_I_MAX_UA);
+
+	ret = sgm4154x_set_watchdog_timer(sgm, SGM4154X_WDT_TIMER_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_prechrg_curr(sgm, sgm->init_data.iprechg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_chrg_volt(sgm, sgm->init_data.max_vreg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_term_curr(sgm, sgm->init_data.iterm);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_ichrg_curr(sgm, sgm->init_data.max_ichg);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_volt_lim(sgm, sgm->init_data.vlim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_input_curr_lim(sgm, sgm->init_data.ilim);
+	if (ret)
+		return ret;
+
+	ret = sgm4154x_set_vac_ovp(sgm);
+	if (ret)
+		return ret;
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_D,
+			   SGM4154X_JEITA_EN,
+			   0);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_IINDPM_INT_MASK,
+			   SGM4154X_IINDPM_INT_MASK);
+
+	regmap_update_bits(sgm->regmap,
+			   SGM4154X_CHRG_CTRL_A,
+			   SGM4154X_VINDPM_INT_MASK,
+			   SGM4154X_VINDPM_INT_MASK);
+
+	/*
+	 * Recharge microvolt set to 200000 by BSP driver instead of hardware
+	 * default value of 100000.
+	 */
+	ret = sgm4154x_set_recharge_volt_ua(sgm, 200000);
+
+	return ret;
+}
+
+static const u32 sgm4154x_chg_otg_cur_ua[] = {
+	1200000, 2000000,
+};
+
+static const struct regulator_ops sgm4154x_vbus_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const struct regulator_desc sgm4154x_otg_rdesc = {
+	.of_match = "otg-vbus",
+	.name = "otg-vbus",
+	.regulators_node = of_match_ptr("regulators"),
+	.ops = &sgm4154x_vbus_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4850000,
+	.uV_step = 150000,
+	.n_voltages = 4,
+	.vsel_reg = SGM4154X_CHRG_CTRL_6,
+	.vsel_mask = SGM4154X_BOOSTV,
+	.enable_reg = SGM4154X_CHRG_CTRL_1,
+	.enable_mask = SGM4154X_OTG_EN,
+	.curr_table = sgm4154x_chg_otg_cur_ua,
+	.n_current_limits = ARRAY_SIZE(sgm4154x_chg_otg_cur_ua),
+	.csel_reg = SGM4154X_CHRG_CTRL_2,
+	.csel_mask = SGM4154X_BOOST_LIM,
+};
+
+static int sgm4154x_vbus_regulator_register(struct sgm4154x_device *sgm)
+{
+	struct regulator_config config = {
+		.dev = sgm->dev,
+		.regmap = sgm->regmap,
+		.driver_data = sgm,
+	};
+
+	sgm->otg_rdev = devm_regulator_register(sgm->dev,
+						&sgm4154x_otg_rdesc,
+						&config);
+
+	return PTR_ERR_OR_ZERO(sgm->otg_rdev);
+}
+
+static int sgm4154x_hw_chipid_detect(struct sgm4154x_device *sgm)
+{
+	int ret;
+	int val;
+
+	ret = regmap_read(sgm->regmap, SGM4154X_CHRG_CTRL_B, &val);
+	if (ret)
+		return ret;
+
+	if ((val & SGM4154X_PN_MASK) != SGM4154X_PN_ID)
+		dev_warn(sgm->dev, "sgm4154x device ID mismatch\n");
+
+	return 0;
+}
+
+static void sgm_charger_work(struct work_struct *work)
+{
+	struct sgm4154x_device *sgm =
+		container_of(work,
+			     struct sgm4154x_device,
+			     sgm_delay_work.work);
+
+	sgm4154x_watchdog_timer_reset(sgm);
+	if (sgm->watchdog_enable)
+		queue_delayed_work(sgm->sgm_monitor_wq,
+				   &sgm->sgm_delay_work,
+				   msecs_to_jiffies(1000 * 5));
+}
+
+static void sgm4154x_disable_irq_wake(void *data)
+{
+	struct sgm4154x_device *sgm = data;
+	struct i2c_client *client = to_i2c_client(sgm->dev);
+
+	disable_irq_wake(client->irq);
+}
+
+static int sgm4154x_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct sgm4154x_device *sgm;
+	int ret;
+
+	sgm = devm_kzalloc(dev, sizeof(*sgm), GFP_KERNEL);
+	if (!sgm)
+		return -ENOMEM;
+
+	sgm->dev = dev;
+
+	sgm->regmap = devm_regmap_init_i2c(client, &sgm4154x_regmap_config);
+	if (IS_ERR(sgm->regmap))
+		return dev_err_probe(dev, PTR_ERR(sgm->regmap),
+				     "Failed to allocate register map\n");
+
+	i2c_set_clientdata(client, sgm);
+
+	ret = sgm4154x_hw_chipid_detect(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to read HW ID\n");
+
+	device_init_wakeup(dev, 1);
+
+	sgm->sgm_monitor_wq = devm_alloc_ordered_workqueue(dev, "sgm-monitor-wq",
+			WQ_MEM_RECLAIM | WQ_FREEZABLE);
+	if (!sgm->sgm_monitor_wq)
+		return -EINVAL;
+
+	ret = devm_delayed_work_autocancel(dev, &sgm->sgm_delay_work,
+					   sgm_charger_work);
+	if (ret)
+		return dev_err_probe(dev, ret, "Unable to register delayed work\n");
+
+	ret = sgm4154x_power_supply_init(sgm, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register power supply\n");
+
+	ret = sgm4154x_hw_init(sgm);
+	if (ret)
+		return dev_err_probe(dev, ret, "Cannot initialize the chip.\n");
+
+	if (client->irq) {
+		ret = devm_request_threaded_irq(dev, client->irq, NULL,
+						sgm4154x_irq_handler_thread,
+						IRQF_TRIGGER_FALLING |
+						IRQF_ONESHOT,
+						"sgm41542-irq", sgm);
+		if (ret)
+			return ret;
+
+		ret = enable_irq_wake(client->irq);
+		if (!ret) {
+			ret = devm_add_action_or_reset(dev, sgm4154x_disable_irq_wake, sgm);
+			if (ret)
+				return ret;
+		}
+	}
+
+	ret = sgm4154x_vbus_regulator_register(sgm);
+	if (ret) {
+		return dev_err_probe(dev, ret,
+				     "Unable to register VBUS regulator\n");
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id sgm4154x_i2c_ids[] = {
+	{ "sgm41542" },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, sgm4154x_i2c_ids);
+
+static const struct of_device_id sgm4154x_of_match[] = {
+	{ .compatible = "sgmicro,sgm41542", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sgm4154x_of_match);
+
+static struct i2c_driver sgm4154x_driver = {
+	.driver = {
+		.name = "sgm4154x-charger",
+		.of_match_table = sgm4154x_of_match,
+	},
+	.probe = sgm4154x_probe,
+	.id_table = sgm4154x_i2c_ids,
+};
+
+module_i2c_driver(sgm4154x_driver);
+
+MODULE_AUTHOR("Xu Shengfei <xsf at rock-chips.com>");
+MODULE_DESCRIPTION("sgm4154x charger driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:04 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:04 -0500
Subject: [PATCH V7 3/6] dt-bindings: display: panel: Add Anbernic TD4310 panel
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../display/panel/anbernic,td4310.yaml        | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml

diff --git a/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
new file mode 100644
index 000000000000..f820dc2f732b
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/anbernic,td4310.yaml
@@ -0,0 +1,66 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/anbernic,td4310.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Anbernic TD4310 Based Panels
+
+maintainers:
+  - Chris Morgan <macromorgan at hotmail.com>
+
+description:
+  Anbernic TD4310 Based Panels, such as the RG-Vita-Pro panel
+  (a 1080x1920 5.5 inch panel).
+
+allOf:
+  - $ref: panel-common.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - anbernic,panel-vita-pro
+      - const: anbernic,td4310
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description: Panel power supply
+
+required:
+  - compatible
+  - port
+  - reg
+  - reset-gpios
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    dsi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        panel at 0 {
+            compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+            reg = <0>;
+            backlight = <&backlight>;
+            enable-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
+            reset-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+            rotation = <270>;
+            vdd-supply = <&vdd_lcd>;
+
+            port {
+                endpoint {
+                    remote-endpoint = <&dsi_out>;
+                };
+            };
+        };
+    };
+
+...
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:05 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:05 -0500
Subject: [PATCH V7 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
on the TD4310 controller IC. It measures approximately 5.5 inches
diagonally and is 1080x1920 in resolution.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/gpu/drm/panel/Kconfig                 |  10 +
 drivers/gpu/drm/panel/Makefile                |   1 +
 drivers/gpu/drm/panel/panel-anbernic-td4310.c | 257 ++++++++++++++++++
 3 files changed, 268 insertions(+)
 create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c

diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index d592f4f4b939..61dd00297ecc 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
 	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
 	  and RG-99 handheld gaming consoles.
 
+config DRM_PANEL_ANBERNIC_TD4310
+	tristate "Anbernic TD4310 LCD panel"
+	depends on GPIOLIB && OF
+	depends on DRM_MIPI_DSI
+	depends on BACKLIGHT_CLASS_DEVICE
+	help
+	  Say Y here to enable support for Anbernic designed panels with the
+	  TD4310 panel controller such as the ones used on the Anbernic RG
+	  Vita Pro.
+
 config DRM_PANEL_ARM_VERSATILE
 	tristate "ARM Versatile panel driver"
 	depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index a4291dc3905b..9d8f70c9de3e 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
+obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
 obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
 obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
 obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
new file mode 100644
index 000000000000..9a1b4525423c
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Anbernic panels with TD4310 panel controller.
+ *
+ * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
+ *
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+#include <video/mipi_display.h>
+
+struct anbernic_panel_td4310_info {
+	const struct drm_display_mode *display_mode;
+	u16 width_mm;
+	u16 height_mm;
+	u32 bus_flags;
+	unsigned long mode_flags;
+	u32 format;
+	u32 lanes;
+	u16 prepare_delay;
+	u16 reset_delay;
+	u16 init_delay;
+	u16 enable_delay;
+	u16 disable_delay;
+	u16 unprepare_delay;
+};
+
+struct anbernic_panel_td4310 {
+	struct device *dev;
+	struct mipi_dsi_device *dsi;
+	struct drm_panel panel;
+	const struct anbernic_panel_td4310_info *panel_info;
+	struct gpio_desc *reset_gpio;
+	struct gpio_desc *enable_gpio;
+	struct regulator *vdd;
+	enum drm_panel_orientation orientation;
+};
+
+static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
+{
+	return container_of(panel, struct anbernic_panel_td4310, panel);
+}
+
+static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+	int ret;
+
+	ret = regulator_enable(ctx->vdd);
+	if (ret)
+		return ret;
+
+	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
+	if (ret)
+		goto err_enable;
+
+	if (ctx->panel_info->enable_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+	if (ret)
+		goto err_reset;
+
+	mipi_dsi_msleep(&dsi_ctx, 10);
+
+	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+	if (ret)
+		goto err_reset;
+
+	if (ctx->panel_info->reset_delay)
+		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
+
+	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
+
+	if (dsi_ctx.accum_err) {
+		ret = dsi_ctx.accum_err;
+		goto err_reset;
+	}
+
+	return 0;
+
+err_reset:
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+err_enable:
+	regulator_disable(ctx->vdd);
+	return ret;
+}
+
+static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	struct mipi_dsi_device *dsi = ctx->dsi;
+	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
+
+	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->unprepare_delay);
+	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
+	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->disable_delay);
+
+	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
+
+	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
+	regulator_disable(ctx->vdd);
+
+	return 0;
+}
+
+static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
+				    struct drm_connector *connector)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
+
+	connector->display_info.bpc = 8;
+	connector->display_info.width_mm = panel_info->width_mm;
+	connector->display_info.height_mm = panel_info->height_mm;
+	connector->display_info.bus_flags = panel_info->bus_flags;
+
+	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
+}
+
+static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
+{
+	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
+
+	return ctx->orientation;
+}
+
+static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
+	.prepare = panel_anbernic_td4310_prepare,
+	.unprepare = panel_anbernic_td4310_unprepare,
+	.get_modes = panel_anbernic_td4310_get_mode,
+	.get_orientation = panel_anbernic_td4310_get_orientation,
+};
+
+static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
+{
+	struct device *dev = &dsi->dev;
+	struct anbernic_panel_td4310 *ctx;
+	int ret;
+
+	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
+				   &panel_anbernic_td4310_funcs,
+				   DRM_MODE_CONNECTOR_DSI);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ctx->dev = dev;
+
+	ctx->panel_info = of_device_get_match_data(dev);
+	if (!ctx->panel_info)
+		return -EINVAL;
+
+	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
+
+	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+				     "Cannot get reset gpio\n");
+
+	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
+	if (IS_ERR(ctx->enable_gpio))
+		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
+				     "Cannot get enable gpio\n");
+
+	ctx->vdd = devm_regulator_get(dev, "vdd");
+	if (IS_ERR(ctx->vdd))
+		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
+				     "Failed to request vdd regulator\n");
+
+	ctx->dsi = dsi;
+	mipi_dsi_set_drvdata(dsi, ctx);
+
+	dsi->lanes = ctx->panel_info->lanes;
+	dsi->format = ctx->panel_info->format;
+	dsi->mode_flags = ctx->panel_info->mode_flags;
+
+	ret = drm_panel_of_backlight(&ctx->panel);
+	if (ret)
+		return ret;
+
+	devm_drm_panel_add(dev, &ctx->panel);
+
+	ret = devm_mipi_dsi_attach(dev, dsi);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
+
+	return 0;
+}
+
+static const struct drm_display_mode anbernic_vitapro_mode = {
+	.clock = 140020,
+	.hdisplay = 1080,
+	.hsync_start = 1080 + 50,
+	.hsync_end = 1080 + 50 + 4,
+	.htotal = 1080 + 50 + 4 + 50,
+	.vdisplay = 1920,
+	.vsync_start = 1920 + 15,
+	.vsync_end = 1920 + 15 + 4,
+	.vtotal = 1920 + 15 + 4 + 32,
+	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
+	.display_mode = &anbernic_vitapro_mode,
+	.width_mm = 69,
+	.height_mm = 121,
+	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
+	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
+		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
+	.format = MIPI_DSI_FMT_RGB888,
+	.lanes = 4,
+	.prepare_delay = 50,
+	.reset_delay = 220,
+	.enable_delay = 120,
+	.disable_delay = 50,
+	.unprepare_delay = 20,
+};
+
+static const struct of_device_id panel_anbernic_td4310_of_match[] = {
+	{
+		.compatible = "anbernic,panel-vita-pro",
+		.data = &anbernic_vitapro_info,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
+
+static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
+	.driver = {
+		.name = "panel-anbernic-td4310",
+		.of_match_table = panel_anbernic_td4310_of_match,
+	},
+	.probe	= panel_anbernic_td4310_probe,
+};
+module_mipi_dsi_driver(anbernic_panel_td4310_driver);
+
+MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
+MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
+MODULE_LICENSE("GPL");
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:06 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:06 -0500
Subject: [PATCH V7 5/6] dt-bindings: arm: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add compatible string for the Anbernic RG Vita-Pro.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 Documentation/devicetree/bindings/arm/rockchip.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml
index 1a9dde18626d..b8babe9d3a26 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.yaml
+++ b/Documentation/devicetree/bindings/arm/rockchip.yaml
@@ -66,6 +66,12 @@ properties:
               - anbernic,rg-ds
           - const: rockchip,rk3568
 
+      - description: Anbernic RK3576 Handheld Gaming Console
+        items:
+          - enum:
+              - anbernic,rg-vita-pro
+          - const: rockchip,rk3576
+
       - description: Ariaboard Photonicat
         items:
           - const: ariaboard,photonicat
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 07:44:07 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 09:44:07 -0500
Subject: [PATCH V7 6/6] arm64: dts: rockchip: Add Anbernic RG Vita-Pro
In-Reply-To: <20260610144407.438846-1-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
Message-ID: <20260610144407.438846-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add device tree for the Anbernic RG Vita-Pro, based on the Rockchip
RK3576. All hardware is currently working except for the accelerometer,
the touchscreen, the battery monitor, and DisplayPort over USB-C. PWM
is also missing currently, and as a result the LEDs and panel backlight
are currently controlled via GPIO but will be changed to PWM once
supported.

The Anbernic RG Vita-Pro includes the following hardware:
 - A 1080x1920 DSI display with touch.
 - 21 buttons.
 - 3 LEDs.
 - 64GB eMMC, 2 SDMMC slots.
 - RTL8852BE WiFi (with Bluetooth via UART)
 - 1 USB 3.0 USB-C port in OTG mode.
 - 3.5mm headphone jack with play button support.
 - 5000mAH battery

The following hardware has incomplete driver support and is not yet
working:
 - An Invensense icm42607p accelerometer.
 - A Cellwise cw221x battery monitor.
 - A Synaptics i2c touchscreen.
 - DisplayPort over USB-C alt-mode.
 - PWM controller.
 - 2 Analog joysticks with LED controllers.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/Makefile         |    1 +
 .../rockchip/rk3576-anbernic-rg-vita-pro.dts  | 1327 +++++++++++++++++
 2 files changed, 1328 insertions(+)
 create mode 100644 arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts

diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
index cb55c6b70d0e..7d86676f98e8 100644
--- a/arch/arm64/boot/dts/rockchip/Makefile
+++ b/arch/arm64/boot/dts/rockchip/Makefile
@@ -165,6 +165,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5.dtb
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-display-vz.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-wolfvision-pf5-io-expander.dtbo
 dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-100ask-dshanpi-a1.dtb
+dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3576-anbernic-rg-vita-pro.dtb
 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
diff --git a/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
new file mode 100644
index 000000000000..344ba1870533
--- /dev/null
+++ b/arch/arm64/boot/dts/rockchip/rk3576-anbernic-rg-vita-pro.dts
@@ -0,0 +1,1327 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2026 Chris Morgan <macromorgan at hotmail.com>
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/soc/rockchip,vop2.h>
+#include <dt-bindings/usb/pd.h>
+
+#include "rk3576.dtsi"
+
+/ {
+	model = "Anbernic RG Vita Pro";
+	chassis-type = "handset";
+	compatible = "anbernic,rg-vita-pro", "rockchip,rk3576";
+
+	aliases {
+		mmc0 = &sdhci;
+		mmc1 = &sdmmc;
+		mmc2 = &sdio;
+	};
+
+	chosen {
+		stdout-path = "serial0:1500000n8";
+	};
+
+	adc_keys_home: adc-keys-home {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 1>;
+		keyup-threshold-microvolt = <1800000>;
+		poll-interval = <60>;
+
+		button-home {
+			label = "HOME";
+			linux,code = <KEY_HOME>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	adc_keys_play: adc-keys-play {
+		compatible = "adc-keys";
+		io-channel-names = "buttons";
+		io-channels = <&saradc 3>;
+		keyup-threshold-microvolt = <1300000>;
+		poll-interval = <60>;
+
+		button-play {
+			label = "PLAY";
+			linux,code = <KEY_PLAYPAUSE>;
+			press-threshold-microvolt = <1750>;
+		};
+	};
+
+	/*
+	 * Battery values from BSP except for the following:
+	 *
+	 * factory-internal-resistance-micro-ohms - This was set to 80 which
+	 * is likely incorrect and changed to 80000.
+	 *
+	 * charge-full-design-microamp-hours - Was set to 8000000 but the
+	 * physical battery says 5000000.
+	 *
+	 * constant-charge-current-max-microamp - Was set to 10000000 which
+	 * both seems high and exceeds what the charger hardware can do.
+	 * Setting to 3800000 which is the maximum input current the charger
+	 * can handle.
+	 */
+	battery: battery {
+		compatible = "simple-battery";
+		charge-full-design-microamp-hours = <5000000>;
+		charge-term-current-microamp = <300000>;
+		constant-charge-current-max-microamp = <3800000>;
+		constant-charge-voltage-max-microvolt = <4350000>;
+		factory-internal-resistance-micro-ohms = <80000>;
+		precharge-current-microamp = <180000>;
+		precharge-upper-limit-microvolt = <3600000>;
+		voltage-max-design-microvolt = <4350000>;
+		voltage-min-design-microvolt = <3000000>;
+	};
+
+	hp_amp: audio-amplifier {
+		compatible = "simple-audio-amplifier";
+		enable-gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&hp_amp_enable_h>;
+		pinctrl-names = "default";
+		sound-name-prefix = "Headphone Amp";
+	};
+
+	/*
+	 * LEDs and Backlights can be controlled as a PWM, but PWM
+	 * driver is not yet available.
+	 */
+	gpio_backlight: backlight {
+		compatible = "gpio-backlight";
+		gpios = <&gpio2 RK_PC4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&led_backlight_h>;
+		pinctrl-names = "default";
+	};
+
+	gpio_leds: leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_amber_h>, <&led_green_h>, <&led_red_h>;
+		pinctrl-names = "default";
+
+		charging-led {
+			color = <LED_COLOR_ID_AMBER>;
+			function = LED_FUNCTION_CHARGING;
+			gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
+		};
+
+		full-led {
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_POWER;
+			gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
+		};
+
+		bat-low-led {
+			color = <LED_COLOR_ID_RED>;
+			function = LED_FUNCTION_ALARM;
+			gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio_keys_control: gpio-keys-control {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&gamepad_keys_l>;
+		pinctrl-names = "default";
+
+		button-a {
+			gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>;
+			label = "EAST";
+			linux,code = <BTN_EAST>;
+		};
+
+		button-b {
+			gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_LOW>;
+			label = "SOUTH";
+			linux,code = <BTN_SOUTH>;
+		};
+
+		button-down {
+			gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>;
+			label = "DPAD-DOWN";
+			linux,code = <BTN_DPAD_DOWN>;
+		};
+
+		button-l1 {
+			gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>;
+			label = "TL";
+			linux,code = <BTN_TL>;
+		};
+
+		button-l2 {
+			gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>;
+			label = "TL2";
+			linux,code = <BTN_TL2>;
+		};
+
+		button-left {
+			gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>;
+			label = "DPAD-LEFT";
+			linux,code = <BTN_DPAD_LEFT>;
+		};
+
+		button-menu {
+			gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>;
+			label = "MENU";
+			linux,code = <BTN_MODE>;
+		};
+
+		button-right {
+			gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>;
+			label = "DPAD-RIGHT";
+			linux,code = <BTN_DPAD_RIGHT>;
+		};
+
+		button-r1 {
+			gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>;
+			label = "T2";
+			linux,code = <BTN_TR>;
+		};
+
+		button-r2 {
+			gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>;
+			label = "TR2";
+			linux,code = <BTN_TR2>;
+		};
+
+		button-select {
+			gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>;
+			label = "SELECT";
+			linux,code = <BTN_SELECT>;
+		};
+
+		button-start {
+			gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>;
+			label = "START";
+			linux,code = <BTN_START>;
+		};
+
+		button-thumbl {
+			gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>;
+			label = "THUMBL";
+			linux,code = <BTN_THUMBL>;
+		};
+
+		button-thumbr {
+			gpios = <&gpio3 RK_PC4 GPIO_ACTIVE_LOW>;
+			label = "THUMBR";
+			linux,code = <BTN_THUMBR>;
+		};
+
+		button-up {
+			gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>;
+			label = "DPAD-UP";
+			linux,code = <BTN_DPAD_UP>;
+		};
+
+		button-x {
+			gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>;
+			label = "NORTH";
+			linux,code = <BTN_NORTH>;
+		};
+
+		button-y {
+			gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>;
+			label = "WEST";
+			linux,code = <BTN_WEST>;
+		};
+	};
+
+	gpio_keys_volume: gpio-keys-volume {
+		compatible = "gpio-keys";
+		autorepeat;
+		pinctrl-0 = <&vol_keys_l>;
+		pinctrl-names = "default";
+
+		vol-down-key {
+			gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEDOWN";
+			linux,code = <KEY_VOLUMEDOWN>;
+		};
+
+		vol-up-key {
+			gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>;
+			label = "VOLUMEUP";
+			linux,code = <KEY_VOLUMEUP>;
+		};
+	};
+
+	hdmi-con {
+		compatible = "hdmi-connector";
+		type = "c";
+
+		port {
+			hdmi_con_in: endpoint {
+				remote-endpoint = <&hdmi_out_con>;
+			};
+		};
+	};
+
+	rfkill {
+		compatible = "rfkill-gpio";
+		pinctrl-names = "default";
+		pinctrl-0 = <&wifi_en_h>;
+		radio-type = "wlan";
+		shutdown-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
+	};
+
+	sound: sound {
+		compatible = "simple-audio-card";
+		pinctrl-0 = <&hp_det>;
+		pinctrl-names = "default";
+		simple-audio-card,aux-devs = <&aw87391_pa_l>, <&aw87391_pa_r>,
+					     <&hp_amp>;
+		simple-audio-card,format = "i2s";
+		simple-audio-card,hp-det-gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_HIGH>;
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "rockchip,es8388-codec";
+		simple-audio-card,pin-switches = "Headphones", "Internal Speakers";
+		simple-audio-card,routing =
+			"LINPUT1", "Mic Jack",
+			"LINPUT2", "Mic Jack",
+			"RINPUT1", "Onboard Microphone",
+			"RINPUT2", "Onboard Microphone",
+			"Headphones", "Headphone Amp OUTL",
+			"Headphones", "Headphone Amp OUTR",
+			"Headphone Amp INL", "LOUT1",
+			"Headphone Amp INR", "ROUT1",
+			"Internal Speakers", "Left Amp OUT",
+			"Internal Speakers", "Right Amp OUT",
+			"Left Amp IN", "LOUT2",
+			"Right Amp IN", "ROUT2";
+		simple-audio-card,widgets =
+			"Microphone", "Mic Jack",
+			"Microphone", "Onboard Microphone",
+			"Headphone", "Headphones",
+			"Speaker", "Internal Speakers";
+		status = "okay";
+
+		simple-audio-card,codec {
+			sound-dai = <&es8388>;
+			system-clock-frequency = <12288000>;
+		};
+
+		simple-audio-card,cpu {
+			sound-dai = <&sai1>;
+		};
+	};
+
+	vcc_1v1_nldo_s3: regulator-vcc-1v1-nldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <1100000>;
+		regulator-min-microvolt = <1100000>;
+		regulator-name = "vcc_1v1_nldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_2v0_pldo_s3: regulator-vcc-2v0-pldo-s3 {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <2000000>;
+		regulator-min-microvolt = <2000000>;
+		regulator-name = "vcc_2v0_pldo_s3";
+		vin-supply = <&vcc_3v8_sys>;
+	};
+
+	vcc_3v8_sys: regulator-vcc-3v8-sys {
+		compatible = "regulator-fixed";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-max-microvolt = <3800000>;
+		regulator-min-microvolt = <3800000>;
+		regulator-name = "vcc_3v8_sys";
+	};
+
+	vcc3v3_sd_s0: regulator-vcc3v3-sd-s0 {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_3v3_sd_s0_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-name = "vcc3v3_sd_s0";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+
+	vcc_sdio: regulator-vcc-sdio {
+		compatible = "regulator-gpio";
+		regulator-name = "vcc_sdio";
+		gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_sdio_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <1800000>;
+		states = <1800000 0>, <3300000 1>;
+	};
+
+	vcc_wifi: regulator-vcc-wifi {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc_wifi";
+		enable-active-high;
+		gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vcc_wifi_h>;
+		pinctrl-names = "default";
+		regulator-max-microvolt = <3300000>;
+		regulator-min-microvolt = <3300000>;
+		regulator-state-mem {
+			regulator-on-in-suspend;
+		};
+	};
+
+	vdd_lcd: regulator-vdd-lcd {
+		compatible = "regulator-fixed";
+		regulator-name = "vdd_lcd";
+		regulator-always-on;
+		enable-active-high;
+		gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&vdd_lcd_h>;
+		pinctrl-names = "default";
+		regulator-state-mem {
+			regulator-off-in-suspend;
+		};
+	};
+};
+
+&combphy0_ps {
+	status = "okay";
+};
+
+&cpu_b0 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b1 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b2 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_b3 {
+	cpu-supply = <&vdd_cpu_big_s0>;
+};
+
+&cpu_l0 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l1 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l2 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&cpu_l3 {
+	cpu-supply = <&vdd_cpu_lit_s0>;
+};
+
+&dsi {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	panel: panel at 0 {
+		compatible = "anbernic,panel-vita-pro", "anbernic,td4310";
+		reg = <0>;
+		backlight = <&gpio_backlight>;
+		enable-gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&lcd_enable>, <&lcd_rst>;
+		reset-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
+		rotation = <270>;
+		vdd-supply = <&vdd_lcd>;
+
+		port {
+			mipi_in_panel: endpoint {
+				remote-endpoint = <&mipi_out_panel>;
+			};
+		};
+	};
+};
+
+&dsi_in {
+	dsi_in_vp1: endpoint {
+		remote-endpoint = <&vp1_out_dsi>;
+	};
+};
+
+&dsi_out {
+	mipi_out_panel: endpoint {
+		remote-endpoint = <&mipi_in_panel>;
+	};
+};
+
+&gpu {
+	mali-supply = <&vdd_gpu_s0>;
+	status = "okay";
+};
+
+&hdmi {
+	status = "okay";
+};
+
+&hdmi_in {
+	hdmi_in_vp0: endpoint {
+		remote-endpoint = <&vp0_out_hdmi>;
+	};
+};
+
+&hdmi_out {
+	hdmi_out_con: endpoint {
+		remote-endpoint = <&hdmi_con_in>;
+	};
+};
+
+&hdmi_sound {
+	status = "okay";
+};
+
+&hdptxphy {
+	status = "okay";
+};
+
+&i2c0 {
+	pinctrl-0 = <&i2c0m1_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	/* synaptics,dsx-i2c touchscreen at 0x70 */
+};
+
+&i2c1 {
+	status = "okay";
+
+	pmic at 23 {
+		compatible = "rockchip,rk806";
+		reg = <0x23>;
+		#gpio-cells = <2>;
+		gpio-controller;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA6 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pmic_pins
+			     &rk806_dvs1_null
+			     &rk806_dvs2_null
+			     &rk806_dvs3_null>;
+		system-power-controller;
+		vcc1-supply = <&vcc_3v8_sys>;
+		vcc2-supply = <&vcc_3v8_sys>;
+		vcc3-supply = <&vcc_3v8_sys>;
+		vcc4-supply = <&vcc_3v8_sys>;
+		vcc5-supply = <&vcc_3v8_sys>;
+		vcc6-supply = <&vcc_3v8_sys>;
+		vcc7-supply = <&vcc_3v8_sys>;
+		vcc8-supply = <&vcc_3v8_sys>;
+		vcc9-supply = <&vcc_3v8_sys>;
+		vcc10-supply = <&vcc_3v8_sys>;
+		vcc11-supply = <&vcc_2v0_pldo_s3>;
+		vcc12-supply = <&vcc_3v8_sys>;
+		vcc13-supply = <&vcc_1v1_nldo_s3>;
+		vcc14-supply = <&vcc_1v1_nldo_s3>;
+		vcca-supply = <&vcc_3v8_sys>;
+
+		rk806_dvs1_null: dvs1-null-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs1_pwrdn: dvs1-pwrdn-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs1_rst: dvs1-rst-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs1_slp: dvs1-slp-pins {
+			pins = "gpio_pwrctrl1";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs2_dvs: dvs2-dvs-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs2_gpio: dvs2-gpio-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs2_null: dvs2-null-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs2_pwrdn: dvs2-pwrdn-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs2_rst: dvs2-rst-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs2_slp: dvs2-slp-pins {
+			pins = "gpio_pwrctrl2";
+			function = "pin_fun1";
+		};
+
+		rk806_dvs3_dvs: dvs3-dvs-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun4";
+		};
+
+		rk806_dvs3_gpio: dvs3-gpio-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun5";
+		};
+
+		rk806_dvs3_null: dvs3-null-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun0";
+		};
+
+		rk806_dvs3_pwrdn: dvs3-pwrdn-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun2";
+		};
+
+		rk806_dvs3_rst: dvs3-rst-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun3";
+		};
+
+		rk806_dvs3_slp: dvs3-slp-pins {
+			pins = "gpio_pwrctrl3";
+			function = "pin_fun1";
+		};
+
+		regulators {
+			vdd_cpu_big_s0: dcdc-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_big_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_npu_s0: dcdc-reg2 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_npu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_cpu_lit_s0: dcdc-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <950000>;
+				regulator-name = "vdd_cpu_lit_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vcc_3v3_s3: dcdc-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcc_3v3_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <3300000>;
+				};
+			};
+
+			vdd_gpu_s0: dcdc-reg5 {
+				regulator-boot-on;
+				regulator-enable-ramp-delay = <400>;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <900000>;
+				regulator-name = "vdd_gpu_s0";
+				regulator-ramp-delay = <12500>;
+				regulator-state-mem {
+					regulator-off-in-suspend;
+					regulator-suspend-microvolt = <850000>;
+				};
+			};
+
+			vddq_ddr_s0: dcdc-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vddq_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdd_logic_s0: dcdc-reg7 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <800000>;
+				regulator-name = "vdd_logic_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcc_1v8_s3: dcdc-reg8 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcc_1v8_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd2_ddr_s3: dcdc-reg9 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-name = "vdd2_ddr_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vdd_ddr_s0: dcdc-reg10 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <550000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdd_ddr_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_1v8_s0: pldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca_1v8_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo2_s0: pldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_1v2_s0: pldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1200000>;
+				regulator-max-microvolt = <1200000>;
+				regulator-name = "vdda_1v2_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vcca_3v3_s0: pldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vcca_3v3_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vccio_sd_s0: pldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <3300000>;
+				regulator-name = "vccio_sd_s0";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+				};
+			};
+
+			vcca1v8_pldo6_s3: pldo-reg6 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <1800000>;
+				regulator-max-microvolt = <1800000>;
+				regulator-name = "vcca1v8_pldo6_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <1800000>;
+				};
+			};
+
+			vdd_0v75_s3: nldo-reg1 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdd_0v75_s3";
+				regulator-state-mem {
+					regulator-on-in-suspend;
+					regulator-suspend-microvolt = <750000>;
+				};
+			};
+
+			vdda_ddr_pll_s0: nldo-reg2 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_ddr_pll_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda0v75_hdmi_s0: nldo-reg3 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda0v75_hdmi_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v85_s0: nldo-reg4 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <850000>;
+				regulator-max-microvolt = <850000>;
+				regulator-name = "vdda_0v85_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+
+			vdda_0v75_s0: nldo-reg5 {
+				regulator-always-on;
+				regulator-boot-on;
+				regulator-min-microvolt = <750000>;
+				regulator-max-microvolt = <750000>;
+				regulator-name = "vdda_0v75_s0";
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+};
+
+&i2c2 {
+	status = "okay";
+
+	/* inv,icm42607 IMU at 0x68 */
+};
+
+&i2c3 {
+	status = "okay";
+
+	es8388: audio-codec at 10 {
+		compatible = "everest,es8388", "everest,es8328";
+		reg = <0x10>;
+		assigned-clock-rates = <12288000>;
+		assigned-clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		AVDD-supply = <&vcca_3v3_s0>;
+		clocks = <&cru CLK_SAI1_MCLKOUT_TO_IO>;
+		DVDD-supply = <&vcc_3v3_s3>;
+		HPVDD-supply = <&vcca_3v3_s0>;
+		pinctrl-0 = <&sai1m0_mclk>;
+		pinctrl-names = "default";
+		PVDD-supply = <&vcc_3v3_s3>;
+		#sound-dai-cells = <0>;
+	};
+
+	aw87391_pa_l: audio-codec at 58 {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x58>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Left Amp";
+	};
+
+	aw87391_pa_r: audio-codec at 5b {
+		compatible = "anbernic,rgds-amp", "awinic,aw87391";
+		reg = <0x5b>;
+		#sound-dai-cells = <0>;
+		sound-name-prefix = "Right Amp";
+	};
+};
+
+&i2c6 {
+	pinctrl-0 = <&i2c6m3_xfer>;
+	pinctrl-names = "default";
+	status = "okay";
+
+	sgm41542: charger at 3b {
+		compatible = "sgmicro,sgm41542";
+		reg = <0x3b>;
+		input-current-limit-microamp = <3000000>;
+		input-voltage-limit-microvolt = <4500000>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-0 = <&charger_irq>;
+		pinctrl-names = "default";
+		monitored-battery = <&battery>;
+		status = "okay";
+
+		regulators {
+			vbus5v0_typec: otg-vbus {
+				regulator-name = "vbus5v0_typec";
+				regulator-max-microvolt = <5000000>;
+				regulator-min-microvolt = <5000000>;
+
+				regulator-state-mem {
+					regulator-off-in-suspend;
+				};
+			};
+		};
+	};
+
+	/* Unused iSmartWare SW2001 encryption device at 0x3c */
+
+	husb311: typec-portc at 4e {
+		compatible = "hynetek,husb311", "richtek,rt1711h";
+		reg = <0x4e>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PD1 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-0 = <&usbc_int>;
+		pinctrl-names = "default";
+		status = "okay";
+		vbus-supply = <&vbus5v0_typec>;
+
+		connector {
+			compatible = "usb-c-connector";
+			label = "USB-C";
+			data-role = "dual";
+			op-sink-microwatt = <10000000>;
+			power-role = "dual";
+			try-power-role  = "sink";
+
+			sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)
+				     PDO_FIXED(9000, 2000, PDO_FIXED_USB_COMM)>;
+			source-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+
+			altmodes {
+				displayport {
+					svid = /bits/ 16 <0xff01>;
+					vdo = <0xffffffff>;
+				};
+			};
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				port at 0 {
+					reg = <0>;
+					usbc0_hs_ep: endpoint {
+						remote-endpoint = <&usb_drd0_hs_ep>;
+					};
+				};
+				port at 1 {
+					reg = <1>;
+					usbc0_ss_ep: endpoint {
+						remote-endpoint = <&usb_drd0_ss_ep>;
+					};
+				};
+				port at 2 {
+					reg = <2>;
+					usbc0_dp_ep: endpoint {
+						remote-endpoint = <&usbdp_phy_ep>;
+					};
+				};
+			};
+		};
+	};
+
+	hym8563: rtc at 51 {
+		compatible = "haoyu,hym8563";
+		reg = <0x51>;
+		#clock-cells = <0>;
+		clock-output-names = "hym8563";
+		interrupt-parent = <&gpio0>;
+		interrupts = <RK_PA0 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hym8563_int>;
+		wakeup-source;
+	};
+
+	/* cellwise,cw221X battery manager at 0x64 */
+};
+
+&mipidcphy {
+	status = "okay";
+};
+
+&pcie0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie0_perstn>;
+	reset-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+	vpcie3v3-supply = <&vcc_wifi>;
+	status = "okay";
+};
+
+&pinctrl {
+	audio {
+		hp_amp_enable_h: hp-amp-enable {
+			rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		hp_det: hp-det {
+			rockchip,pins = <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	bluetooth {
+		bt_reset_gpio: bt-reset-pin {
+			rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_gpio: bt-wake-pin {
+			rockchip,pins = <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		bt_wake_host_irq: bt-wake-host-irq {
+			rockchip,pins = <2 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	charger {
+		charger_irq: charger-irq {
+			rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	display {
+		lcd_enable: lcd-enable {
+			rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		lcd_rst: lcd-rst {
+			rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	gpio-keys {
+		vol_keys_l: vol-keys_l {
+			rockchip,pins =
+				<3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		gamepad_keys_l: gamepad-keys-l {
+			rockchip,pins =
+				<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PB7 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>,
+				<3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	gpio-leds {
+		led_amber_h: led-amber-h {
+			rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_backlight_h: led-backlight-h {
+			rockchip,pins = <2 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_green_h: led-green-h {
+			rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		led_red_h: led-red-h {
+			rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	pcie {
+		pcie0_perstn: pcie0-perstn {
+			rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	regulator {
+		vcc_3v3_sd_s0_h: vcc-3v3-sd-s0-h {
+			rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_sdio_h: vcc-sdio-h {
+			rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vcc_wifi_h: vcc-wifi-h {
+			rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+
+		vdd_lcd_h: vdd-lcd-h {
+			rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+
+	rtc {
+		hym8563_int: hym8563-int {
+			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	touch {
+		touch_int: touch-int {
+			rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	usb {
+		usbc_int: usbc-int {
+			rockchip,pins = <0 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		usbc0_sbu1: usbc0-sbu1 {
+			rockchip,pins = <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		usbc0_sbu2: usbc0-sbu2 {
+			rockchip,pins = <4 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+	};
+
+	wifi {
+		wifi_en_h: wifi-en-h {
+			rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
+};
+
+&sai1 {
+	pinctrl-0 = <&sai1m0_lrck
+		     &sai1m0_sclk
+		     &sai1m0_sdi0
+		     &sai1m0_sdo0>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sai6 {
+	status = "okay";
+};
+
+&saradc {
+	vref-supply = <&vcca1v8_pldo2_s0>;
+	status = "okay";
+};
+
+&sdio {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-mmc;
+	no-sdio;
+	pinctrl-0 = <&sdmmc1m0_bus4>, <&sdmmc1m0_clk>,
+		    <&sdmmc1m0_cmd>, <&sdmmc1m0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vcc_sdio>;
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	full-pwr-cycle-in-suspend;
+	no-sd;
+	no-sdio;
+	non-removable;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
+&sdmmc {
+	bus-width = <4>;
+	cap-mmc-highspeed;
+	cap-sd-highspeed;
+	disable-wp;
+	max-frequency = <150000000>;
+	no-sdio;
+	no-mmc;
+	pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>,
+		    <&sdmmc0_cmd>, <&sdmmc0_det>;
+	pinctrl-names = "default";
+	sd-uhs-sdr12;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	vmmc-supply = <&vcc3v3_sd_s0>;
+	vqmmc-supply = <&vccio_sd_s0>;
+	status = "okay";
+};
+
+&spi1 {
+	num-cs = <1>;
+	pinctrl-0 = <&spi1m2_pins>, <&spi1m2_csn0>;
+	status = "okay";
+
+	/* SPI controlled MCU for joystick and joystick LEDs. */
+};
+
+&vop {
+	status = "okay";
+};
+
+&vop_mmu {
+	status = "okay";
+};
+
+&vp0 {
+	vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
+		reg = <ROCKCHIP_VOP2_EP_HDMI0>;
+		remote-endpoint = <&hdmi_in_vp0>;
+	};
+};
+
+&vp1 {
+	vp1_out_dsi: endpoint at ROCKCHIP_VOP2_EP_MIPI0 {
+		reg = <ROCKCHIP_VOP2_EP_MIPI0>;
+		remote-endpoint = <&dsi_in_vp1>;
+	};
+};
+
+&u2phy0 {
+	status = "okay";
+};
+
+&u2phy0_otg {
+	status = "okay";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart6 {
+	pinctrl-0 = <&uart6m1_xfer>, <&uart6m1_ctsn>, <&uart6m1_rtsn>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+
+	bluetooth {
+		compatible = "realtek,rtl8822cs-bt";
+		device-wake-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_HIGH>;
+		enable-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
+		host-wake-gpios = <&gpio2 RK_PC1 GPIO_ACTIVE_HIGH>;
+		pinctrl-0 = <&bt_reset_gpio>, <&bt_wake_gpio>, <&bt_wake_host_irq>;
+		pinctrl-names = "default";
+	};
+};
+
+&usbdp_phy {
+	mode-switch;
+	orientation-switch;
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbc0_sbu1 &usbc0_sbu2>;
+	sbu1-dc-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>;
+	sbu2-dc-gpios = <&gpio4 RK_PB7 GPIO_ACTIVE_HIGH>;
+	status = "okay";
+
+	port {
+		usbdp_phy_ep: endpoint {
+			remote-endpoint = <&usbc0_dp_ep>;
+		};
+	};
+};
+
+&usb_drd0_dwc3 {
+	usb-role-switch;
+	dr_mode = "otg";
+	status = "okay";
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port at 0 {
+			reg = <0>;
+			usb_drd0_hs_ep: endpoint {
+				remote-endpoint = <&usbc0_hs_ep>;
+			};
+		};
+
+		port at 1 {
+			reg = <1>;
+			usb_drd0_ss_ep: endpoint {
+				remote-endpoint = <&usbc0_ss_ep>;
+			};
+		};
+	};
+};
-- 
2.43.0



From conor at kernel.org  Wed Jun 10 09:33:06 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Jun 2026 17:33:06 +0100
Subject: [PATCH 1/3] dt-bindings: vendor-prefixes: Add youyeetoo
In-Reply-To: <20260610-yy3588-board-v1-1-4bb7176b6826@superkali.me>
References: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
 <20260610-yy3588-board-v1-1-4bb7176b6826@superkali.me>
Message-ID: <20260610-automated-imitate-7052e09dcb33@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-rockchip/attachments/20260610/d3443906/attachment.sig>

From conor at kernel.org  Wed Jun 10 09:33:25 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Jun 2026 17:33:25 +0100
Subject: [PATCH 2/3] dt-bindings: arm: rockchip: Add Youyeetoo YY3588
In-Reply-To: <20260610-yy3588-board-v1-2-4bb7176b6826@superkali.me>
References: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
 <20260610-yy3588-board-v1-2-4bb7176b6826@superkali.me>
Message-ID: <20260610-synergy-stipend-f53ec049246b@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-rockchip/attachments/20260610/9893dfaf/attachment.sig>

From conor at kernel.org  Wed Jun 10 09:43:44 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Jun 2026 17:43:44 +0100
Subject: [PATCH v2 1/2] dt-bindings: arm: rockchip: Add HINLINK H28K
In-Reply-To: <20260610100006.366963-2-amadeus@jmu.edu.cn>
References: <20260610100006.366963-1-amadeus@jmu.edu.cn>
 <20260610100006.366963-2-amadeus@jmu.edu.cn>
Message-ID: <20260610-rectal-subtype-77250f6bc6ff@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-rockchip/attachments/20260610/59c1d409/attachment.sig>

From macroalpha82 at gmail.com  Wed Jun 10 10:54:44 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:44 -0500
Subject: [PATCH V11 0/9] Add Invensense ICM42607
Message-ID: <20260610175455.19006-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.

This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.

Changes Since V1:
 - Instead of creating a new driver, merged with the existing inv_icm42600
   driver. This necessitated adding some code to the existing driver to
   permit using a different register layout for the same functionality.
 - Split changes up a bit more to decrease the size of the individual
   patches. Note that patch 0004 is still pretty hefty; if I need to split
   further I may need to create some temporary stub functions.
 - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
   per Jonathan's recommendations.

Changes Since V2:
 - Went back to using a new driver on advice from Invensense engineer.
 - Further split changes up into smaller chunks of functionality. Note
   still that the largest patch is approximately 900 lines, and that while
   the driver compiles cleanly at each commit it is not able to drive the
   hardware until the commit that adds the Interrupt (as it also adds the
   Makefile).
 - Change the error to a warning when the devicetree binding does not match
   the hardware ID.
 - Dropped the ack on the devicetree bindings, as I am creating a new file
   (for a new driver) instead of modifying the existing one.

Changes Since V3:
 - Numerous small fixes (too many to list here). Thank you to everyone who
   provided feedback.
 - Split power management additions into an additional commit to break
   things up further.
 - Consolidated devicetree documentation in existing
   invensense,icm42600.yaml file.
 - Removed most of the FIELD_PREP from header file to c files to make code
   easier to read.
 - Changed scale values to 2D arrays for Gyro and Accelerometer.
 - Removed IIO_CHAN_INFO_CALIBBIAS attribute.

Changes Since V4:
 - Additional numerous small fixes, thank you again for all the feedback.
 - Dropped power control API and instead run device in low noise mode.
 - Split devicetree bindings into two distinct changes.
 - Reordered adding of enums and structs to main header file so that they
   are only brought in when needed.
 - Stopped using enum for driver data and instead am using pointer to
   device specific driver data.

Changes Since V5:
 - Corrected use of "dev_warn_probe" to just "dev_warn".
 - Fixed some return scenarios which would unconditionally return 0
   when an error was present.
 - Corrected use of max() to min() for bounds checking. max() was
   incorrect.
 - Fixed using "st->conf.accel.odr" in the gyroscope function. It
   should have been "st->conf.gyro.odr" which it now is.
 - Additional small fixes suggested by "sashiko.dev".
 - Added a regmap cache. I used the datasheet to try and determine
   which registers might change without explicit writes.

Changes Since V6:
 - Corrected additional errors identified by sashiko.dev, mostly
   fixing potential deadlocks, missing calls for pm runtime, and
   potential overflow issues.

Changes Since V7:
 - Dropped Wake on Movement patches, since some of the functionality
   was only available for a device on which I cannot test.
 - Dropped support for SPI 3-Wire mode, since it complicated the
   bus setup (and I lack the hardware to test such features anyway).
 - Fixed a few additional bugs identified by sashiko.dev bot.

Changes Since V8:
 - Added back IRQ dropped accidentally when dropping wake on movement
   patches.
 - Dropped "Reviewed-By" tag on patch 2 because of substantial changes
   made to devicetree binding documentation.
 - Additional small fixes as suggested.

Changes Since V9:
 - Removed interrupts (and buffers) from the driver. I previously was
   unable to detect deadlocks because it turns out my IRQ was not even
   wired correctly in my device.
 - Updated devicetree binding commits to make interrupts optional for
   users of the icm42607 driver.

Changes Since V10:
 - Explicitly specified enum values in header file.
 - Removed additional dead code for buffer handling.
 - Cleaned up headers.
 - Added additional locks as requested by sashiko.dev bot.

Chris Morgan (9):
  dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
  dt-bindings: iio: imu: icm42600: Add icm42607
  iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
  iio: imu: inv_icm42607: Add I2C and SPI For icm42607
  iio: imu: inv_icm42607: Add PM support for icm42607
  iio: imu: inv_icm42607: Add Temp Support in icm42607
  iio: imu: inv_icm42607: Add Accelerometer for icm42607
  iio: imu: inv_icm42607: Add Gyroscope to icm42607
  arm64: dts: rockchip: Add icm42607p IMU for RG-DS

 .../bindings/iio/imu/invensense,icm42600.yaml |  20 +-
 .../dts/rockchip/rk3568-anbernic-rg-ds.dts    |   8 +-
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 ++
 drivers/iio/imu/inv_icm42607/Makefile         |  13 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 415 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 379 +++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 506 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 369 +++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  93 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 105 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  |  82 +++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  |  33 ++
 14 files changed, 2053 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:45 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:45 -0500
Subject: [PATCH V11 1/9] dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add mount-matrix attribute to schema. This attribute has been supported
since the first revision of this driver, but was not documented.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/iio/imu/invensense,icm42600.yaml        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd..9b2af104f186 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -53,6 +53,8 @@ properties:
   drive-open-drain:
     type: boolean
 
+  mount-matrix: true
+
   vdd-supply:
     description: Regulator that provides power to the sensor
 
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:46 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:46 -0500
Subject: [PATCH V11 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the ICM42607 and ICM42607P inertial measurement unit.

This device is functionally very similar to the icm42600 series with a
very different register layout. The driver does not require an
interrupt for these specific chip revisions.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../bindings/iio/imu/invensense,icm42600.yaml  | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 9b2af104f186..81b6e85decd5 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
       - invensense,icm42600
       - invensense,icm42602
       - invensense,icm42605
+      - invensense,icm42607
+      - invensense,icm42607p
       - invensense,icm42622
       - invensense,icm42631
       - invensense,icm42686
@@ -67,10 +69,24 @@ properties:
 required:
   - compatible
   - reg
-  - interrupts
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - invensense,icm42600
+              - invensense,icm42602
+              - invensense,icm42605
+              - invensense,icm42622
+              - invensense,icm42631
+              - invensense,icm42686
+              - invensense,icm42688
+    then:
+      required:
+        - interrupts
 
 unevaluatedProperties: false
 
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:47 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:47 -0500
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the core component of a new inv_icm42607 driver. This includes
a few setup functions and the full register definition in the
header file.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
 2 files changed, 531 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..716fc0f1c3fd
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,334 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+enum inv_icm42607_sensor_mode {
+	INV_ICM42607_SENSOR_MODE_OFF = 0,
+	INV_ICM42607_SENSOR_MODE_STANDBY = 1,
+	INV_ICM42607_SENSOR_MODE_LOW_POWER = 2,
+	INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3,
+	INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+	INV_ICM42607_GYRO_FS_2000DPS = 0,
+	INV_ICM42607_GYRO_FS_1000DPS = 1,
+	INV_ICM42607_GYRO_FS_500DPS = 2,
+	INV_ICM42607_GYRO_FS_250DPS = 3,
+	INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+	INV_ICM42607_ACCEL_FS_16G = 0,
+	INV_ICM42607_ACCEL_FS_8G = 1,
+	INV_ICM42607_ACCEL_FS_4G = 2,
+	INV_ICM42607_ACCEL_FS_2G = 3,
+	INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values  - Note Gyro does not support ODR less than 12.5Hz */
+enum inv_icm42607_odr {
+	INV_ICM42607_ODR_1600HZ = 5,
+	INV_ICM42607_ODR_800HZ = 6,
+	INV_ICM42607_ODR_400HZ = 7,
+	INV_ICM42607_ODR_200HZ = 8,
+	INV_ICM42607_ODR_100HZ = 9,
+	INV_ICM42607_ODR_50HZ = 10,
+	INV_ICM42607_ODR_25HZ = 11,
+	INV_ICM42607_ODR_12_5HZ = 12,
+	INV_ICM42607_ODR_6_25HZ_LP = 13,
+	INV_ICM42607_ODR_3_125HZ_LP = 14,
+	INV_ICM42607_ODR_1_5625HZ_LP = 15,
+	INV_ICM42607_ODR_NB
+};
+
+/* Low-Noise mode sensor data filter (bandwidth) */
+enum inv_icm42607_filter_bw {
+	INV_ICM42607_FILTER_BYPASS = 0,
+	INV_ICM42607_FILTER_BW_180HZ = 1,
+	INV_ICM42607_FILTER_BW_121HZ = 2,
+	INV_ICM42607_FILTER_BW_73HZ = 3,
+	INV_ICM42607_FILTER_BW_53HZ = 4,
+	INV_ICM42607_FILTER_BW_34HZ = 5,
+	INV_ICM42607_FILTER_BW_25HZ = 6,
+	INV_ICM42607_FILTER_BW_16HZ = 7,
+	INV_ICM42607_FILTER_BW_NB
+};
+
+/* Signed so that negative values can signify an invalid condition. */
+struct inv_icm42607_sensor_conf {
+	int mode;
+	int fs;
+	int odr;
+	int filter;
+};
+
+struct inv_icm42607_conf {
+	struct inv_icm42607_sensor_conf gyro;
+	struct inv_icm42607_sensor_conf accel;
+	bool temp_en;
+};
+
+struct inv_icm42607_hw {
+	u8 whoami;
+	const char *name;
+	const struct inv_icm42607_conf *conf;
+};
+
+/**
+ *  struct inv_icm42607_state - driver state variables
+ *  @lock:		lock for serializing multiple registers access.
+ *  @hw:		Hardware specific data.
+ *  @map:		regmap pointer.
+ *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @orientation:	sensor chip orientation relative to main hardware.
+ *  @conf:		chip sensors configurations.
+ */
+struct inv_icm42607_state {
+	struct mutex lock;
+	const struct inv_icm42607_hw *hw;
+	struct regmap *map;
+	struct regulator *vddio_supply;
+	struct iio_mount_matrix orientation;
+	struct inv_icm42607_conf conf;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY			0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG			0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE		BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE		BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET		0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET	BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH	BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1			0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2			0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3			0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG			0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED		BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL		BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH	BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW		0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED		BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL		BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH	BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW		0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1			0x09
+#define INV_ICM42607_REG_TEMP_DATA0			0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1			0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0			0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1			0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0			0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1			0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0			0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1			0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0			0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1			0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0			0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1			0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0			0x16
+#define INV_ICM42607_DATA_INVALID			-32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH			0x17
+#define INV_ICM42607_REG_TMST_FSYNCL			0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0			0x31
+#define INV_ICM42607_REG_APEX_DATA1			0x32
+#define INV_ICM42607_REG_APEX_DATA2			0x33
+#define INV_ICM42607_REG_APEX_DATA3			0x34
+#define INV_ICM42607_REG_APEX_DATA4			0x1D
+#define INV_ICM42607_REG_APEX_DATA5			0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0			0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL		BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE			BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK		GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0			0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0			0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0			0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK		GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1			0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1			0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK		GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0			0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN	BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN		BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN	BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1			0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE		BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE		BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE		BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE		BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG			0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK		GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE		BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE			BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN			BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1			0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE			BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2			0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3			0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm)		\
+		cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX			(2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE		8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE		16
+
+#define INV_ICM42607_REG_INT_SOURCE0			0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1			0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3			0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4			0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN		BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN		BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0			0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1			0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0			0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42607_REG_INTF_CONFIG1			0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN		BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN		BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK		GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT		0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL		1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF		2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY		0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY		BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS			0x3A
+#define INV_ICM42607_INT_STATUS_ST			BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC			BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY			BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE		BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS		BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL		BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY			BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2			0x3B
+#define INV_ICM42607_INT_STATUS2_SMD			BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3			0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET		BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF		BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET		BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET			BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH			0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL			0x3E
+#define INV_ICM42607_REG_FIFO_DATA			0x3F
+
+#define INV_ICM42607_REG_ACCEL_WOM_X_THR		0x4b
+#define INV_ICM42607_REG_ACCEL_WOM_Y_THR		0x4c
+#define INV_ICM42607_REG_ACCEL_WOM_Z_THR		0x4d
+
+#define INV_ICM42607_REG_WHOAMI				0x75
+#define INV_ICM42607P_WHOAMI				0x60
+#define INV_ICM42607_WHOAMI				0x67
+
+/* Timings as listed in section 3 of datasheet */
+#define INV_ICM42607_POWER_UP_TIME_US			100000
+#define INV_ICM42607_RESET_TIME_MS			1
+#define INV_ICM42607_ACCEL_STARTUP_TIME_MS		10
+#define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
+#define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..334264120b42
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
+				 const struct inv_icm42607_conf *conf)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+	/*
+	 * No temperature enable reg in datasheet, but BSP driver selected RC
+	 * oscillator clock in LP mode when temperature was disabled.
+	 */
+	if (!conf->temp_en)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+	val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+	val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+				 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+				 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	st->conf = *conf;
+
+	return 0;
+}
+
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	const struct device *dev = regmap_get_device(st->map);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+	if (ret)
+		return ret;
+
+	/* Warn, but don't fail. */
+	if (val != st->hw->whoami)
+		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+			 val, st->hw->whoami, st->hw->name);
+
+	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
+
+	/*
+	 * No polling interval specified in datasheet, so use reset time as
+	 * polling interval and 10x reset time as timeout period.
+	 */
+	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
+				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "reset error, reset done bit not set\n");
+
+	/* Sync the regcache again after a reset. */
+	regcache_mark_dirty(st->map);
+	ret = regcache_sync(st->map);
+	if (ret)
+		return ret;
+
+	ret = inv_icm42607_bus_setup(st);
+	if (ret)
+		return ret;
+
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+	int ret;
+
+	ret = regulator_enable(st->vddio_supply);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+	return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+	struct inv_icm42607_state *st = _data;
+
+	regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	struct device *dev = regmap_get_device(regmap);
+	struct inv_icm42607_state *st;
+	int ret;
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
+	st->hw = hw;
+	st->map = regmap;
+
+	ret = iio_read_mount_matrix(dev, &st->orientation);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to retrieve mounting matrix\n");
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get vdd regulator\n");
+
+	st->vddio_supply = devm_regulator_get(dev, "vddio");
+	if (IS_ERR(st->vddio_supply))
+		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+				     "Failed to get vddio regulator\n");
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+	if (ret)
+		return ret;
+
+	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+	ret = inv_icm42607_setup(st, inv_icm42607_bus_setup);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP");
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:48 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:48 -0500
Subject: [PATCH V11 4/9] iio: imu: inv_icm42607: Add I2C and SPI For icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add I2C and SPI driver support for InvenSense ICM-42607 devices.
Add necessary Kconfig and Makefile to allow building of (incomplete)
driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 +++++
 drivers/iio/imu/inv_icm42607/Makefile         |  10 ++
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  16 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  57 ++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  92 ++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 104 ++++++++++++++++++
 8 files changed, 311 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c

diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb6..8bab4616be20 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
 source "drivers/iio/imu/inv_icm45600/Kconfig"
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c9..3268dc2371ae 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
 obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
 
 obj-y += inv_icm42600/
+obj-y += inv_icm42607/
 obj-y += inv_icm45600/
 obj-y += inv_mpu6050/
 
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 000000000000..7ba64e6e8d80
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+	tristate
+	select IIO_BUFFER
+	select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+	tristate "InvenSense ICM-42607X I2C driver"
+	depends on I2C
+	select INV_ICM42607
+	select REGMAP_I2C
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over I2C.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+	tristate "InvenSense ICM-42607X SPI driver"
+	depends on SPI_MASTER
+	select INV_ICM42607
+	select REGMAP_SPI
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over SPI.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 000000000000..be109102e203
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 716fc0f1c3fd..743a15fb1b89 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -12,6 +12,22 @@
 #include <linux/regmap.h>
 #include <linux/types.h>
 
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+	INV_ICM42607_SLEW_RATE_20_60NS = 0,
+	INV_ICM42607_SLEW_RATE_12_36NS = 1,
+	INV_ICM42607_SLEW_RATE_6_19NS = 2,
+	INV_ICM42607_SLEW_RATE_4_14NS = 3,
+	INV_ICM42607_SLEW_RATE_2_6NS = 4,
+	INV_ICM42607_SLEW_RATE_2NS = 5,
+	INV_ICM42607_SLEW_RATE_NB
+};
+
 enum inv_icm42607_sensor_mode {
 	INV_ICM42607_SENSOR_MODE_OFF = 0,
 	INV_ICM42607_SENSOR_MODE_STANDBY = 1,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 334264120b42..26dc09bbeaed 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -14,6 +14,63 @@
 
 #include "inv_icm42607.h"
 
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY:
+	case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+	case INV_ICM42607_REG_APEX_CONFIG0:
+	case INV_ICM42607_REG_FIFO_CONFIG2 ... INV_ICM42607_REG_FIFO_CONFIG3:
+	case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+	case INV_ICM42607_REG_INT_STATUS_DRDY:
+	case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = INV_ICM42607_REG_WHOAMI,
+	.cache_type = REGCACHE_MAPLE,
+	.volatile_reg = inv_icm42607_is_volatile_reg,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+	.gyro = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_GYRO_FS_1000DPS,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.accel = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_ACCEL_FS_4G,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.temp_en = false,
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+	.whoami = INV_ICM42607_WHOAMI,
+	.name = "icm42607",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+	.whoami = INV_ICM42607P_WHOAMI,
+	.name = "icm42607p",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 000000000000..2946d5465853
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+			 INV_ICM42607_SLEW_RATE_12_36NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+				 INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = i2c_get_match_data(client);
+	if (!hw)
+		return dev_err_probe(&client->dev, -ENODEV,
+				     "Failed to get i2c data\n");
+
+	regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&client->dev, PTR_ERR(regmap),
+				     "Failed to register i2c regmap %ld\n",
+				     PTR_ERR(regmap));
+
+	return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	}, {
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-i2c",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_id,
+	.probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 000000000000..3485777ac5b6
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	/* Only support 4-wire mode for now. */
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+				      INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+	if (ret)
+		return ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+			 INV_ICM42607_SLEW_RATE_2NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+				 INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+	if (ret)
+		return ret;
+
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = spi_get_device_match_data(spi);
+	if (!hw)
+		return dev_err_probe(&spi->dev, -ENODEV,
+				     "Failed to get SPI data\n");
+
+	if (spi->mode & SPI_3WIRE)
+		return dev_err_probe(&spi->dev, -ENODEV,
+				     "SPI 3-wire mode not supported\n");
+
+	regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&spi->dev, PTR_ERR(regmap),
+				     "Failed to register spi regmap %ld\n",
+				     PTR_ERR(regmap));
+
+	return inv_icm42607_core_probe(regmap, hw,
+				       inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	},
+	{
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-spi",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_spi_id_table,
+	.probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:49 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:49 -0500
Subject: [PATCH V11 5/9] iio: imu: inv_icm42607: Add PM support for icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add power management support for the ICM42607 device driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  18 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 125 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |   1 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   |   1 +
 4 files changed, 145 insertions(+)

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 743a15fb1b89..1f1397eaa00e 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -9,6 +9,7 @@
 #include <linux/bits.h>
 #include <linux/iio/iio.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/regmap.h>
 #include <linux/types.h>
 
@@ -103,22 +104,32 @@ struct inv_icm42607_hw {
 	const struct inv_icm42607_conf *conf;
 };
 
+struct inv_icm42607_suspended {
+	enum inv_icm42607_sensor_mode gyro;
+	enum inv_icm42607_sensor_mode accel;
+	bool temp;
+};
+
 /**
  *  struct inv_icm42607_state - driver state variables
  *  @lock:		lock for serializing multiple registers access.
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
  *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @vddio_en:		I/O voltage status for runtime PM.
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
+ *  @suspended:		suspended sensors configuration.
  */
 struct inv_icm42607_state {
 	struct mutex lock;
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
 	struct regulator *vddio_supply;
+	bool vddio_en;
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
+	struct inv_icm42607_suspended suspended;
 };
 
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -337,11 +348,18 @@ struct inv_icm42607_state {
 #define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
 #define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
 
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS			2000
+
 typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
 
 extern const struct regmap_config inv_icm42607_regmap_config;
 extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 26dc09bbeaed..5e1f924a3e34 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -8,6 +8,7 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time.h>
@@ -71,6 +72,51 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+				      enum inv_icm42607_sensor_mode gyro,
+				      enum inv_icm42607_sensor_mode accel,
+				      bool temp, unsigned int *sleep_ms)
+{
+	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
+	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
+	bool oldtemp = st->conf.temp_en;
+	unsigned int sleepval;
+	unsigned int val;
+	int ret;
+
+	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+		return 0;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+	if (!temp)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	st->conf.gyro.mode = gyro;
+	st->conf.accel.mode = accel;
+	st->conf.temp_en = temp;
+
+	sleepval = 0;
+	if (temp && !oldtemp)
+		sleepval = max(sleepval, INV_ICM42607_TEMP_STARTUP_TIME_MS);
+
+	if (accel != oldaccel)
+		sleepval = max(sleepval, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
+
+	if (gyro != oldgyro)
+		sleepval = max(sleepval, INV_ICM42607_GYRO_STARTUP_TIME_MS);
+
+	if (sleep_ms)
+		*sleep_ms = sleepval;
+	else if (sleepval)
+		fsleep(sleepval * USEC_PER_MSEC);
+
+	return 0;
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
@@ -181,12 +227,17 @@ static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
 {
 	int ret;
 
+	if (st->vddio_en)
+		return 0;
+
 	ret = regulator_enable(st->vddio_supply);
 	if (ret)
 		return ret;
 
 	fsleep(INV_ICM42607_POWER_UP_TIME_US);
 
+	st->vddio_en = true;
+
 	return 0;
 }
 
@@ -194,7 +245,12 @@ static void inv_icm42607_disable_vddio_reg(void *_data)
 {
 	struct inv_icm42607_state *st = _data;
 
+	if (!st->vddio_en)
+		return;
+
 	regulator_disable(st->vddio_supply);
+
+	st->vddio_en = false;
 }
 
 int inv_icm42607_core_probe(struct regmap *regmap,
@@ -209,6 +265,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (!st)
 		return -ENOMEM;
 
+	dev_set_drvdata(dev, st);
+
 	ret = devm_mutex_init(dev, &st->lock);
 	if (ret)
 		return ret;
@@ -244,10 +302,77 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (ret)
 		return ret;
 
+	ret = devm_pm_runtime_set_active_enabled(dev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(dev);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
 
+static int inv_icm42607_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		return ret;
+
+	inv_icm42607_disable_vddio_reg(st);
+
+	return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* save sensors state */
+	st->suspended.gyro = st->conf.gyro.mode;
+	st->suspended.accel = st->conf.accel.mode;
+	st->suspended.temp = st->conf.temp_en;
+
+	return inv_icm42607_set_pwr_mgmt0(st, INV_ICM42607_SENSOR_MODE_OFF,
+					  INV_ICM42607_SENSOR_MODE_OFF, false,
+					  NULL);
+}
+
+static int inv_icm42607_runtime_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* restore sensors state */
+	return inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
+					  st->suspended.accel,
+					  st->suspended.temp, NULL);
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+	SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
+		       inv_icm42607_runtime_resume, NULL)
+};
+
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
index 2946d5465853..0c2ff8e12643 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -80,6 +80,7 @@ static struct i2c_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-i2c",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_id,
 	.probe = inv_icm42607_probe,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
index 3485777ac5b6..1a7f6b0fa86b 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -92,6 +92,7 @@ static struct spi_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-spi",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_spi_id_table,
 	.probe = inv_icm42607_probe,
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:50 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:50 -0500
Subject: [PATCH V11 6/9] iio: imu: inv_icm42607: Add Temp Support in icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add functions for reading temperature sensor data.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |  1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  5 ++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 18 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  | 82 +++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  | 33 ++++++++
 5 files changed, 139 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index be109102e203..c04953ed42ce 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 1f1397eaa00e..1246a92edffc 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -120,6 +120,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @buffer:		data transfer buffer aligned for DMA.
  */
 struct inv_icm42607_state {
 	struct mutex lock;
@@ -130,6 +131,7 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
 
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -361,6 +363,9 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 5e1f924a3e34..88e3a064434b 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -117,6 +117,24 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+			 INV_ICM42607_FILTER_BW_34HZ);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+				 INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+					  st->conf.accel.mode, enable,
+					  sleep_ms);
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
new file mode 100644
index 000000000000..55260082a19e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp)
+{
+	struct device *dev = regmap_get_device(st->map);
+	__be16 *raw;
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_temp_conf(st, true, NULL);
+	if (ret)
+		return ret;
+
+	raw = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1,
+			       raw, sizeof(*raw));
+	if (ret)
+		return ret;
+
+	*temp = be16_to_cpup(raw);
+	if (*temp == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 temp;
+	int ret;
+
+	if (chan->type != IIO_TEMP)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_temp_read(st, &temp);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = temp;
+		return IIO_VAL_INT;
+	/*
+	 * T?C = (temp / 128) + 25
+	 * Tm?C = 1000 * ((temp * 100 / 12800) + 25)
+	 * scale: 100000 / 12800 ~= 7.8125
+	 * offset: 3200
+	 */
+	case IIO_CHAN_INFO_SCALE:
+		*val = 7;
+		*val2 = 812500000;
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 3200;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
new file mode 100644
index 000000000000..e03924e30866
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_TEMP_H_
+#define INV_ICM42607_TEMP_H_
+
+#include <linux/bitops.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+#define INV_ICM42607_TEMP_CHAN(_index)				\
+{								\
+	.type = IIO_TEMP,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW) |			\
+		BIT(IIO_CHAN_INFO_OFFSET) |			\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+	},							\
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long mask);
+
+#endif
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:51 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:51 -0500
Subject: [PATCH V11 7/9] iio: imu: inv_icm42607: Add Accelerometer for icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-8-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add icm42607 accelerometer sensor for icm42607.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  34 ++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 379 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  61 +++
 4 files changed, 475 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index c04953ed42ce..d74b23b1e1be 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 1246a92edffc..52f047d96eb4 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -84,6 +84,17 @@ enum inv_icm42607_filter_bw {
 	INV_ICM42607_FILTER_BW_NB
 };
 
+/* Low-Power mode sensor data filter (averaging) */
+enum inv_icm42607_filter_avg {
+	INV_ICM42607_FILTER_AVG_2X = 0,
+	INV_ICM42607_FILTER_AVG_4X = 1,
+	INV_ICM42607_FILTER_AVG_8X = 2,
+	INV_ICM42607_FILTER_AVG_16X = 3,
+	INV_ICM42607_FILTER_AVG_32X = 4,
+	INV_ICM42607_FILTER_AVG_64X = 5,
+	/* values 6 and 7 also correspond to 64x. */
+};
+
 /* Signed so that negative values can signify an invalid condition. */
 struct inv_icm42607_sensor_conf {
 	int mode;
@@ -91,6 +102,7 @@ struct inv_icm42607_sensor_conf {
 	int odr;
 	int filter;
 };
+#define INV_ICM42607_SENSOR_CONF_INIT		{ -1, -1, -1, -1 }
 
 struct inv_icm42607_conf {
 	struct inv_icm42607_sensor_conf gyro;
@@ -120,6 +132,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @indio_accel:	accelerometer IIO device.
  *  @buffer:		data transfer buffer aligned for DMA.
  */
 struct inv_icm42607_state {
@@ -131,9 +144,20 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	struct iio_dev *indio_accel;
 	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
 
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @power_mode:		sensor requested power mode (for common frequencies)
+ * @filter:		sensor filter.
+ */
+struct inv_icm42607_sensor_state {
+	enum inv_icm42607_sensor_mode power_mode;
+	int filter;
+};
+
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
 
 /* Register Map for User Bank 0 */
@@ -363,6 +387,14 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan);
+
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -370,4 +402,6 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
+
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
new file mode 100644
index 000000000000..cb60bb5ecc14
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)		\
+{									\
+	.type = IIO_ACCEL,						\
+	.modified = 1,							\
+	.channel2 = _modifier,						\
+	.info_mask_separate =						\
+		BIT(IIO_CHAN_INFO_RAW),					\
+	.info_mask_shared_by_type =					\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_type_available =				\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_all =					\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.info_mask_shared_by_all_available =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.scan_index = _index,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 16,						\
+		.storagebits = 16,					\
+		.endianness = IIO_BE,					\
+	},								\
+	.ext_info = _ext_info,						\
+}
+
+enum inv_icm42607_accel_scan {
+	INV_ICM42607_ACCEL_SCAN_X,
+	INV_ICM42607_ACCEL_SCAN_Y,
+	INV_ICM42607_ACCEL_SCAN_Z,
+	INV_ICM42607_ACCEL_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP),
+};
+
+static int inv_icm42607_accel_read_sensor(struct iio_dev *indio_dev,
+					  struct iio_chan_spec const *chan,
+					  s16 *val)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable accel sensor */
+	conf.mode = accel_st->power_mode;
+	conf.filter = accel_st->filter;
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read accel register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_accel_scale_nano[][2] = {
+	[INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 },
+	[INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 },
+	[INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 },
+	[INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 }
+};
+
+static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev,
+					 int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.accel.fs;
+
+	*val = inv_icm42607_accel_scale_nano[idx][0];
+	*val2 = inv_icm42607_accel_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev,
+					  int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_accel_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_accel_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_accel_conf(st, &conf, NULL);
+}
+
+/* IIO format int + micro , values 0-5 reserved. */
+static const int inv_icm42607_accel_odr[][2] = {
+	[INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 },
+	[INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 },
+	[INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 },
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 }
+};
+
+static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
+				       int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.accel.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_accel_odr[i][0];
+	*val2 = inv_icm42607_accel_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
+					int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
+		if (val == inv_icm42607_accel_odr[idx][0] &&
+		    val2 == inv_icm42607_accel_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ACCEL:
+		break;
+	case IIO_TEMP:
+		return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_accel_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_read_avail(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 const int **vals,
+					 int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_accel_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_accel_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_accel_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
+		iio_device_release_direct(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
+						struct iio_chan_spec const *chan,
+						long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_accel_info = {
+	.read_raw = inv_icm42607_accel_read_raw,
+	.read_avail = inv_icm42607_accel_read_avail,
+	.write_raw = inv_icm42607_accel_write_raw,
+	.write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *accel_st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	accel_st = iio_priv(indio_dev);
+
+	accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+	accel_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_accel_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_accel_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 88e3a064434b..96e170b10aa4 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -72,6 +72,15 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan)
+{
+	const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+	return &st->orientation;
+}
+
 static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 				      enum inv_icm42607_sensor_mode gyro,
 				      enum inv_icm42607_sensor_mode accel,
@@ -117,6 +126,53 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.accel;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		if (conf->mode == INV_ICM42607_SENSOR_MODE_LOW_POWER) {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
+		} else {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
+					 conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+		}
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -327,6 +383,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
 	pm_runtime_use_autosuspend(dev);
 
+	/* Initialize IIO device for Accel */
+	st->indio_accel = inv_icm42607_accel_init(st);
+	if (IS_ERR(st->indio_accel))
+		return PTR_ERR(st->indio_accel);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:52 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:52 -0500
Subject: [PATCH V11 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-9-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add gyroscope functions to the icm42607 driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |   8 +
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  48 +++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 369 ++++++++++++++++++
 4 files changed, 426 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index d74b23b1e1be..7b907e019601 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_gyro.o
 inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 52f047d96eb4..df30503807c8 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -132,6 +132,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  *  @conf:		chip sensors configurations.
  *  @suspended:		suspended sensors configuration.
+ *  @indio_gyro:	gyroscope IIO device.
  *  @indio_accel:	accelerometer IIO device.
  *  @buffer:		data transfer buffer aligned for DMA.
  */
@@ -144,6 +145,7 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 	struct inv_icm42607_conf conf;
 	struct inv_icm42607_suspended suspended;
+	struct iio_dev *indio_gyro;
 	struct iio_dev *indio_accel;
 	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 };
@@ -395,6 +397,10 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 				struct inv_icm42607_sensor_conf *conf,
 				unsigned int *sleep_ms);
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -402,6 +408,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st);
+
 struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
 
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 96e170b10aa4..99ae67f826bc 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -173,6 +173,49 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 					  st->conf.temp_en, sleep_ms);
 }
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.gyro;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK,
+				 conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK,
+				  conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
+				 conf->filter);
+		ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+					 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -388,6 +431,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (IS_ERR(st->indio_accel))
 		return PTR_ERR(st->indio_accel);
 
+	/* Initialize IIO device for Gyro */
+	st->indio_gyro = inv_icm42607_gyro_init(st);
+	if (IS_ERR(st->indio_gyro))
+		return PTR_ERR(st->indio_gyro);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
new file mode 100644
index 000000000000..8cabebe2e96b
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info)	\
+{								\
+	.type = IIO_ANGL_VEL,					\
+	.modified = 1,						\
+	.channel2 = _modifier,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW),				\
+	.info_mask_shared_by_type =				\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_BE,				\
+	},							\
+	.ext_info = _ext_info,					\
+}
+
+enum inv_icm42607_gyro_scan {
+	INV_ICM42607_GYRO_SCAN_X,
+	INV_ICM42607_GYRO_SCAN_Y,
+	INV_ICM42607_GYRO_SCAN_Z,
+	INV_ICM42607_GYRO_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP),
+};
+
+static int inv_icm42607_gyro_read_sensor(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 s16 *val)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_GYRO_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable gyro sensor */
+	conf.mode = gyro_st->power_mode;
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read gyro register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_gyro_scale_nano[][2] = {
+	[INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 },
+	[INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 },
+	[INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 },
+	[INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 },
+};
+
+static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev,
+					int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.gyro.fs;
+
+	*val = inv_icm42607_gyro_scale_nano[idx][0];
+	*val2 = inv_icm42607_gyro_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev,
+					 int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano);
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_gyro_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_gyro_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
+}
+
+static const int inv_icm42607_gyro_odr[][2] = {
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+};
+
+static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st,
+				      int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.gyro.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_gyro_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_gyro_odr[i][0];
+	*val2 = inv_icm42607_gyro_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
+				       int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); ++idx) {
+		if (val == inv_icm42607_gyro_odr[idx][0] &&
+		    val2 == inv_icm42607_gyro_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ANGL_VEL:
+		break;
+	case IIO_TEMP:
+		return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_gyro_read_sensor(indio_dev, chan, &data);
+		iio_device_release_direct(indio_dev);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_gyro_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_read_avail(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					const int **vals,
+					int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_gyro_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_gyro_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_gyro_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		if (!iio_device_claim_direct(indio_dev))
+			return -EBUSY;
+		ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2);
+		iio_device_release_direct(indio_dev);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
+					       struct iio_chan_spec const *chan,
+					       long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_gyro_info = {
+	.read_raw = inv_icm42607_gyro_read_raw,
+	.read_avail = inv_icm42607_gyro_read_avail,
+	.write_raw = inv_icm42607_gyro_write_raw,
+	.write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *gyro_st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	gyro_st = iio_priv(indio_dev);
+
+	gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_gyro_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_gyro_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
-- 
2.43.0



From macroalpha82 at gmail.com  Wed Jun 10 10:54:53 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Wed, 10 Jun 2026 12:54:53 -0500
Subject: [PATCH V11 9/9] arm64: dts: rockchip: Add icm42607p IMU for RG-DS
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260610175455.19006-10-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix
was tested with iio-sensor-proxy and reports correct orientation.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
index 8d906ab02c5f..b770bfd5268d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
@@ -871,7 +871,13 @@ aw87391_pa_r: audio-codec at 5b {
 		sound-name-prefix = "Right Amp";
 	};
 
-	/* invensense,icm42607p at 0x68 */
+	icm42607p: imu at 68 {
+		compatible = "invensense,icm42607p";
+		reg = <0x68>;
+		mount-matrix = "-1", "0", "0",
+			       "0", "1", "0",
+			       "0", "0", "-1";
+	};
 };
 
 &i2c3 {
-- 
2.43.0



From simon at symple.nz  Wed Jun 10 23:15:02 2026
From: simon at symple.nz (Simon Wright)
Date: Thu, 11 Jun 2026 18:15:02 +1200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <2CB1844A-3DB7-4973-98E0-0C141DD38B45@gmail.com>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
 <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>
 <2CB1844A-3DB7-4973-98E0-0C141DD38B45@gmail.com>
Message-ID: <1f178828-2cba-4120-bc6d-bb3be7b24073@symple.nz>

Hi Piotr,

Short version: the in-tree port didn't actually have the warmup running (it needs a
probe-time buffer alloc + a pm_runtime_resume hook, not just the decode code). Rather
than pick that apart, here's a clean patch that wires it properly - and I've now
validated it on hardware.

The patch is self-contained and needs no devicetree change (mainline already maps the
"link" register bank it uses); git apply-clean on 7.0 and 7.1-rc7:

    https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug/tree/master/fix

    git apply fix/0001-media-rkvdec-prime-VDPU383-deblock-warmup-rk3576.patch

It adds one file (rkvdec-rk3576-workaround.c) plus a probe + pm_runtime_resume hook,
scoped to the RK3576/VDPU383 variant. Confirm it's actually active before judging it:

    dmesg | grep -i "deblock-priming"
    # expect: "RK3576 H.264 deblock-priming workaround enabled"

I validated it on the two RK3576 boards here: on a NanoPi R76S the warmup takes BBB
from ~18% of decodes corrupt to 0/40; on an ArmSoM Sige5 the unpatched HW decode is
100% corrupt, and the corruption looks exactly like the photo you shared. Before/after
captures:

    https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug#what-it-looks-like

Your board spread (nanopi M5/R76S, rock4d 20-40%) and ours (R76S 18%, Sige5 100%) are the
same timing-marginal race the priming settles, so I'd expect it to clear on your
boards once it's firing.

If you get it built, a quick "builds + the line shows up", and a Tested-by across your
devices, would strengthen this for upstream - multi-board confirmation on a hardware
workaround is exactly what the maintainers want.

Regards,
Simon


From andriy.shevchenko at intel.com  Thu Jun 11 00:35:49 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Thu, 11 Jun 2026 10:35:49 +0300
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260610175455.19006-4-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-4-macroalpha82@gmail.com>
Message-ID: <aiplVZRI-0TCDnjL@ashevche-desk.local>

On Wed, Jun 10, 2026 at 12:54:47PM -0500, Chris Morgan wrote:

> Add the core component of a new inv_icm42607 driver. This includes
> a few setup functions and the full register definition in the
> header file.

...

>  2 files changed, 531 insertions(+)
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

I'm not sure this is correct split by files. These files are not:
- being build
- being mentioned in MAINTAINERS

...

> +#ifndef INV_ICM42607_H_
> +#define INV_ICM42607_H_
> +
> +#include <linux/bits.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>

mutex_types.h ?

> +#include <linux/regmap.h>
> +#include <linux/types.h>

Do you need forward declaration for regulator data type?

...

> +#define INV_ICM42607_POWER_UP_TIME_US			100000

100 * USEC_PER_MSEC (will require time.h)?

...

> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

+ bitfields.h

> +#include <linux/delay.h>
> +#include <linux/dev_printk.h>

+ device/devres.h
+ err.h

> +#include <linux/iio/iio.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/time.h>

Also check if you need types.h.

...

> +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> +
> +	/*
> +	 * No polling interval specified in datasheet, so use reset time as
> +	 * polling interval and 10x reset time as timeout period.
> +	 */
> +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));

Besides too many parentheses, this can be switched to regular patter of "num * what".
Also, TBH, the plain values would be better here

	fsleep(1 * USEC_PER_MSEC);

	/*
	 * No polling interval specified in datasheet, so use reset time as
	 * polling interval and 10x reset time as timeout period.
	 */
	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
				       1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);

And in the similar way in other fsleep() / _read_poll_timeout() cases.

> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "reset error, reset done bit not set\n");

-- 
With Best Regards,
Andy Shevchenko




From piotr.oniszczuk at gmail.com  Thu Jun 11 00:40:40 2026
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Thu, 11 Jun 2026 09:40:40 +0200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <1f178828-2cba-4120-bc6d-bb3be7b24073@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
 <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>
 <2CB1844A-3DB7-4973-98E0-0C141DD38B45@gmail.com>
 <1f178828-2cba-4120-bc6d-bb3be7b24073@symple.nz>
Message-ID: <8673B89B-0F1F-400D-BD0B-31FC1647167A@gmail.com>



> Wiadomo?? napisana przez Simon Wright <simon at symple.nz> w dniu 11 cze 2026, o godz. 08:15:
> 
> Hi Piotr,
> 
> Short version: the in-tree port didn't actually have the warmup running (it needs a
> probe-time buffer alloc + a pm_runtime_resume hook, not just the decode code). Rather
> than pick that apart, here's a clean patch that wires it properly - and I've now
> validated it on hardware.

Happy to hear that.
(I was afraid your excellent work will not solve my issue?)

> 
> The patch is self-contained and needs no devicetree change (mainline already maps the
> "link" register bank it uses); git apply-clean on 7.0 and 7.1-rc7:
> 
> 
>    dmesg | grep -i "deblock-priming"
>    # expect: "RK3576 H.264 deblock-priming workaround enabled"
> 

Im seeing this so all good.

> I validated it on the two RK3576 boards here: on a NanoPi R76S the warmup takes BBB
> from ~18% of decodes corrupt to 0/40; on an ArmSoM Sige5 the unpatched HW decode is
> 100% corrupt, and the corruption looks exactly like the photo you shared. Before/after
> captures:

Pls give me few days - I ask test users to give daily usage test runs to make sure users will be happy
(So far my short lab tests showing all good)

Simon: fantastic work!




From andriy.shevchenko at intel.com  Thu Jun 11 00:49:41 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Thu, 11 Jun 2026 10:49:41 +0300
Subject: [PATCH V11 4/9] iio: imu: inv_icm42607: Add I2C and SPI For
 icm42607
In-Reply-To: <20260610175455.19006-5-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-5-macroalpha82@gmail.com>
Message-ID: <aipolU1W3QNXdd5b@ashevche-desk.local>

On Wed, Jun 10, 2026 at 12:54:48PM -0500, Chris Morgan wrote:

> Add I2C and SPI driver support for InvenSense ICM-42607 devices.
> Add necessary Kconfig and Makefile to allow building of (incomplete)
> driver.

...

>  drivers/iio/imu/Kconfig                       |   1 +
>  drivers/iio/imu/Makefile                      |   1 +
>  drivers/iio/imu/inv_icm42607/Kconfig          |  30 +++++
>  drivers/iio/imu/inv_icm42607/Makefile         |  10 ++

These should be part of the previous patch.

...

> +config INV_ICM42607
> +	tristate

To make it compilable w.o. SPI/I2C make this as

	tristate "Inven... Core driver" if COMPILE_TEST


> +	select IIO_BUFFER
> +	select IIO_INV_SENSORS_TIMESTAMP

...

> +obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
> +inv-icm42607-i2c-y += inv_icm42607_i2c.o
> +
> +obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
> +inv-icm42607-spi-y += inv_icm42607_spi.o

Add each of them in a separate patch.

...

> +#include <linux/device.h>

Why?
And a lot of missing headers (bitfield.h, dev_printk.h, mod_devicetable.h, err.h)

> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>

...

> +static int inv_icm42607_probe(struct i2c_client *client)
> +{
> +	const struct inv_icm42607_hw *hw;
> +	struct regmap *regmap;
> +
> +	hw = i2c_get_match_data(client);
> +	if (!hw)
> +		return dev_err_probe(&client->dev, -ENODEV,
> +				     "Failed to get i2c data\n");

Add

	struct device *dev = &client->dev;

and modify this and other eligible pieces accordingly.

		return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n");

> +	regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
> +	if (IS_ERR(regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(regmap),
> +				     "Failed to register i2c regmap %ld\n",

Do not duplicate a printing of an error code.

> +				     PTR_ERR(regmap));

		return dev_err_probe(dev, PTR_ERR(regmap),
				     "Failed to register i2c regmap\n");

> +	return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
> +}
> +

...

> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c

As per above.

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Thu Jun 11 01:00:17 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Thu, 11 Jun 2026 11:00:17 +0300
Subject: [PATCH V11 5/9] iio: imu: inv_icm42607: Add PM support for
 icm42607
In-Reply-To: <20260610175455.19006-6-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-6-macroalpha82@gmail.com>
Message-ID: <aiprEfu5K7rP0LRr@ashevche-desk.local>

On Wed, Jun 10, 2026 at 12:54:49PM -0500, Chris Morgan wrote:
> Add power management support for the ICM42607 device driver.

...

>  struct inv_icm42607_state {
>  	struct mutex lock;
>  	const struct inv_icm42607_hw *hw;
>  	struct regmap *map;
>  	struct regulator *vddio_supply;
> +	bool vddio_en;
>  	struct iio_mount_matrix orientation;
>  	struct inv_icm42607_conf conf;
> +	struct inv_icm42607_suspended suspended;
>  };

When adding a new member to the data structure always consult with `pahole`
tool to see if the layout is the best fit.

...

> +/*
> + * Suspend delay assumed from other icm42600 series device, not
> + * documented in datasheet.
> + */
> +#define INV_ICM42607_SUSPEND_DELAY_MS			2000

2 * USEC_PER_MSEC

...

> +	sleepval = 0;
> +	if (temp && !oldtemp)
> +		sleepval = max(sleepval, INV_ICM42607_TEMP_STARTUP_TIME_MS);
> +
> +	if (accel != oldaccel)
> +		sleepval = max(sleepval, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
> +
> +	if (gyro != oldgyro)
> +		sleepval = max(sleepval, INV_ICM42607_GYRO_STARTUP_TIME_MS);
> +
> +	if (sleep_ms)
> +		*sleep_ms = sleepval;
> +	else if (sleepval)
> +		fsleep(sleepval * USEC_PER_MSEC);

Also good to have a _ms suffis in sleepval.

...

> +	dev_set_drvdata(dev, st);

This what requires device.h. So, you can start with it whenever you first need
dev_printk.h, devres/*.h, but it doesn't mean you are supposed to drop other
non-device.h related headers, such as err.h.

...

> +EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
> +	SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
> +	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
> +		       inv_icm42607_runtime_resume, NULL)

Keep it logically split, either as

	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend, inv_icm42607_runtime_resume, NULL)

or as

	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
		       inv_icm42607_runtime_resume,
		       NULL)

> +};

-- 
With Best Regards,
Andy Shevchenko




From m.szyprowski at samsung.com  Thu Jun 11 01:26:14 2026
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Thu, 11 Jun 2026 10:26:14 +0200
Subject: [PATCH 0/2] gpio: fix sleeping-in-atomic in shared-proxy;
 restore meson non-sleeping
In-Reply-To: <20260610153329.937833-1-v@baodeep.com>
References: <CGME20260610153425eucas1p29d20a835114a28b15cb12ea00534e074@eucas1p2.samsung.com>
	<20260610153329.937833-1-v@baodeep.com>
Message-ID: <184d315b-a0a1-4792-8a40-1b4967025916@samsung.com>

Hi Viachesla,

On 10.06.2026 17:32, Viacheslav Bocharov wrote:
> gpio-shared-proxy chooses its descriptor lock (mutex vs spinlock) from
> the underlying chip's can_sleep, but under that lock it calls config and
> direction ops that reach sleeping pinctrl paths. On a controller with
> non-sleeping MMIO value ops the lock is a spinlock, so a sleeping call
> runs from atomic context:
>
>   BUG: sleeping function called from invalid context
>     ... pinctrl_gpio_set_config <- gpiochip_generic_config
>     <- gpio_shared_proxy_set_config (voting spinlock held)
>     <- ... <- mmc_pwrseq_simple_probe
>
> This was reported on Khadas VIM3 and worked around for Amlogic by
> commit 28f240683871 ("pinctrl: meson: mark the GPIO controller as
> sleeping"), which marked the whole meson controller sleeping. That
> workaround broke atomic value-path consumers: w1-gpio (1-Wire bitbang)
> no longer detects devices, because its IRQ-disabled read slot calls the
> non-cansleep gpiod_*_value() and now hits WARN_ON(can_sleep) per bit.
>
> Patch 1 fixes the proxy locking generically (always a sleeping mutex).
> Patch 2 then restores meson can_sleep=false, fixing 1-Wire.
>
> Patch 1 has a trade-off: a proxied GPIO becomes sleeping, so consumers
> gating on gpiod_cansleep() change behaviour. No current device needs
> atomic (non-cansleep) value access on a shared GPIO -- every report
> (Khadas VIM3, ODROID-M1, my test on JetHub D1+) is a shared reset line
> (eMMC/SDIO pwrseq or PCIe reset) driven through the cansleep accessors,
> which is what the proxy exists to vote on. An alternative that keeps
> atomic value access (split locking) is possible but adds a second lock
> and new race windows. I went with the simpler, verified approach and
> would appreciate guidance on whether the atomic value path must be
> preserved.
>
> The two are a unit: patch 2 must not be applied without patch 1,
> otherwise the original VIM3 splat returns on boards that share a meson
> GPIO -- please keep the order. I have not Cc'd stable; I will request
> stable backports separately once both patches have landed.
>
> Viacheslav Bocharov (2):
>   gpio: shared-proxy: always serialize with a sleeping mutex
>   pinctrl: meson: restore non-sleeping GPIO access

Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>

This probably also affects the similar changes in Rockchip GPIO driver done
by the following commits:
20cf2aed89ac ("gpio: rockchip: mark the GPIO controller as sleeping")
7ca497be0016 ("gpio: rockchip: Stop calling pinctrl for set_direction")

I've checked this patchset with these two reverted and no warning was reported.

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland



From broonie at kernel.org  Wed Jun 10 04:12:06 2026
From: broonie at kernel.org (Mark Brown)
Date: Wed, 10 Jun 2026 12:12:06 +0100
Subject: [PATCH] ASoC: dt-bindings: everest,es8389: Document audio
 graph port
In-Reply-To: <20260607105913.355966-1-diederik@cknow-tech.com>
References: <20260607105913.355966-1-diederik@cknow-tech.com>
Message-ID: <178108992684.232889.2776738169377861702.b4-ty@b4>

On Sun, 07 Jun 2026 12:58:49 +0200, Diederik de Haas wrote:
> ASoC: dt-bindings: everest,es8389: Document audio graph port

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/1] ASoC: dt-bindings: everest,es8389: Document audio graph port
      https://git.kernel.org/broonie/sound/c/aa283db3bb8d

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 v at baodeep.com  Thu Jun 11 02:27:23 2026
From: v at baodeep.com (Viacheslav)
Date: Thu, 11 Jun 2026 12:27:23 +0300
Subject: [PATCH 0/2] gpio: fix sleeping-in-atomic in shared-proxy; restore
 meson non-sleeping
In-Reply-To: <184d315b-a0a1-4792-8a40-1b4967025916@samsung.com>
References: <CGME20260610153425eucas1p29d20a835114a28b15cb12ea00534e074@eucas1p2.samsung.com>
 <20260610153329.937833-1-v@baodeep.com>
 <184d315b-a0a1-4792-8a40-1b4967025916@samsung.com>
Message-ID: <a523e854-c1d8-4f9d-a184-70ebee5fd630@baodeep.com>

Hi, Marek!

11.06.2026 11:26, Marek Szyprowski wrote:
> Hi Viachesla,
> 
> On 10.06.2026 17:32, Viacheslav Bocharov wrote:
> 
> Tested-by: Marek Szyprowski <m.szyprowski at samsung.com>
> 

Thanks for testing.

> This probably also affects the similar changes in Rockchip GPIO driver done
> by the following commits:
> 20cf2aed89ac ("gpio: rockchip: mark the GPIO controller as sleeping")
> 7ca497be0016 ("gpio: rockchip: Stop calling pinctrl for set_direction")
> 

Yeah, we also need to revert can_sleep=true on rockchip and amlogic-a4 
(d6df4abe95a4).


Best regards
--
Viacheslav Bocharov
Shenzhen JetHome Technology Co., Ltd.


From mripard at kernel.org  Thu Jun 11 02:49:02 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Thu, 11 Jun 2026 09:49:02 +0000
Subject: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in
 hotplug_event()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
Message-ID: <be56d8fe4fe3e7bd1c37b92c273c414d@kernel.org>

On Tue, 2 Jun 2026 01:44:01 +0300, Cristian Ciocaltea wrote:
> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
> only stores a return value that is never used beyond the immediate
> return statement.  This simplifies the code without behavior changes.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> [ ... ]

Acked-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From jic23 at kernel.org  Thu Jun 11 03:52:19 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 11:52:19 +0100
Subject: [PATCH V11 4/9] iio: imu: inv_icm42607: Add I2C and SPI For
 icm42607
In-Reply-To: <aipolU1W3QNXdd5b@ashevche-desk.local>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-5-macroalpha82@gmail.com>
	<aipolU1W3QNXdd5b@ashevche-desk.local>
Message-ID: <20260611115219.318fe543@jic23-huawei>

On Thu, 11 Jun 2026 10:49:41 +0300
Andy Shevchenko <andriy.shevchenko at intel.com> wrote:

> On Wed, Jun 10, 2026 at 12:54:48PM -0500, Chris Morgan wrote:
> 
> > Add I2C and SPI driver support for InvenSense ICM-42607 devices.
> > Add necessary Kconfig and Makefile to allow building of (incomplete)
> > driver.  
> 
> ...
> 
> >  drivers/iio/imu/Kconfig                       |   1 +
> >  drivers/iio/imu/Makefile                      |   1 +
> >  drivers/iio/imu/inv_icm42607/Kconfig          |  30 +++++
> >  drivers/iio/imu/inv_icm42607/Makefile         |  10 ++  
> 
> These should be part of the previous patch.
> 
> ...
> 
> > +config INV_ICM42607
> > +	tristate  
> 
> To make it compilable w.o. SPI/I2C make this as
> 
> 	tristate "Inven... Core driver" if COMPILE_TEST
Hi Andy,

Is it worth it?  I'm not convinced - we will get pretty 
good build coverage with a dependence on either SPI or I2C.
Plus as someone who always builds with COMPILE_TEST this
seems overly noisy to me.

Jonathan


From jic23 at kernel.org  Thu Jun 11 03:59:38 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 11:59:38 +0100
Subject: [PATCH V11 0/9] Add Invensense ICM42607
In-Reply-To: <20260610175455.19006-1-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
Message-ID: <20260611115938.27712b66@jic23-huawei>

On Wed, 10 Jun 2026 12:54:44 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add support for the ICM42607 IMU. This sensor shares the same
> functionality but a different register layout with the existing
> ICM42600.
> 
> This driver should work with the ICM42607 and ICM42607P over both I2C
> and SPI, however only the ICM42607P over I2C could be tested.
Hi Chris,

Just a quick reminder to check if there is useful feedback at:
https://sashiko.dev/#/patchset/20260610175455.19006-1-macroalpha82%40gmail.com

I didn't look into most of the but the last one about no avail mask bits
being set for gyro channels was easy to verify as correct and suggests
a testing gap.

Jonathan



From jic23 at kernel.org  Thu Jun 11 04:09:43 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 12:09:43 +0100
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260610175455.19006-4-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-4-macroalpha82@gmail.com>
Message-ID: <20260611120943.7119975b@jic23-huawei>

On Wed, 10 Jun 2026 12:54:47 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add the core component of a new inv_icm42607 driver. This includes
> a few setup functions and the full register definition in the
> header file.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Hi Chris,

A couple more minor things from a fresh read.

Thanks

Jonathan

> ---
>  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
>  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
>  2 files changed, 531 insertions(+)
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> 
> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> new file mode 100644
> index 000000000000..716fc0f1c3fd
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> new file mode 100644
> index 000000000000..334264120b42
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

> +
> +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> +{
> +	const struct device *dev = regmap_get_device(st->map);
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> +	if (ret)
> +		return ret;
> +
> +	/* Warn, but don't fail. */
> +	if (val != st->hw->whoami)
> +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> +			 val, st->hw->whoami, st->hw->name);
> +
> +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> +	if (ret)
> +		return ret;
> +
> +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> +
> +	/*
> +	 * No polling interval specified in datasheet, so use reset time as
> +	 * polling interval and 10x reset time as timeout period.
> +	 */
> +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "reset error, reset done bit not set\n");
> +
> +	/* Sync the regcache again after a reset. */
> +	regcache_mark_dirty(st->map);
> +	ret = regcache_sync(st->map);

Sashiko raised the point that you don't have a writeable register list for the regmap
and so potentially we at very least write a bunch of stuff that isn't needed.
I doubt it's actually a problem or you would have seen it, but nice little optimization
to reduce what is written.

> +	if (ret)
> +		return ret;
> +
> +	ret = inv_icm42607_bus_setup(st);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> +			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
> +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);

That should have a FIELD_PREP() to save us having to got check that
the MASK includes the LSB.  

> +	if (ret)
> +		return ret;
> +
> +	return inv_icm42607_set_conf(st, st->hw->conf);
> +}

> +
> +MODULE_AUTHOR("InvenSense, Inc.");
> +MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");

Why does it have a trailing x?  Whilst a wild card is less harmful
here than in many places I'd still drop it.

> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP");

Do we need this yet?  I think it only gets used later, in which case
move it to the first patch that needs this.




From jic23 at kernel.org  Thu Jun 11 04:12:52 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 12:12:52 +0100
Subject: [PATCH V11 4/9] iio: imu: inv_icm42607: Add I2C and SPI For
 icm42607
In-Reply-To: <20260610175455.19006-5-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-5-macroalpha82@gmail.com>
Message-ID: <20260611121252.679bc6ec@jic23-huawei>

On Wed, 10 Jun 2026 12:54:48 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add I2C and SPI driver support for InvenSense ICM-42607 devices.
> Add necessary Kconfig and Makefile to allow building of (incomplete)
> driver.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>

Some similar missing FIELD_PREP() comments. Not a bug, but
a readability issue that is easy to resolve.

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> index 334264120b42..26dc09bbeaed 100644
> --- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
>
> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
> new file mode 100644
> index 000000000000..2946d5465853
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
> @@ -0,0 +1,92 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +#include "inv_icm42607.h"
> +
> +static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
> +{
> +	unsigned int val;
> +	int ret;
> +
> +	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> +				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
> +				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
> +	if (ret)
> +		return ret;
> +
> +	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
> +			 INV_ICM42607_SLEW_RATE_12_36NS);
> +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
> +				 INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> +				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
> +				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
FIELD_PREP() (see below)
> +}

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
> new file mode 100644
> index 000000000000..3485777ac5b6
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
> @@ -0,0 +1,104 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/spi/spi.h>
> +
> +#include "inv_icm42607.h"
> +
> +static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
> +{
> +	unsigned int val;
> +	int ret;
> +
> +	/* Only support 4-wire mode for now. */
> +	ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
> +				      INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> +				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
> +				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
> +	if (ret)
> +		return ret;
> +
> +	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
> +			 INV_ICM42607_SLEW_RATE_2NS);
> +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
> +				 INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> +				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
> +				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
Should be a FIELD_PREP() for readability (so reviewer doesn't need to check
this field includes bit 0)

> +}
>




From jic23 at kernel.org  Thu Jun 11 04:22:13 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 12:22:13 +0100
Subject: [PATCH V11 6/9] iio: imu: inv_icm42607: Add Temp Support in
 icm42607
In-Reply-To: <20260610175455.19006-7-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-7-macroalpha82@gmail.com>
Message-ID: <20260611122213.631903ec@jic23-huawei>

On Wed, 10 Jun 2026 12:54:50 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add functions for reading temperature sensor data.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Hi Chris,

A few consistency things around the channel definitions and some
left over stuff I think from you ripping out the interrupt / buffered support.

Thanks,

Jonathan

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
> new file mode 100644
> index 000000000000..55260082a19e
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
> @@ -0,0 +1,82 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "inv_icm42607.h"
> +#include "inv_icm42607_temp.h"

> +int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
> +				struct iio_chan_spec const *chan,
> +				int *val, int *val2, long mask)
> +{
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	s16 temp;
> +	int ret;
> +
> +	if (chan->type != IIO_TEMP)
> +		return -EINVAL;
This feels little over defensive given the function name. Any bug
that called it anyway would be pretty bad!
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:

The lack of having the shared_by_all stuff in here makes things
a little fragile (once you've added them to the bitmap below) as
which chan->type we get depends on channel registration ordering.

So avoid this being called for those mask elements.  I'll reply
to next patch to call that out in a few mins.

> +		if (!iio_device_claim_direct(indio_dev))
> +			return -EBUSY;

A driver that isn't yet doing buffered support should not be
claiming modes (as it's always in direct mode).  If this is
serializing for some reason other than avoiding mode transitions,
it should be using the local lock. Seems it is doing that
anyway so just drop this layer of protection.

> +		ret = inv_icm42607_temp_read(st, &temp);
> +		iio_device_release_direct(indio_dev);
> +		if (ret)
> +			return ret;
> +		*val = temp;
> +		return IIO_VAL_INT;
> +	/*
> +	 * T?C = (temp / 128) + 25
> +	 * Tm?C = 1000 * ((temp * 100 / 12800) + 25)
> +	 * scale: 100000 / 12800 ~= 7.8125
> +	 * offset: 3200
> +	 */
> +	case IIO_CHAN_INFO_SCALE:
> +		*val = 7;
> +		*val2 = 812500000;
> +		return IIO_VAL_INT_PLUS_NANO;
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = 3200;
> +		return IIO_VAL_INT;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
> new file mode 100644
> index 000000000000..e03924e30866
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#ifndef INV_ICM42607_TEMP_H_
> +#define INV_ICM42607_TEMP_H_
> +
> +#include <linux/bitops.h>
> +
> +struct iio_dev;
> +struct iio_chan_spec;
> +
> +#define INV_ICM42607_TEMP_CHAN(_index)				\
> +{								\
> +	.type = IIO_TEMP,					\
> +	.info_mask_separate =					\
> +		BIT(IIO_CHAN_INFO_RAW) |			\
> +		BIT(IIO_CHAN_INFO_OFFSET) |			\
> +		BIT(IIO_CHAN_INFO_SCALE),			\

Whilst it makes no difference to exposure of sysfs attributes, this
should include the shared_by_all stuff form the other channels.
That is supposed to be in every channel so that we can easily see
what affects each channel. 

> +	.scan_index = _index,					\
> +	.scan_type = {						\
> +		.sign = 's',					\
> +		.realbits = 16,					\
> +		.storagebits = 16,				\
> +	},							\
> +}
> +
> +int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
> +			       struct iio_chan_spec const *chan,
> +			       int *val, int *val2, long mask);
> +
> +#endif



From vkoul at kernel.org  Thu Jun 11 04:26:23 2026
From: vkoul at kernel.org (Vinod Koul)
Date: Thu, 11 Jun 2026 16:56:23 +0530
Subject: [PATCH v2 0/6] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
In-Reply-To: <ebcad67e-e14a-4d0e-b3e0-79ae1d146eaf@collabora.com>
References: <20260511-hdptx-clk-fixes-v2-0-664e41379cab@collabora.com>
 <e0eeb794-11b9-4ba6-bee2-f6cc607d3a16@collabora.com>
 <ebcad67e-e14a-4d0e-b3e0-79ae1d146eaf@collabora.com>
Message-ID: <aiqbX8kon8HtiSEl@vaman>

On 03-06-26, 13:27, Cristian Ciocaltea wrote:
> On 5/20/26 10:05 PM, Cristian Ciocaltea wrote:
> > Hi Vinod,
> > 
> > On 5/11/26 9:21 PM, Cristian Ciocaltea wrote:
> >> This series provides a set of bug fixes and cleanups for the Rockchip
> >> Samsung HDPTX PHY driver.
> >>
> >> The first part of the series (i.e. PATCH 1 & 2) addresses clock rate
> >> calculation and synchronization issues.  Specifically, it fixes edge
> >> cases where the PHY PLL is pre-programmed by an external component (like
> >> a bootloader) or when changing the color depth (bpc) while keeping the
> >> modeline constant.  Because the Common Clock Framework .set_rate()
> >> callback might not be invoked if the pixel clock remains unchanged, this
> >> previously led to out-of-sync states between CCF and the actual HDMI PHY
> >> configuration.
> >>
> >> The second part focuses on code cleanups and modernizing the register
> >> access.  Now that dw_hdmi_qp driver has fully switched to using
> >> phy_configure(), we can drop the deprecated TMDS rate setup workarounds
> >> and the restrict_rate_change flag logic.  Finally, it refactors the
> >> driver to consistently use standard bitfield macros.
> >>
> >> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> >> ---
> >> Changes in v2:
> >> - Collected Tested-by tags from Thomas and Simon
> >> - Fixed a typo in commit description of patch 1
> >> - Added a comment in patch 2 explaining why PLL config errors are
> >>   ignored for rk_hdptx_phy_consumer_get()
> >> - Added a missed FIELD_GET conversion for lcpll_hw.pms_sdiv in patch 6
> >> - Rebased onto latest phy/fixes
> >> - Link to v1: https://lore.kernel.org/r/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f at collabora.com
> > 
> > In case you missed my comments from last week on the Sashiko AI review findings
> > - in short, I don't think there is anything to worry about and the series should
> > be fine to apply as-is.  Please let me know if you would still prefer a new
> > revision.
> Kind reminder..

Please post a new revision based on phy/next

Thanks
-- 
~Vinod


From jic23 at kernel.org  Thu Jun 11 04:31:03 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 12:31:03 +0100
Subject: [PATCH V11 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <20260610175455.19006-8-macroalpha82@gmail.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-8-macroalpha82@gmail.com>
Message-ID: <20260611123103.198353d3@jic23-huawei>

On Wed, 10 Jun 2026 12:54:51 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add icm42607 accelerometer sensor for icm42607.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>

Minor things inline.

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
> new file mode 100644
> index 000000000000..cb60bb5ecc14
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
> @@ -0,0 +1,379 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "inv_icm42607.h"
> +#include "inv_icm42607_temp.h"
> +
> +#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)		\
> +{									\
> +	.type = IIO_ACCEL,						\
> +	.modified = 1,							\
> +	.channel2 = _modifier,						\
> +	.info_mask_separate =						\
> +		BIT(IIO_CHAN_INFO_RAW),					\
> +	.info_mask_shared_by_type =					\
> +		BIT(IIO_CHAN_INFO_SCALE),				\
> +	.info_mask_shared_by_type_available =				\
> +		BIT(IIO_CHAN_INFO_SCALE),				\
> +	.info_mask_shared_by_all =					\
> +		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
> +	.info_mask_shared_by_all_available =				\
> +		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\

See other comments on this is is 'all' and perhaps applies to temperature.
If it doesn't apply to temperature then it may need splitting up.

Little less clear cut for mount matrix, so I don't mind that one just

> +	.scan_index = _index,						\
> +	.scan_type = {							\
> +		.sign = 's',						\
> +		.realbits = 16,						\
> +		.storagebits = 16,					\
> +		.endianness = IIO_BE,					\
> +	},								\
> +	.ext_info = _ext_info,						\
> +}


> +static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
> +					int val, int val2)
> +{
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	struct device *dev = regmap_get_device(st->map);
> +	unsigned int idx;
> +	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
> +	int ret;
> +
> +	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
> +		if (val == inv_icm42607_accel_odr[idx][0] &&
> +		    val2 == inv_icm42607_accel_odr[idx][1])
> +			break;
> +	}
> +	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
> +		return -EINVAL;
> +
> +	conf.odr = idx;
> +
> +	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> +	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&st->lock);
> +
> +	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
> +	if (ret)
> +		return ret;
> +
> +	return 0;

If this isn't getting more complex later,
	return inv_...

> +}
> +
> +static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
> +				       struct iio_chan_spec const *chan,
> +				       int *val, int *val2, long mask)
> +{
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	s16 data;
> +	int ret;
> +
> +	switch (chan->type) {
> +	case IIO_ACCEL:
> +		break;
> +	case IIO_TEMP:
> +		return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);

I commented on this in previous patch, but once the shared_by_all is
added to the temp channel, this needs modifying to ensure we only call the
temp handler for cases that aren't shared_by_all.

> +	default:
> +		return -EINVAL;
> +	}
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		if (!iio_device_claim_direct(indio_dev))
> +			return -EBUSY;

As below - drop these mode claims as for now there is only one mode.

> +		ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
> +		iio_device_release_direct(indio_dev);
> +		if (ret)
> +			return ret;
> +		*val = data;
> +		return IIO_VAL_INT;
> +	case IIO_CHAN_INFO_SCALE:
> +		return inv_icm42607_accel_read_scale(indio_dev, val, val2);
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		return inv_icm42607_accel_read_odr(st, val, val2);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int inv_icm42607_accel_read_avail(struct iio_dev *indio_dev,
> +					 struct iio_chan_spec const *chan,
> +						 const int **vals,
> +					 int *type, int *length, long mask)
> +{
> +	if (chan->type != IIO_ACCEL)
> +		return -EINVAL;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SCALE:
> +		*vals = (const int *)inv_icm42607_accel_scale_nano;
> +		*type = IIO_VAL_INT_PLUS_NANO;
> +		*length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
> +		return IIO_AVAIL_LIST;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		*vals = (const int *)inv_icm42607_accel_odr[5];
> +		*type = IIO_VAL_INT_PLUS_MICRO;
> +		*length = (ARRAY_SIZE(inv_icm42607_accel_odr) - 5) * 2;
> +		return IIO_AVAIL_LIST;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
> +					struct iio_chan_spec const *chan,
> +					int val, int val2, long mask)
> +{
> +	int ret;
> +
> +	if (chan->type != IIO_ACCEL)
> +		return -EINVAL;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_SCALE:
> +		if (!iio_device_claim_direct(indio_dev))

As in previous, this stuff doesn't belong in a driver that is always in direct
mode.

> +			return -EBUSY;
> +		ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
> +		iio_device_release_direct(indio_dev);
> +		return ret;
> +	case IIO_CHAN_INFO_SAMP_FREQ:
> +		return inv_icm42607_accel_write_odr(indio_dev, val, val2);
> +	default:
> +		return -EINVAL;
> +	}

> +struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
> +{
> +	struct device *dev = regmap_get_device(st->map);
> +	const char *name;

where no other strong reason for ordering, reverse xmas tree.

> +	struct inv_icm42607_sensor_state *accel_st;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
> +	if (!name)
> +		return ERR_PTR(-ENOMEM);
> +
> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
> +	if (!indio_dev)
> +		return ERR_PTR(-ENOMEM);
> +	accel_st = iio_priv(indio_dev);
> +
> +	accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
> +	accel_st->filter = INV_ICM42607_FILTER_BW_73HZ;
> +
> +	iio_device_set_drvdata(indio_dev, st);
> +	indio_dev->name = name;
> +	indio_dev->info = &inv_icm42607_accel_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = inv_icm42607_accel_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
> +
> +	ret = devm_iio_device_register(dev, indio_dev);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	return indio_dev;
> +}



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:02 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:02 +0300
Subject: [PATCH v3 0/6] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
Message-ID: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>

This series provides a set of bug fixes and cleanups for the Rockchip
Samsung HDPTX PHY driver.

The first part of the series (i.e. PATCH 1 & 2) addresses clock rate
calculation and synchronization issues.  Specifically, it fixes edge
cases where the PHY PLL is pre-programmed by an external component (like
a bootloader) or when changing the color depth (bpc) while keeping the
modeline constant.  Because the Common Clock Framework .set_rate()
callback might not be invoked if the pixel clock remains unchanged, this
previously led to out-of-sync states between CCF and the actual HDMI PHY
configuration.

The second part focuses on code cleanups and modernizing the register
access.  Now that dw_hdmi_qp driver has fully switched to using
phy_configure(), we can drop the deprecated TMDS rate setup workarounds
and the restrict_rate_change flag logic.  Finally, it refactors the
driver to consistently use standard bitfield macros.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v3:
- Replaced div_u64() with DIV_ROUND_CLOSEST_ULL() in Patch 1 (Sashiko)
- Fixed theoretical usage_count unbalanced issue in Patch 2 (Sashiko)
- Rebased series onto latest phy/next
- Link to v2: https://patch.msgid.link/20260511-hdptx-clk-fixes-v2-0-664e41379cab at collabora.com

Changes in v2:
- Collected Tested-by tags from Thomas and Simon
- Fixed a typo in commit description of patch 1
- Added a comment in patch 2 explaining why PLL config errors are
  ignored for rk_hdptx_phy_consumer_get()
- Added a missed FIELD_GET conversion for lcpll_hw.pms_sdiv in patch 6
- Rebased onto latest phy/fixes
- Link to v1: https://lore.kernel.org/r/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f at collabora.com

---
Cristian Ciocaltea (6):
      phy: rockchip: samsung-hdptx: Fix rate recalculation for high bpc
      phy: rockchip: samsung-hdptx: Handle uncommitted PHY config changes
      phy: rockchip: samsung-hdptx: Drop TMDS rate setup workaround
      phy: rockchip: samsung-hdptx: Drop restrict_rate_change handling
      phy: rockchip: samsung-hdptx: Simplify GRF access with FIELD_PREP_WM16()
      phy: rockchip: samsung-hdptx: Consistently use bitfield macros

 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 216 ++++++++++------------
 1 file changed, 95 insertions(+), 121 deletions(-)
---
base-commit: 293e19f416fa3f233a2fb013258f7abcb39ad6ed
change-id: 20260227-hdptx-clk-fixes-47426632f862



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:03 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:03 +0300
Subject: [PATCH v3 1/6] phy: rockchip: samsung-hdptx: Fix rate
 recalculation for high bpc
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-1-67b1b0c00e16@collabora.com>

The PHY PLL can be programmed by an external component, e.g. the
bootloader, just before the recalc_rate() callback is invoked during
devm_clk_hw_register() in the probe path.

Therefore rk_hdptx_phy_clk_recalc_rate() finds the PLL enabled and
attempts to compute the clock rate, while making use of the bpc value
from the HDMI PHY configuration, which always defaults to 8 because
phy_configure() was not run at that point.  As a consequence, the
(re)calculated rate is incorrect when the actual bpc was higher than 8.

Do not rely on any of the hdmi_cfg members when computing the clock rate
and, instead, read the required input data (i.e. bpc), directly from the
hardware registers.

Fixes: 3481fc04d969 ("phy: rockchip: samsung-hdptx: Compute clk rate from PLL config")
Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 2d973bc37f07..710603afff86 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -2168,7 +2168,7 @@ 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;
+	u32 mode, bpc, val;
 	int ret, i;
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
@@ -2266,6 +2266,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	if (ret)
 		return 0;
 	ropll_hw.pms_sdiv = ((val & PLL_PCG_POSTDIV_SEL_MASK) >> 4) + 1;
+	bpc = (FIELD_GET(PLL_PCG_CLK_SEL_MASK, val) << 1) + 8;
 
 	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
 	if (ropll_hw.sdm_en) {
@@ -2280,7 +2281,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 			fout = fout + sdm;
 	}
 
-	return div_u64(fout * 2, ropll_hw.pms_sdiv * 10);
+	return DIV_ROUND_CLOSEST_ULL(fout * 2 * 8, ropll_hw.pms_sdiv * 10 * bpc);
 }
 
 static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
@@ -2288,19 +2289,13 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 	u32 status;
-	u64 rate;
 	int ret;
 
 	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);
-
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
-		return rate;
-
-	return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
+	return rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
 }
 
 static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:04 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:04 +0300
Subject: [PATCH v3 2/6] phy: rockchip: samsung-hdptx: Handle uncommitted
 PHY config changes
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-2-67b1b0c00e16@collabora.com>

Any changes to the PHY link rate and/or color depth done via the HDMI
PHY configuration API are not immediately programmed into the hardware,
but are delayed until the PHY usage count gets incremented from 0 to 1,
that is when it is powered on or when the PLL clock exposed through
the CCF API is prepared, whichever comes first.

Since the clock might remain in prepared state after subsequent PHY
config changes, the programming can also be triggered via
clk_ops.set_rate().  However, from the clock consumer perspective (i.e.
VOP2 display controller), the (pixel) clock rate doesn't vary with bpc,
as that is handled internally by the PHY and reflected in the TDMS
character rate only.

As a consequence, changing the bpc while preserving the modeline may
lead to out-of-sync issues between CCF and HDMI PHY config state,
because the .set_rate() callback is not invoked when clock rate remains
constant.  This may also happen when the PHY PLL has been pre-programmed
by an external entity, e.g. the bootloader, which is actually a
regression introduced by the recent FRL patches.

Introduce a pll_config_dirty flag to keep track of uncommitted PHY
config changes and use it in clk_ops.determine_rate() to invalidate the
current clock rate (as known by CCF) and, consequently, ensure those
changes are programmed into hardware via clk_ops.set_rate().

Moreover, proceed with a similar fix in phy_ops.power_on() callback, to
handle the scenario where the CCF API is not used due to operating in
FRL mode, while the clock is still in a prepared state and thus
preventing rk_hdptx_phy_consumer_get() to apply the updated PHY
configuration.

Fixes: de5dba833118 ("phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support")
Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management")
Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 84 +++++++++++++----------
 1 file changed, 48 insertions(+), 36 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 710603afff86..5295d5f6f287 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -413,6 +413,7 @@ struct rk_hdptx_phy {
 
 	/* clk provider */
 	struct clk_hw hw;
+	bool pll_config_dirty;
 	bool restrict_rate_change;
 
 	atomic_t usage_count;
@@ -1260,13 +1261,19 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 
 static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx)
 {
+	int ret;
+
 	if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE)
-		return rk_hdptx_tmds_ropll_cmn_config(hdptx);
+		ret = rk_hdptx_tmds_ropll_cmn_config(hdptx);
+	else if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
+		ret = rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+	else
+		ret = rk_hdptx_frl_lcpll_cmn_config(hdptx);
 
-	if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
-		return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+	if (!ret)
+		hdptx->pll_config_dirty = false;
 
-	return rk_hdptx_frl_lcpll_cmn_config(hdptx);
+	return ret;
 }
 
 static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx)
@@ -1347,25 +1354,22 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
 		return 0;
 
 	ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status);
-	if (ret)
-		goto dec_usage;
-
-	if (status & HDPTX_O_PLL_LOCK_DONE)
-		dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n");
+	if (ret) {
+		atomic_dec(&hdptx->usage_count);
+		return ret;
+	}
 
 	if (mode == PHY_MODE_DP) {
 		rk_hdptx_dp_reset(hdptx);
 	} else {
-		ret = rk_hdptx_pll_cmn_config(hdptx);
-		if (ret)
-			goto dec_usage;
+		/*
+		 * Ignore PLL config errors at this point as pll_config_dirty
+		 * was not reset and, therefore, operation will be retried.
+		 */
+		rk_hdptx_pll_cmn_config(hdptx);
 	}
 
 	return 0;
-
-dec_usage:
-	atomic_dec(&hdptx->usage_count);
-	return ret;
 }
 
 static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
@@ -1700,13 +1704,18 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		if (ret)
 			rk_hdptx_phy_consumer_put(hdptx, true);
 	} else {
-		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+		if (hdptx->pll_config_dirty)
+			ret = rk_hdptx_pll_cmn_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) {
+			regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+				     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+
+			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);
@@ -2081,7 +2090,10 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
 			dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
 		} else {
 			hdptx->restrict_rate_change = true;
-			dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+			hdptx->pll_config_dirty = true;
+
+			dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
+				hdptx->hdmi_cfg.mode ? "FRL" : "TMDS",
 				hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 		}
 
@@ -2303,8 +2315,19 @@ static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
-		return hdptx->hdmi_cfg.rate;
+	/*
+	 * Invalidate current clock rate to ensure rk_hdptx_phy_clk_set_rate()
+	 * will be invoked to commit PLL configuration.
+	 */
+	if (hdptx->pll_config_dirty) {
+		req->rate = 0;
+		return 0;
+	}
+
+	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+		req->rate = hdptx->hdmi_cfg.rate;
+		return 0;
+	}
 
 	/*
 	 * FIXME: Temporarily allow altering TMDS char rate via CCF.
@@ -2336,17 +2359,6 @@ 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 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 link rate change since determine_rate() */
-	if (hdptx->hdmi_cfg.rate != link_rate) {
-		dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
-			 link_rate, hdptx->hdmi_cfg.rate);
-		hdptx->hdmi_cfg.rate = link_rate;
-	}
 
 	/*
 	 * The link rate would be normally programmed in HW during

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:05 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:05 +0300
Subject: [PATCH v3 3/6] phy: rockchip: samsung-hdptx: Drop TMDS rate setup
 workaround
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-3-67b1b0c00e16@collabora.com>

Since commit ba9c2fe18c17 ("drm/rockchip: dw_hdmi_qp: Switch to
phy_configure()") the TMDS rate setup doesn't rely anymore on the
unconventional usage of the bus width, instead it is managed exclusively
through the HDMI PHY configuration API.

Drop the now obsolete workaround to retrieve the TMDS character rate via
phy_get_bus_width() during power_on().

While at it, get rid of the extra call to rk_hdptx_phy_consumer_put() by
moving the statement at the end of the function.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 27 +++++------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 5295d5f6f287..92c77e58518c 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1660,22 +1660,6 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 	enum phy_mode mode = phy_get_mode(phy);
 	int ret, lane;
 
-	if (mode != PHY_MODE_DP) {
-		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.
-			 * Will be removed as soon the switch to the HDMI PHY
-			 * configuration API has been completed on both ends.
-			 */
-			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.rate, hdptx->hdmi_cfg.bpc);
-	}
-
 	ret = rk_hdptx_phy_consumer_get(hdptx);
 	if (ret)
 		return ret;
@@ -1701,9 +1685,10 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		rk_hdptx_dp_pll_init(hdptx);
 
 		ret = rk_hdptx_dp_aux_init(hdptx);
-		if (ret)
-			rk_hdptx_phy_consumer_put(hdptx, true);
 	} else {
+		dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+			hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
+
 		if (hdptx->pll_config_dirty)
 			ret = rk_hdptx_pll_cmn_config(hdptx);
 
@@ -1716,11 +1701,11 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 			else
 				ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
 		}
-
-		if (ret)
-			rk_hdptx_phy_consumer_put(hdptx, true);
 	}
 
+	if (ret)
+		rk_hdptx_phy_consumer_put(hdptx, true);
+
 	return ret;
 }
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:06 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:06 +0300
Subject: [PATCH v3 4/6] phy: rockchip: samsung-hdptx: Drop
 restrict_rate_change handling
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-4-67b1b0c00e16@collabora.com>

Since commit 6efbd0f46dd8 ("phy: rockchip: samsung-hdptx: Restrict
altering TMDS char rate via CCF"), adjusting the rate via the Common
Clock Framework API has been disallowed.

To avoid breaking existing users until switching to the PHY config API,
it introduced a temporary exception to the rule, controlled via the
'restrict_rate_change' flag.

As the API transition completed, remove the now deprecated exception
logic.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 42 +++++------------------
 1 file changed, 8 insertions(+), 34 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 92c77e58518c..529dd2d5d9bd 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -414,7 +414,6 @@ struct rk_hdptx_phy {
 	/* clk provider */
 	struct clk_hw hw;
 	bool pll_config_dirty;
-	bool restrict_rate_change;
 
 	atomic_t usage_count;
 
@@ -2074,7 +2073,6 @@ 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->restrict_rate_change = true;
 			hdptx->pll_config_dirty = true;
 
 			dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
@@ -2301,41 +2299,17 @@ static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
 	/*
-	 * Invalidate current clock rate to ensure rk_hdptx_phy_clk_set_rate()
-	 * will be invoked to commit PLL configuration.
+	 * For uncommitted PLL configuration, invalidate the current clock rate
+	 * to ensure rk_hdptx_phy_clk_set_rate() will be always invoked.
+	 * Otherwise, restrict the rate according to the PHY link setup.
 	 */
-	if (hdptx->pll_config_dirty) {
+	if (hdptx->pll_config_dirty)
 		req->rate = 0;
-		return 0;
-	}
-
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+	else if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
 		req->rate = hdptx->hdmi_cfg.rate;
-		return 0;
-	}
-
-	/*
-	 * FIXME: Temporarily allow altering TMDS char rate via CCF.
-	 * 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 && req->rate != hdptx->hdmi_cfg.rate) {
-		struct phy_configure_opts_hdmi hdmi = {
-			.tmds_char_rate = req->rate,
-		};
-
-		int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi, &hdptx->hdmi_cfg);
-
-		if (ret)
-			return ret;
-	}
-
-	/*
-	 * The TMDS char rate shall be adjusted via phy_configure() only,
-	 * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
-	 * a different rate argument.
-	 */
-	req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8, hdptx->hdmi_cfg.bpc);
+	else
+		req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8,
+						  hdptx->hdmi_cfg.bpc);
 
 	return 0;
 }

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:07 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:07 +0300
Subject: [PATCH v3 5/6] phy: rockchip: samsung-hdptx: Simplify GRF access
 with FIELD_PREP_WM16()
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-5-67b1b0c00e16@collabora.com>

The 16 most significant bits of the general-purpose register (GRF) are
used as a write-enable mask for the remaining 16 bits.

Make use of the recently introduced FIELD_PREP_WM16() macro to avoid
open-coding the bit shift operations and improve code readability.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 52 +++++++++++------------
 1 file changed, 25 insertions(+), 27 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 529dd2d5d9bd..5ed110e2adc7 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
- * Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2024-2026 Collabora Ltd.
  *
  * Author: Algea Cao <algea.cao at rock-chips.com>
  * Author: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/hw_bitfield.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -949,7 +950,9 @@ static void rk_hdptx_pre_power_up(struct rk_hdptx_phy *hdptx)
 	reset_control_assert(hdptx->rsts[RST_CMN].rstc);
 	reset_control_assert(hdptx->rsts[RST_INIT].rstc);
 
-	val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16;
+	val = (FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 }
 
@@ -960,8 +963,8 @@ static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx)
 
 	reset_control_deassert(hdptx->rsts[RST_LANE].rstc);
 
-	val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 |
-	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
+	val = (FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
 	/* 3 lanes FRL mode */
@@ -990,16 +993,15 @@ static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx)
 	u32 val;
 	int ret;
 
-	val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 |
-	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
+	val = (FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
 	usleep_range(10, 15);
 	reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
 
 	usleep_range(10, 15);
-	val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN;
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 1));
 
 	usleep_range(10, 15);
 	reset_control_deassert(hdptx->rsts[RST_CMN].rstc);
@@ -1037,7 +1039,9 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx)
 	reset_control_assert(hdptx->rsts[RST_CMN].rstc);
 	reset_control_assert(hdptx->rsts[RST_INIT].rstc);
 
-	val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16;
+	val = (FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 }
 
@@ -1135,7 +1139,7 @@ static int rk_hdptx_frl_lcpll_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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 0));
 
 	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);
@@ -1178,8 +1182,7 @@ static int rk_hdptx_frl_lcpll_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 1));
 
 	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);
@@ -1218,7 +1221,7 @@ 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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 0));
 
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq);
@@ -1336,11 +1339,9 @@ static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
 			   FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
 
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x0));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0));
+		     FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+		     FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+		     FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 }
 
 static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
@@ -1616,9 +1617,8 @@ static int rk_hdptx_dp_aux_init(struct rk_hdptx_phy *hdptx)
 			   FIELD_PREP(OVRD_SB_VREG_EN_MASK, 0x1));
 
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x1));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x1));
+		     FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1) |
+		     FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1));
 	usleep_range(20, 25);
 
 	reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
@@ -1665,7 +1665,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 
 	if (mode == PHY_MODE_DP) {
 		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x1));
+			     FIELD_PREP_WM16(HDPTX_MODE_SEL, 1));
 
 		for (lane = 0; lane < 4; lane++) {
 			regmap_update_bits(hdptx->regmap, LANE_REG(031e) + 0x400 * lane,
@@ -1693,7 +1693,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 
 		if (!ret) {
 			regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-				     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+				     FIELD_PREP_WM16(HDPTX_MODE_SEL, 0));
 
 			if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
 				ret = rk_hdptx_frl_lcpll_mode_config(hdptx);
@@ -1828,8 +1828,7 @@ static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx,
 	u32 bw, status;
 	int ret;
 
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0));
 
 	switch (dp->link_rate) {
 	case 1620:
@@ -1885,8 +1884,7 @@ static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx,
 	regmap_update_bits(hdptx->regmap, CMN_REG(0095), DP_TX_LINK_BW_MASK,
 			   FIELD_PREP(DP_TX_LINK_BW_MASK, bw));
 
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x1));
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 1));
 
 	ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS,
 				       status, FIELD_GET(HDPTX_O_PLL_LOCK_DONE, status),

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:31:08 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:31:08 +0300
Subject: [PATCH v3 6/6] phy: rockchip: samsung-hdptx: Consistently use
 bitfield macros
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <20260611-hdptx-clk-fixes-v3-6-67b1b0c00e16@collabora.com>

Make the code more robust and improve readability by using the available
bitfield macros (e.g. FIELD_PREP, FIELD_GET) whenever possible, instead
of open coding the related bit operations.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 24 ++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 5ed110e2adc7..a8a8cd176897 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -53,6 +53,12 @@
 /* CMN_REG(001e) */
 #define LCPLL_PI_EN_MASK		BIT(5)
 #define LCPLL_100M_CLK_EN_MASK		BIT(0)
+/* CMN_REG(0022) */
+#define ANA_LCPLL_PMS_PDIV_MASK		GENMASK(7, 4)
+#define ANA_LCPLL_PMS_REFDIV_MASK	GENMASK(3, 0)
+/* CMN_REG(0023) */
+#define LCPLL_PMS_SDIV_RBR_MASK		GENMASK(7, 4)
+#define LCPLL_PMS_SDIV_HBR_MASK		GENMASK(3, 0)
 /* CMN_REG(0025) */
 #define LCPLL_PMS_IQDIV_RSTN_MASK	BIT(4)
 /* CMN_REG(0028) */
@@ -1157,9 +1163,11 @@ static int rk_hdptx_frl_lcpll_cmn_config(struct rk_hdptx_phy *hdptx)
 	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);
+		     FIELD_PREP(ANA_LCPLL_PMS_PDIV_MASK, cfg->pms_pdiv) |
+		     FIELD_PREP(ANA_LCPLL_PMS_REFDIV_MASK, cfg->pms_refdiv));
 	regmap_write(hdptx->regmap, CMN_REG(0023),
-		     (cfg->pms_sdiv << 4) | cfg->pms_sdiv);
+		     FIELD_PREP(LCPLL_PMS_SDIV_RBR_MASK, cfg->pms_sdiv) |
+		     FIELD_PREP(LCPLL_PMS_SDIV_HBR_MASK, 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);
@@ -1229,8 +1237,10 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv);
 	regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc);
 	regmap_write(hdptx->regmap, CMN_REG(0059),
-		     (cfg->pms_pdiv << 4) | cfg->pms_refdiv);
-	regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4);
+		     FIELD_PREP(ANA_ROPLL_PMS_PDIV_MASK, cfg->pms_pdiv) |
+		     FIELD_PREP(ANA_ROPLL_PMS_REFDIV_MASK, cfg->pms_refdiv));
+	regmap_write(hdptx->regmap, CMN_REG(005a),
+		     FIELD_PREP(ROPLL_PMS_SDIV_RBR_MASK, cfg->pms_sdiv));
 
 	regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK,
 			   FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en));
@@ -2177,7 +2187,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 		ret = regmap_read(hdptx->regmap, CMN_REG(0023), &val);
 		if (ret)
 			return 0;
-		lcpll_hw.pms_sdiv = val & 0xf;
+		lcpll_hw.pms_sdiv = FIELD_GET(LCPLL_PMS_SDIV_HBR_MASK, val);
 
 		ret = regmap_read(hdptx->regmap, CMN_REG(002B), &val);
 		if (ret)
@@ -2197,7 +2207,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 		ret = regmap_read(hdptx->regmap, CMN_REG(002D), &val);
 		if (ret)
 			return 0;
-		lcpll_hw.sdc_n = (val & LCPLL_SDC_N_MASK) >> 1;
+		lcpll_hw.sdc_n = FIELD_GET(LCPLL_SDC_N_MASK, val);
 
 		for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
 			const struct lcpll_config *cfg = &rk_hdptx_frl_lcpll_cfg[i];
@@ -2258,7 +2268,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	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;
+	ropll_hw.pms_sdiv = FIELD_GET(PLL_PCG_POSTDIV_SEL_MASK, val) + 1;
 	bpc = (FIELD_GET(PLL_PCG_CLK_SEL_MASK, val) << 1) + 8;
 
 	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 05:34:27 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Thu, 11 Jun 2026 15:34:27 +0300
Subject: [PATCH v2 0/6] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
In-Reply-To: <aiqbX8kon8HtiSEl@vaman>
References: <20260511-hdptx-clk-fixes-v2-0-664e41379cab@collabora.com>
 <e0eeb794-11b9-4ba6-bee2-f6cc607d3a16@collabora.com>
 <ebcad67e-e14a-4d0e-b3e0-79ae1d146eaf@collabora.com> <aiqbX8kon8HtiSEl@vaman>
Message-ID: <38f0e334-bf28-4c8d-aa3c-e075c31a0c1e@collabora.com>

On 6/11/26 2:26 PM, Vinod Koul wrote:
> On 03-06-26, 13:27, Cristian Ciocaltea wrote:
>> On 5/20/26 10:05 PM, Cristian Ciocaltea wrote:
>>> Hi Vinod,
>>>
>>> On 5/11/26 9:21 PM, Cristian Ciocaltea wrote:
>>>> This series provides a set of bug fixes and cleanups for the Rockchip
>>>> Samsung HDPTX PHY driver.
>>>>
>>>> The first part of the series (i.e. PATCH 1 & 2) addresses clock rate
>>>> calculation and synchronization issues.  Specifically, it fixes edge
>>>> cases where the PHY PLL is pre-programmed by an external component (like
>>>> a bootloader) or when changing the color depth (bpc) while keeping the
>>>> modeline constant.  Because the Common Clock Framework .set_rate()
>>>> callback might not be invoked if the pixel clock remains unchanged, this
>>>> previously led to out-of-sync states between CCF and the actual HDMI PHY
>>>> configuration.
>>>>
>>>> The second part focuses on code cleanups and modernizing the register
>>>> access.  Now that dw_hdmi_qp driver has fully switched to using
>>>> phy_configure(), we can drop the deprecated TMDS rate setup workarounds
>>>> and the restrict_rate_change flag logic.  Finally, it refactors the
>>>> driver to consistently use standard bitfield macros.
>>>>
>>>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>>>> ---
>>>> Changes in v2:
>>>> - Collected Tested-by tags from Thomas and Simon
>>>> - Fixed a typo in commit description of patch 1
>>>> - Added a comment in patch 2 explaining why PLL config errors are
>>>>   ignored for rk_hdptx_phy_consumer_get()
>>>> - Added a missed FIELD_GET conversion for lcpll_hw.pms_sdiv in patch 6
>>>> - Rebased onto latest phy/fixes
>>>> - Link to v1: https://lore.kernel.org/r/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f at collabora.com
>>>
>>> In case you missed my comments from last week on the Sashiko AI review findings
>>> - in short, I don't think there is anything to worry about and the series should
>>> be fine to apply as-is.  Please let me know if you would still prefer a new
>>> revision.
>> Kind reminder..
> 
> Please post a new revision based on phy/next

Done (also addressed the confirmed Sashiko reported issues):

https://lore.kernel.org/all/20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16 at collabora.com/

Thanks,
Cristian


From macromorgan at hotmail.com  Thu Jun 11 07:28:55 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 09:28:55 -0500
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <aiplVZRI-0TCDnjL@ashevche-desk.local>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-4-macroalpha82@gmail.com>
 <aiplVZRI-0TCDnjL@ashevche-desk.local>
Message-ID: <PH0PR19MB9973380727A98C4B42F9A79D77A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Thu, Jun 11, 2026 at 10:35:49AM +0300, Andy Shevchenko wrote:
> On Wed, Jun 10, 2026 at 12:54:47PM -0500, Chris Morgan wrote:
> 
> > Add the core component of a new inv_icm42607 driver. This includes
> > a few setup functions and the full register definition in the
> > header file.
> 
> ...
> 
> >  2 files changed, 531 insertions(+)
> >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> 
> I'm not sure this is correct split by files. These files are not:
> - being build
> - being mentioned in MAINTAINERS

I can merge patches v3 and v4. Early on they were pretty big but now
that they've been paired down some I think it may be manageable.

Early on I was told to try and keep each patch around ~750 lines.
I can add these to together and get it to about ~850 lines, but
it will be compileable at that commit rather than waiting on a
second one.

> 
> ...
> 
> > +#ifndef INV_ICM42607_H_
> > +#define INV_ICM42607_H_
> > +
> > +#include <linux/bits.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/mutex.h>
> 
> mutex_types.h ?
> 

I'm not sure I understand this, can you elaborate why I'd need it?

> > +#include <linux/regmap.h>
> > +#include <linux/types.h>
> 
> Do you need forward declaration for regulator data type?
> 

I think earlier I had regulator-consumer and stripped it out, but I
might have cut a bit too deep so I can add that back.

> ...
> 
> > +#define INV_ICM42607_POWER_UP_TIME_US			100000
> 
> 100 * USEC_PER_MSEC (will require time.h)?
> 

Understood.

> ...
> 
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> 
> + bitfields.h
> 

Understood.

> > +#include <linux/delay.h>
> > +#include <linux/dev_printk.h>
> 
> + device/devres.h
> + err.h
> 

Understood.

> > +#include <linux/iio/iio.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/time.h>
> 
> Also check if you need types.h.
> 

I'll add it, I'm honestly not sure. I never got iwyu working it seems.

> ...
> 
> > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > +
> > +	/*
> > +	 * No polling interval specified in datasheet, so use reset time as
> > +	 * polling interval and 10x reset time as timeout period.
> > +	 */
> > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> 
> Besides too many parentheses, this can be switched to regular patter of "num * what".
> Also, TBH, the plain values would be better here

I'll switch to plain numbers and let the comment above do the explaining.

> 
> 	fsleep(1 * USEC_PER_MSEC);
> 
> 	/*
> 	 * No polling interval specified in datasheet, so use reset time as
> 	 * polling interval and 10x reset time as timeout period.
> 	 */
> 	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> 				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> 				       1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
> 
> And in the similar way in other fsleep() / _read_poll_timeout() cases.
> 

Plain numbers, gotcha.

> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "reset error, reset done bit not set\n");
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you,
Chris


From macromorgan at hotmail.com  Thu Jun 11 07:32:38 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 09:32:38 -0500
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260611120943.7119975b@jic23-huawei>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-4-macroalpha82@gmail.com>
 <20260611120943.7119975b@jic23-huawei>
Message-ID: <PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Thu, Jun 11, 2026 at 12:09:43PM +0100, Jonathan Cameron wrote:
> On Wed, 10 Jun 2026 12:54:47 -0500
> Chris Morgan <macroalpha82 at gmail.com> wrote:
> 
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Add the core component of a new inv_icm42607 driver. This includes
> > a few setup functions and the full register definition in the
> > header file.
> > 
> > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> Hi Chris,
> 
> A couple more minor things from a fresh read.
> 
> Thanks
> 
> Jonathan
> 
> > ---
> >  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
> >  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
> >  2 files changed, 531 insertions(+)
> >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > new file mode 100644
> > index 000000000000..716fc0f1c3fd
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > new file mode 100644
> > index 000000000000..334264120b42
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> 
> > +
> > +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> > +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> > +{
> > +	const struct device *dev = regmap_get_device(st->map);
> > +	unsigned int val;
> > +	int ret;
> > +
> > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	/* Warn, but don't fail. */
> > +	if (val != st->hw->whoami)
> > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > +			 val, st->hw->whoami, st->hw->name);
> > +
> > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > +	if (ret)
> > +		return ret;
> > +
> > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > +
> > +	/*
> > +	 * No polling interval specified in datasheet, so use reset time as
> > +	 * polling interval and 10x reset time as timeout period.
> > +	 */
> > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> > +	if (ret)
> > +		return dev_err_probe(dev, ret,
> > +				     "reset error, reset done bit not set\n");
> > +
> > +	/* Sync the regcache again after a reset. */
> > +	regcache_mark_dirty(st->map);
> > +	ret = regcache_sync(st->map);
> 
> Sashiko raised the point that you don't have a writeable register list for the regmap
> and so potentially we at very least write a bunch of stuff that isn't needed.
> I doubt it's actually a problem or you would have seen it, but nice little optimization
> to reduce what is written.

I will add such a list, I'd put it in patch 4 unless you think I should
merge patch 3 and 4 to make the driver compileable at the first commit
of code (will push the number of lines to the ~850/900 range though).

> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = inv_icm42607_bus_setup(st);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
> > +			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
> > +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
> > +				 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
> 
> That should have a FIELD_PREP() to save us having to got check that
> the MASK includes the LSB.  

Okay.

> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	return inv_icm42607_set_conf(st, st->hw->conf);
> > +}
> 
> > +
> > +MODULE_AUTHOR("InvenSense, Inc.");
> > +MODULE_DESCRIPTION("InvenSense ICM-42607x device driver");
> 
> Why does it have a trailing x?  Whilst a wild card is less harmful
> here than in many places I'd still drop it.

I think I missed it from the very beginning. I'll drop.

> 
> > +MODULE_LICENSE("GPL");
> > +MODULE_IMPORT_NS("IIO_INV_SENSORS_TIMESTAMP");
> 
> Do we need this yet?  I think it only gets used later, in which case
> move it to the first patch that needs this.
> 
> 

No, we don't need it at all anymore. I think I can safely drop this now
that I'm no longer calling that code. Was a vestige from the buffers
code.

Thank you,
Chris


From macromorgan at hotmail.com  Thu Jun 11 07:36:08 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 09:36:08 -0500
Subject: [PATCH V11 0/9] Add Invensense ICM42607
In-Reply-To: <20260611115938.27712b66@jic23-huawei>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260611115938.27712b66@jic23-huawei>
Message-ID: <PH0PR19MB99733845CDEFA1D8441200B60FA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Thu, Jun 11, 2026 at 11:59:38AM +0100, Jonathan Cameron wrote:
> On Wed, 10 Jun 2026 12:54:44 -0500
> Chris Morgan <macroalpha82 at gmail.com> wrote:
> 
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Add support for the ICM42607 IMU. This sensor shares the same
> > functionality but a different register layout with the existing
> > ICM42600.
> > 
> > This driver should work with the ICM42607 and ICM42607P over both I2C
> > and SPI, however only the ICM42607P over I2C could be tested.
> Hi Chris,
> 
> Just a quick reminder to check if there is useful feedback at:
> https://sashiko.dev/#/patchset/20260610175455.19006-1-macroalpha82%40gmail.com
> 
> I didn't look into most of the but the last one about no avail mask bits
> being set for gyro channels was easy to verify as correct and suggests
> a testing gap.
> 
> Jonathan
> 

Thanks, I've been checking sashiko on every patch and trying to address
what it says to the best of my ability. Honestly I wish there was a way
to simply push to that bot first and *then* push to the mailing list
once I've resolved all of its comments.

Thank you,
Chris


From mripard at kernel.org  Thu Jun 11 08:19:34 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Thu, 11 Jun 2026 15:19:34 +0000
Subject: [PATCH v7 03/30] drm/display: scdc_helper: Add macro for
 connector-prefixed debug messages
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-3-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-3-445eb54ee1ed@collabora.com>
Message-ID: <404cdc5ee5da868c0f0cb17d19dcebd8@kernel.org>

On Tue, 2 Jun 2026 01:44:03 +0300, Cristian Ciocaltea wrote:
> Introduce the drm_scdc_dbg() wrapper over drm_dbg_kms() to help getting
> rid of the boilerplate around prefixing the debug messages with the
> connector information.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> [ ... ]

Acked-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From mripard at kernel.org  Thu Jun 11 08:25:45 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Thu, 11 Jun 2026 17:25:45 +0200
Subject: [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware
 hotplug helper for SCDC sync
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-5-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-5-445eb54ee1ed@collabora.com>
Message-ID: <20260611-refined-idealistic-sunfish-3df3a4@houat>

On Tue, Jun 02, 2026 at 01:44:05AM +0300, Cristian Ciocaltea wrote:
> Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
> drm_atomic_helper_connector_hdmi_hotplug() that accepts a
> drm_modeset_acquire_ctx.
> 
> This enables SCDC status synchronization on hotplug events, which
> requires lock acquisition context for performing the CRTC reset
> triggered by drm_scdc_sync_status().
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
>  drivers/gpu/drm/display/drm_hdmi_state_helper.c | 40 ++++++++++++++++++++-----
>  include/drm/display/drm_hdmi_state_helper.h     |  4 +++
>  2 files changed, 37 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> index a331ebdd65af..a96d81cbf94f 100644
> --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c
> @@ -12,6 +12,7 @@
>  #include <drm/display/drm_hdmi_cec_helper.h>
>  #include <drm/display/drm_hdmi_helper.h>
>  #include <drm/display/drm_hdmi_state_helper.h>
> +#include <drm/display/drm_scdc_helper.h>
>  
>  /**
>   * DOC: hdmi helpers
> @@ -1150,18 +1151,20 @@ drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *con
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
>  
> -static void
> +static int
>  drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
> -					enum drm_connector_status status)
> +					enum drm_connector_status status,
> +					struct drm_modeset_acquire_ctx *ctx)
>  {
>  	const struct drm_edid *drm_edid;
> +	int ret = 0;
>  
>  	if (status == connector_status_disconnected) {
> -		// TODO: also handle scramber, HDMI sink disconnected.
> +		ret = drm_scdc_sync_status(connector, false, ctx);
>  		drm_connector_hdmi_audio_plugged_notify(connector, false);
>  		drm_edid_connector_update(connector, NULL);
>  		drm_connector_cec_phys_addr_invalidate(connector);
> -		return;
> +		return ret;
>  	}
>  
>  	if (connector->hdmi.funcs->read_edid)
> @@ -1174,10 +1177,12 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
>  	drm_edid_free(drm_edid);
>  
>  	if (status == connector_status_connected) {
> -		// TODO: also handle scramber, HDMI sink is now connected.
> +		ret = drm_scdc_sync_status(connector, true, ctx);
>  		drm_connector_hdmi_audio_plugged_notify(connector, true);
>  		drm_connector_cec_phys_addr_set(connector);
>  	}
> +
> +	return ret;
>  }
>  
>  /**
> @@ -1191,10 +1196,31 @@ drm_atomic_helper_connector_hdmi_update(struct drm_connector *connector,
>  void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
>  					      enum drm_connector_status status)
>  {
> -	drm_atomic_helper_connector_hdmi_update(connector, status);
> +	drm_atomic_helper_connector_hdmi_update(connector, status, NULL);
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
>  
> +/**
> + * drm_atomic_helper_connector_hdmi_hotplug_ctx - Handle the hotplug event for the HDMI connector
> + * @connector: A pointer to the HDMI connector
> + * @status: Connection status
> + * @ctx: Lock acquisition context to be used for resetting CRTC
> + *
> + * This function should be called as a part of the .detect() / .detect_ctx()
> + * callbacks for all status changes.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + * If @ctx is set, it might also return -EDEADLK.
> + */
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> +						 enum drm_connector_status status,
> +						 struct drm_modeset_acquire_ctx *ctx)
> +{
> +	return drm_atomic_helper_connector_hdmi_update(connector, status, ctx);
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug_ctx);
> +
>  /**
>   * drm_atomic_helper_connector_hdmi_force - HDMI Connector implementation of the force callback
>   * @connector: A pointer to the HDMI connector
> @@ -1206,6 +1232,6 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_hotplug);
>   */
>  void drm_atomic_helper_connector_hdmi_force(struct drm_connector *connector)
>  {
> -	drm_atomic_helper_connector_hdmi_update(connector, connector->status);
> +	drm_atomic_helper_connector_hdmi_update(connector, connector->status, NULL);
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_force);
> diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
> index 13375bd0f4ae..75fedd4a3ba8 100644
> --- a/include/drm/display/drm_hdmi_state_helper.h
> +++ b/include/drm/display/drm_hdmi_state_helper.h
> @@ -7,6 +7,7 @@ struct drm_atomic_commit;
>  struct drm_connector;
>  struct drm_connector_state;
>  struct drm_display_mode;
> +struct drm_modeset_acquire_ctx;
>  struct hdmi_audio_infoframe;
>  
>  enum drm_connector_status;
> @@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
>  						       struct drm_atomic_commit *state);
>  void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
>  					      enum drm_connector_status status);
> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
> +						 enum drm_connector_status status,
> +						 struct drm_modeset_acquire_ctx *ctx);

There's not a lot of users, so I'd prefer if we were just changing the
prototype of drm_atomic_helper_connector_hdmi_hotplug()

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-rockchip/attachments/20260611/4fdd22c0/attachment.sig>

From mripard at kernel.org  Thu Jun 11 08:32:27 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Thu, 11 Jun 2026 15:32:27 +0000
Subject: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate
 constants
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-24-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-24-445eb54ee1ed@collabora.com>
Message-ID: <e6d0f078ffe3425dfbcd36a42ba9053a@kernel.org>

On Tue, 2 Jun 2026 01:44:24 +0300, Cristian Ciocaltea wrote:
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h.  Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
> 
> 
> [ ... ]

Acked-by: Maxime Ripard <mripard at kernel.org>

Thanks!
Maxime


From vkoul at kernel.org  Thu Jun 11 08:35:55 2026
From: vkoul at kernel.org (Vinod Koul)
Date: Thu, 11 Jun 2026 21:05:55 +0530
Subject: [PATCH] phy: rockchip: inno-usb2: Add missing clkout_ctl_phy
 kerneldoc
In-Reply-To: <20260520102859.1357411-1-heiko@sntech.de>
References: <20260520102859.1357411-1-heiko@sntech.de>
Message-ID: <178119215503.568088.10282212626375144435.b4-ty@kernel.org>


On Wed, 20 May 2026 12:28:59 +0200, Heiko Stuebner wrote:
> Add the missing documentation for the newly added clkout_ctl_phy field.
> 
> 

Applied, thanks!

[1/1] phy: rockchip: inno-usb2: Add missing clkout_ctl_phy kerneldoc
      commit: 2ace2e949979b82f82f12dd76d7c5a6145246ca3

Best regards,
-- 
~Vinod




From jic23 at kernel.org  Thu Jun 11 09:18:24 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 17:18:24 +0100
Subject: [PATCH V11 0/9] Add Invensense ICM42607
In-Reply-To: <PH0PR19MB99733845CDEFA1D8441200B60FA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260611115938.27712b66@jic23-huawei>
	<PH0PR19MB99733845CDEFA1D8441200B60FA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260611171824.0f932f3f@jic23-huawei>

On Thu, 11 Jun 2026 09:36:08 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Thu, Jun 11, 2026 at 11:59:38AM +0100, Jonathan Cameron wrote:
> > On Wed, 10 Jun 2026 12:54:44 -0500
> > Chris Morgan <macroalpha82 at gmail.com> wrote:
> >   
> > > From: Chris Morgan <macromorgan at hotmail.com>
> > > 
> > > Add support for the ICM42607 IMU. This sensor shares the same
> > > functionality but a different register layout with the existing
> > > ICM42600.
> > > 
> > > This driver should work with the ICM42607 and ICM42607P over both I2C
> > > and SPI, however only the ICM42607P over I2C could be tested.  
> > Hi Chris,
> > 
> > Just a quick reminder to check if there is useful feedback at:
> > https://sashiko.dev/#/patchset/20260610175455.19006-1-macroalpha82%40gmail.com
> > 
> > I didn't look into most of the but the last one about no avail mask bits
> > being set for gyro channels was easy to verify as correct and suggests
> > a testing gap.
> > 
> > Jonathan
> >   
> 
> Thanks, I've been checking sashiko on every patch and trying to address
> what it says to the best of my ability. Honestly I wish there was a way
> to simply push to that bot first and *then* push to the mailing list
> once I've resolved all of its comments.

Agreed - that would be helpful.  I believe it is possible to run locally
against a bunch of LLMs - I recall seeing something saying there
is a git repo with scripts. No idea if that is possible with a free level though.

Jonathan

> 
> Thank you,
> Chris



From jic23 at kernel.org  Thu Jun 11 09:20:22 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Thu, 11 Jun 2026 17:20:22 +0100
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-4-macroalpha82@gmail.com>
	<20260611120943.7119975b@jic23-huawei>
	<PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260611172022.4d138820@jic23-huawei>

On Thu, 11 Jun 2026 09:32:38 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Thu, Jun 11, 2026 at 12:09:43PM +0100, Jonathan Cameron wrote:
> > On Wed, 10 Jun 2026 12:54:47 -0500
> > Chris Morgan <macroalpha82 at gmail.com> wrote:
> >   
> > > From: Chris Morgan <macromorgan at hotmail.com>
> > > 
> > > Add the core component of a new inv_icm42607 driver. This includes
> > > a few setup functions and the full register definition in the
> > > header file.
> > > 
> > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>  
> > Hi Chris,
> > 
> > A couple more minor things from a fresh read.
> > 
> > Thanks
> > 
> > Jonathan
> >   
> > > ---
> > >  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
> > >  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
> > >  2 files changed, 531 insertions(+)
> > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > 
> > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > new file mode 100644
> > > index 000000000000..716fc0f1c3fd
> > > --- /dev/null
> > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h  
> >   
> > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > new file mode 100644
> > > index 000000000000..334264120b42
> > > --- /dev/null
> > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c  
> >   
> > > +
> > > +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> > > +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> > > +{
> > > +	const struct device *dev = regmap_get_device(st->map);
> > > +	unsigned int val;
> > > +	int ret;
> > > +
> > > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	/* Warn, but don't fail. */
> > > +	if (val != st->hw->whoami)
> > > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > > +			 val, st->hw->whoami, st->hw->name);
> > > +
> > > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > > +
> > > +	/*
> > > +	 * No polling interval specified in datasheet, so use reset time as
> > > +	 * polling interval and 10x reset time as timeout period.
> > > +	 */
> > > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> > > +	if (ret)
> > > +		return dev_err_probe(dev, ret,
> > > +				     "reset error, reset done bit not set\n");
> > > +
> > > +	/* Sync the regcache again after a reset. */
> > > +	regcache_mark_dirty(st->map);
> > > +	ret = regcache_sync(st->map);  
> > 
> > Sashiko raised the point that you don't have a writeable register list for the regmap
> > and so potentially we at very least write a bunch of stuff that isn't needed.
> > I doubt it's actually a problem or you would have seen it, but nice little optimization
> > to reduce what is written.  
> 
> I will add such a list, I'd put it in patch 4 unless you think I should
> merge patch 3 and 4 to make the driver compileable at the first commit
> of code (will push the number of lines to the ~850/900 range though).
> 
I'm fine with them split but don't mind if Andy prefers them combined.
His comment on adding a COMPILE_TEST option would allow that to be
built, but it is a bit odd to do it just for that purpose.

Jonathan



From macromorgan at hotmail.com  Thu Jun 11 09:31:09 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 11:31:09 -0500
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260611172022.4d138820@jic23-huawei>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-4-macroalpha82@gmail.com>
 <20260611120943.7119975b@jic23-huawei>
 <PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
 <20260611172022.4d138820@jic23-huawei>
Message-ID: <PH0PR19MB997338CE11110E16E7FB668E3BA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Thu, Jun 11, 2026 at 05:20:22PM +0100, Jonathan Cameron wrote:
> On Thu, 11 Jun 2026 09:32:38 -0500
> Chris Morgan <macromorgan at hotmail.com> wrote:
> 
> > On Thu, Jun 11, 2026 at 12:09:43PM +0100, Jonathan Cameron wrote:
> > > On Wed, 10 Jun 2026 12:54:47 -0500
> > > Chris Morgan <macroalpha82 at gmail.com> wrote:
> > >   
> > > > From: Chris Morgan <macromorgan at hotmail.com>
> > > > 
> > > > Add the core component of a new inv_icm42607 driver. This includes
> > > > a few setup functions and the full register definition in the
> > > > header file.
> > > > 
> > > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>  
> > > Hi Chris,
> > > 
> > > A couple more minor things from a fresh read.
> > > 
> > > Thanks
> > > 
> > > Jonathan
> > >   
> > > > ---
> > > >  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
> > > >  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
> > > >  2 files changed, 531 insertions(+)
> > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > 
> > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > > new file mode 100644
> > > > index 000000000000..716fc0f1c3fd
> > > > --- /dev/null
> > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h  
> > >   
> > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > new file mode 100644
> > > > index 000000000000..334264120b42
> > > > --- /dev/null
> > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c  
> > >   
> > > > +
> > > > +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> > > > +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> > > > +{
> > > > +	const struct device *dev = regmap_get_device(st->map);
> > > > +	unsigned int val;
> > > > +	int ret;
> > > > +
> > > > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	/* Warn, but don't fail. */
> > > > +	if (val != st->hw->whoami)
> > > > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > > > +			 val, st->hw->whoami, st->hw->name);
> > > > +
> > > > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > > > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > > > +
> > > > +	/*
> > > > +	 * No polling interval specified in datasheet, so use reset time as
> > > > +	 * polling interval and 10x reset time as timeout period.
> > > > +	 */
> > > > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > > > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> > > > +	if (ret)
> > > > +		return dev_err_probe(dev, ret,
> > > > +				     "reset error, reset done bit not set\n");
> > > > +
> > > > +	/* Sync the regcache again after a reset. */
> > > > +	regcache_mark_dirty(st->map);
> > > > +	ret = regcache_sync(st->map);  
> > > 
> > > Sashiko raised the point that you don't have a writeable register list for the regmap
> > > and so potentially we at very least write a bunch of stuff that isn't needed.
> > > I doubt it's actually a problem or you would have seen it, but nice little optimization
> > > to reduce what is written.  
> > 
> > I will add such a list, I'd put it in patch 4 unless you think I should
> > merge patch 3 and 4 to make the driver compileable at the first commit
> > of code (will push the number of lines to the ~850/900 range though).
> > 
> I'm fine with them split but don't mind if Andy prefers them combined.
> His comment on adding a COMPILE_TEST option would allow that to be
> built, but it is a bit odd to do it just for that purpose.
> 
> Jonathan
> 

I'm going to add the i2c stuff to this series, and then do the SPI
on the next patch. That should add only a little bit to this one but
still ensure the very first (code) commit has something to compile.
I'm going to avoid doing COMPILE_TEST unless collectively you all
think I should.

I'm still racing to try and get this one done before the merge
window opens up, but I'm pretty sure it's already too late at
this point. I'll refrain from submitting updates once the window opens
though.

Thank you,
Chris


From robh at kernel.org  Thu Jun 11 09:31:35 2026
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Jun 2026 11:31:35 -0500
Subject: [PATCH v3 2/3] dt-bindings: mfd: syscon: Drop custom select for
 older dtschema
In-Reply-To: <20260609-vertical-antarctic-e18a7ec91685@spud>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
 <20260608-n-dt-bindings-simple-bus-syscon-v3-2-4eba9ec1212a@oss.qualcomm.com>
 <20260609-vertical-antarctic-e18a7ec91685@spud>
Message-ID: <20260611163135.GA2913196-robh@kernel.org>

On Tue, Jun 09, 2026 at 05:28:21PM +0100, Conor Dooley wrote:
> On Mon, Jun 08, 2026 at 10:44:25PM +0200, Krzysztof Kozlowski wrote:
> > Older dtschema <2024.02 required custom select to avoid applying this
> > binding to anything having "syscon" compatible.  That's not the case
> > anymore and this additional select has two headaches:
> > 
> > 1. Duplicates all the compatibles listed in the schema.
> > 
> > 2. Is error-prone, because it requires contributor to add the compatible
> >    in two places, otherwise the schema will be silently ignored.
> >    The select list already misses mentioning compatibles:
> >    mediatek,mt8365-infracfg-nao and renesas,r9a08g046-lvds-cmn (with the
> >    latter being reverted for different reasons).
> > 
> > This requires bumping minimum dtschema requirement to v2024.04, which
> > feels old enough to be a safe requirement.
> 
> I agree, seems reasonable enough given it's a jump from 2023.09 and not
> some large jump.
> The diff is nice too!
> I assume Rob will be taking it, but just in case..
> Acked-by: Conor Dooley <conor.dooley at microchip.com>

I expect Lee to take this. I suspect syscon.yaml has other conflicting 
changes.

Rob


From robh at kernel.org  Thu Jun 11 09:36:13 2026
From: robh at kernel.org (Rob Herring)
Date: Thu, 11 Jun 2026 11:36:13 -0500
Subject: [PATCH V7 1/6] dt-bindings: power: supply: sgm41542: document
 sgm41542
In-Reply-To: <20260610144407.438846-2-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
 <20260610144407.438846-2-macroalpha82@gmail.com>
Message-ID: <20260611163613.GA2922314-robh@kernel.org>

On Wed, Jun 10, 2026 at 09:44:02AM -0500, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Document the SG Micro sgm41542 battery charger/boost converter.
> The parameters of input-current-limit-microamp and
> input-voltage-limit-microvolt are defined as such since they are in
> common use among multiple bindings currently.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>

Missing Conor's reviewed-by.
> ---
>  .../power/supply/sgmicro,sgm41542.yaml        | 96 +++++++++++++++++++
>  1 file changed, 96 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml


From macromorgan at hotmail.com  Thu Jun 11 09:47:01 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 11:47:01 -0500
Subject: [PATCH V7 1/6] dt-bindings: power: supply: sgm41542: document
 sgm41542
In-Reply-To: <20260611163613.GA2922314-robh@kernel.org>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
 <20260610144407.438846-2-macroalpha82@gmail.com>
 <20260611163613.GA2922314-robh@kernel.org>
Message-ID: <PH0PR19MB997338544F64D0799C799908E6A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>

On Thu, Jun 11, 2026 at 11:36:13AM -0500, Rob Herring wrote:
> On Wed, Jun 10, 2026 at 09:44:02AM -0500, Chris Morgan wrote:
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Document the SG Micro sgm41542 battery charger/boost converter.
> > The parameters of input-current-limit-microamp and
> > input-voltage-limit-microvolt are defined as such since they are in
> > common use among multiple bindings currently.
> > 
> > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> 
> Missing Conor's reviewed-by.
> > ---
> >  .../power/supply/sgmicro,sgm41542.yaml        | 96 +++++++++++++++++++
> >  1 file changed, 96 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/power/supply/sgmicro,sgm41542.yaml

I'm sorry, somehow I accidentally dropped it. If I need a V8 I'll be
sure to include it, unless you want me to submit a V8 to add it?

Thank you,
Chris


From dave.stevenson at raspberrypi.com  Thu Jun 11 10:14:11 2026
From: dave.stevenson at raspberrypi.com (Dave Stevenson)
Date: Thu, 11 Jun 2026 18:14:11 +0100
Subject: [PATCH v7 24/30] drm/vc4: hdmi: Use common TMDS char rate constants
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-24-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com> <20260602-dw-hdmi-qp-scramb-v7-24-445eb54ee1ed@collabora.com>
Message-ID: <CAPY8ntDw9CSZgMzdDenHdv8ZN8Ho5JAhu1h8FXUiqLfxcVCWLQ@mail.gmail.com>

On Mon, 1 Jun 2026 at 23:45, Cristian Ciocaltea
<cristian.ciocaltea at collabora.com> wrote:
>
> Replace HDMI_14_MAX_TMDS_CLK defined locally with
> HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h.  Note this
> incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
> rate was actually introduced in HDMI 1.3.
>
> Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
> magic number.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

Reviewed-by: Dave Stevenson <dave.stevenson at raspberrypi.com>

> ---


From geraldogabriel at gmail.com  Thu Jun 11 13:02:42 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Thu, 11 Jun 2026 17:02:42 -0300
Subject: [PATCH v6 0/3] PCI: rockchip: 5.0 GT/s speed discouraged by Rockchip
Message-ID: <cover.1781207474.git.geraldogabriel@gmail.com>

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, including data loss.

Drop all code related to 5.0 GT/s operational speed from this driver.

Endpoint Mode driver was not tested.

---
Changes in v6:
- Squashed patches 3 & 4 together as suggested by Mani
- More formal warning message as suggested by Dragan
- Set the 2.5 GT/s bit regardless of if link-speed is set to 2
- Link to v5: https://lore.kernel.org/all/cover.1772239598.git.geraldogabriel at gmail.com/T/

Changes in v5:
- Changed commit order to not break builds and adjusted copy pasted
  commit message. (thanks Charalampos!)
- Reintroduced behavior to force 2.5 GT/s in case there's something
  non-default in the DT. (thanks Dragan!)
- Link to v4: https://lore.kernel.org/linux-rockchip/cover.1772169998.git.geraldogabriel at gmail.com/T/

Changes in v4:
- Incorporate suggestion by Bjorn and refined by Dragan to drop the
  "catastrophic" code
- Link to v3: https://lore.kernel.org/linux-rockchip/cover.1772057799.git.geraldogabriel at gmail.com/T/

Changes in v3:
- Clarify warning message even though Rockchip won't disclose details
- Drop DT changes as they were applied as subset by Heiko
- Link to v2: https://lore.kernel.org/all/cover.1763415705.git.geraldogabriel at gmail.com/T/

Changes in v2:
- hard limit to 2.5 GT/s, not just warn
- add Reported-by: and Reviewed-by: Dragan Simic
- remove redundant declaration of max-link-speed from helios64 dts
- fix Link: of helios64 patch
- simplify RC mode comment
- Link to v1: https://lore.kernel.org/all/aRhR79u5BPtRRFw3 at geday/T/

---

Geraldo Nascimento (3):
  PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
  PCI: rockchip-host: do not attempt 5.0 GT/s retraining
  PCI: rockchip: drive at 2.5 GT/s, error other speeds

 drivers/pci/controller/pcie-rockchip-ep.c   | 13 -------------
 drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
 drivers/pci/controller/pcie-rockchip.c      | 16 +++++++++-------
 drivers/pci/controller/pcie-rockchip.h      |  3 ---
 4 files changed, 9 insertions(+), 43 deletions(-)

-- 
2.54.0



From geraldogabriel at gmail.com  Thu Jun 11 13:03:11 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Thu, 11 Jun 2026 17:03:11 -0300
Subject: [PATCH v6 1/3] PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
In-Reply-To: <cover.1781207474.git.geraldogabriel@gmail.com>
References: <cover.1781207474.git.geraldogabriel@gmail.com>
Message-ID: <76c828d29b0f05df0970b3a862ee1af8c96faf17.1781207474.git.geraldogabriel@gmail.com>

Drop the 5.0 GT/s Link Speed retraining code block from Rockchip PCIe
EP driver. The reason is that Shawn Lin from Rockchip has reiterated
that there may be danger of "catastrophic failure" in using their PCIe
with 5.0 GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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

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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip-ep.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index 799461335762e..9ebc227a1ef84 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -553,19 +553,6 @@ static void rockchip_pcie_ep_link_training(struct work_struct *work)
 	if (ret)
 		goto again;
 
-	/*
-	 * Check the current speed: if gen2 speed was requested and we are not
-	 * at gen2 speed yet, retrain again for gen2.
-	 */
-	val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
-	if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) {
-		/* Enable retrain for gen2 */
-		rockchip_pcie_ep_retrain_link(rockchip);
-		readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
-				   val, PCIE_LINK_IS_GEN2(val), 50,
-				   LINK_TRAIN_TIMEOUT);
-	}
-
 	/* Check again that the link is up */
 	if (!rockchip_pcie_ep_link_up(rockchip))
 		goto again;
-- 
2.54.0



From geraldogabriel at gmail.com  Thu Jun 11 13:03:46 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Thu, 11 Jun 2026 17:03:46 -0300
Subject: [PATCH v6 2/3] PCI: rockchip-host: do not attempt 5.0 GT/s retraining
In-Reply-To: <cover.1781207474.git.geraldogabriel@gmail.com>
References: <cover.1781207474.git.geraldogabriel@gmail.com>
Message-ID: <fa9ed4fc6d4531a9216473151ddaebdb70398c20.1781207474.git.geraldogabriel@gmail.com>

Drop the 5.0 GT/s Link Speed retraining from Rockchip PCIe Root
Complex Mode Operation, so called host driver.

The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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

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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
 1 file changed, 20 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index ee1822ca01db3..1374a2c92b563 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -328,26 +328,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
 		goto err_power_off_phy;
 	}
 
-	if (rockchip->link_gen == 2) {
-		/*
-		 * Enable retrain for gen2. This should be configured only after
-		 * gen1 finished.
-		 */
-		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
-		status &= ~PCI_EXP_LNKCTL2_TLS;
-		status |= PCI_EXP_LNKCTL2_TLS_5_0GT;
-		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
-		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
-		status |= PCI_EXP_LNKCTL_RL;
-		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
-
-		err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
-					 status, PCIE_LINK_IS_GEN2(status), 20,
-					 500 * USEC_PER_MSEC);
-		if (err)
-			dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
-	}
-
 	/* Check the final link width from negotiated lane counter from MGMT */
 	status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
 	status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
-- 
2.54.0



From geraldogabriel at gmail.com  Thu Jun 11 13:04:22 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Thu, 11 Jun 2026 17:04:22 -0300
Subject: [PATCH v6 3/3] PCI: rockchip: drive at 2.5 GT/s, error other speeds
In-Reply-To: <cover.1781207474.git.geraldogabriel@gmail.com>
References: <cover.1781207474.git.geraldogabriel@gmail.com>
Message-ID: <4ac5cd7d2271df375ed6307f5c394247721395d9.1781207474.git.geraldogabriel@gmail.com>

Configure the core to be driven at 2.5 GT/s Link Speed and ignore
any other speed with a warning. Also drop the 5.0 GT/s Link Speed
defines from Rockchip PCIe header.

The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0 GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip.c | 16 +++++++++-------
 drivers/pci/controller/pcie-rockchip.h |  3 ---
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
index 0f88da3788054..5a2876d7c8547 100644
--- a/drivers/pci/controller/pcie-rockchip.c
+++ b/drivers/pci/controller/pcie-rockchip.c
@@ -66,8 +66,10 @@ 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, limited 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];
@@ -147,12 +149,12 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
 		goto err_exit_phy;
 	}
 
+	/* 5.0 GT/s may cause catastrophic failure for this core */
 	if (rockchip->link_gen == 2)
-		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
-				    PCIE_CLIENT_CONFIG);
-	else
-		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
-				    PCIE_CLIENT_CONFIG);
+		dev_warn(dev, "5.0 GT/s may cause data loss or worse\n");
+
+	rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
+			    PCIE_CLIENT_CONFIG);
 
 	regs = PCIE_CLIENT_ARI_ENABLE |
 	       PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
index 3e82a69b9c006..b5da15601b585 100644
--- a/drivers/pci/controller/pcie-rockchip.h
+++ b/drivers/pci/controller/pcie-rockchip.h
@@ -42,7 +42,6 @@
 #define   PCIE_CLIENT_MODE_RC			HWORD_SET_BIT(0x0040)
 #define   PCIE_CLIENT_MODE_EP			HWORD_CLR_BIT(0x0040)
 #define   PCIE_CLIENT_GEN_SEL_1			HWORD_CLR_BIT(0x0080)
-#define   PCIE_CLIENT_GEN_SEL_2			HWORD_SET_BIT(0x0080)
 #define PCIE_CLIENT_LEGACY_INT_CTRL	(PCIE_CLIENT_BASE + 0x0c)
 #define   PCIE_CLIENT_INT_IN_ASSERT		HWORD_SET_BIT(0x0002)
 #define   PCIE_CLIENT_INT_IN_DEASSERT		HWORD_CLR_BIT(0x0002)
@@ -197,8 +196,6 @@
 	(((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY)
 #define PCIE_LINK_UP(x) \
 	(((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP)
-#define PCIE_LINK_IS_GEN2(x) \
-	(((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G)
 
 #define RC_REGION_0_ADDR_TRANS_H		0x00000000
 #define RC_REGION_0_ADDR_TRANS_L		0x00000000
-- 
2.54.0



From macroalpha82 at gmail.com  Thu Jun 11 13:25:58 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:25:58 -0500
Subject: [PATCH V12 1/9] dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add mount-matrix attribute to schema. This attribute has been supported
since the first revision of this driver, but was not documented.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/iio/imu/invensense,icm42600.yaml        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd..9b2af104f186 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -53,6 +53,8 @@ properties:
   drive-open-drain:
     type: boolean
 
+  mount-matrix: true
+
   vdd-supply:
     description: Regulator that provides power to the sensor
 
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:25:57 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:25:57 -0500
Subject: [PATCH V12 0/9] Add Invensense ICM42607
Message-ID: <20260611202607.85376-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.

This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.

Changes Since V1:
 - Instead of creating a new driver, merged with the existing inv_icm42600
   driver. This necessitated adding some code to the existing driver to
   permit using a different register layout for the same functionality.
 - Split changes up a bit more to decrease the size of the individual
   patches. Note that patch 0004 is still pretty hefty; if I need to split
   further I may need to create some temporary stub functions.
 - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
   per Jonathan's recommendations.

Changes Since V2:
 - Went back to using a new driver on advice from Invensense engineer.
 - Further split changes up into smaller chunks of functionality. Note
   still that the largest patch is approximately 900 lines, and that while
   the driver compiles cleanly at each commit it is not able to drive the
   hardware until the commit that adds the Interrupt (as it also adds the
   Makefile).
 - Change the error to a warning when the devicetree binding does not match
   the hardware ID.
 - Dropped the ack on the devicetree bindings, as I am creating a new file
   (for a new driver) instead of modifying the existing one.

Changes Since V3:
 - Numerous small fixes (too many to list here). Thank you to everyone who
   provided feedback.
 - Split power management additions into an additional commit to break
   things up further.
 - Consolidated devicetree documentation in existing
   invensense,icm42600.yaml file.
 - Removed most of the FIELD_PREP from header file to c files to make code
   easier to read.
 - Changed scale values to 2D arrays for Gyro and Accelerometer.
 - Removed IIO_CHAN_INFO_CALIBBIAS attribute.

Changes Since V4:
 - Additional numerous small fixes, thank you again for all the feedback.
 - Dropped power control API and instead run device in low noise mode.
 - Split devicetree bindings into two distinct changes.
 - Reordered adding of enums and structs to main header file so that they
   are only brought in when needed.
 - Stopped using enum for driver data and instead am using pointer to
   device specific driver data.

Changes Since V5:
 - Corrected use of "dev_warn_probe" to just "dev_warn".
 - Fixed some return scenarios which would unconditionally return 0
   when an error was present.
 - Corrected use of max() to min() for bounds checking. max() was
   incorrect.
 - Fixed using "st->conf.accel.odr" in the gyroscope function. It
   should have been "st->conf.gyro.odr" which it now is.
 - Additional small fixes suggested by "sashiko.dev".
 - Added a regmap cache. I used the datasheet to try and determine
   which registers might change without explicit writes.

Changes Since V6:
 - Corrected additional errors identified by sashiko.dev, mostly
   fixing potential deadlocks, missing calls for pm runtime, and
   potential overflow issues.

Changes Since V7:
 - Dropped Wake on Movement patches, since some of the functionality
   was only available for a device on which I cannot test.
 - Dropped support for SPI 3-Wire mode, since it complicated the
   bus setup (and I lack the hardware to test such features anyway).
 - Fixed a few additional bugs identified by sashiko.dev bot.

Changes Since V8:
 - Added back IRQ dropped accidentally when dropping wake on movement
   patches.
 - Dropped "Reviewed-By" tag on patch 2 because of substantial changes
   made to devicetree binding documentation.
 - Additional small fixes as suggested.

Changes Since V9:
 - Removed interrupts (and buffers) from the driver. I previously was
   unable to detect deadlocks because it turns out my IRQ was not even
   wired correctly in my device.
 - Updated devicetree binding commits to make interrupts optional for
   users of the icm42607 driver.

Changes Since V10:
 - Explicitly specified enum values in header file.
 - Removed additional dead code for buffer handling.
 - Cleaned up headers.
 - Added additional locks as requested by sashiko.dev bot.

Changes Since V11:
 - Since driver has shrunk in size considerably, moved i2c bits into
   first code commit. This ensures that the very first commit with code
   can now be compiled. The commit after that adds SPI support as it
   was in the previous versions.
 - Used pahole to optimize inv_icm42607_state. Reordering elements
   reduced size in memory from 384 bytes to 256 bytes.
 - Added a map of all readable registers and all writeable registers
   according to the datasheet.
 - Added back some missing headers pointed out by the maintainers.
 - Added FIELD_PREP in a few more places to make the code more
   obvious on what it's doing.
 - Added a comment to the power management code to note that
   temperature sensor being enabled doesn't matter as the clocks
   are off by default when the gyro and accel channels are off.
 - Removed iio_device_claim_direct() calls since it was no longer
   needed.
 - Fixed shared_by_all attributes for temperature sensor.
 - Additional miscellanous fixes as requested.

Chris Morgan (9):
  dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
  dt-bindings: iio: imu: icm42600: Add icm42607
  iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
  iio: imu: inv_icm42607: Add SPI For icm42607
  iio: imu: inv_icm42607: Add PM support for icm42607
  iio: imu: inv_icm42607: Add Temp Support in icm42607
  iio: imu: inv_icm42607: Add Accelerometer for icm42607
  iio: imu: inv_icm42607: Add Gyroscope to icm42607
  arm64: dts: rockchip: Add icm42607p IMU for RG-DS

 .../bindings/iio/imu/invensense,icm42600.yaml |  20 +-
 .../dts/rockchip/rk3568-anbernic-rg-ds.dts    |   8 +-
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 +
 drivers/iio/imu/inv_icm42607/Makefile         |  13 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 417 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 376 ++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 543 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 370 ++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  98 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 108 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  |  76 +++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  |  37 ++
 14 files changed, 2096 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:01 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:01 -0500
Subject: [PATCH V12 4/9] iio: imu: inv_icm42607: Add SPI For icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add SPI driver support for InvenSense ICM-42607 devices.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Kconfig          |  12 ++
 drivers/iio/imu/inv_icm42607/Makefile         |   3 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 107 ++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c

diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
index 083c212087ab..23f461f57afc 100644
--- a/drivers/iio/imu/inv_icm42607/Kconfig
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -16,3 +16,15 @@ config INV_ICM42607_I2C
 
 	  This driver can be built as a module. The module will be called
 	  inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+	tristate "InvenSense ICM-42607 SPI driver"
+	depends on SPI_MASTER
+	select INV_ICM42607
+	select REGMAP_SPI
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over SPI.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index 32046e2727d7..be109102e203 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -5,3 +5,6 @@ inv-icm42607-y += inv_icm42607_core.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 000000000000..0c8deb1f33e2
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	/* Only support 4-wire mode for now. */
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+				      INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+	if (ret)
+		return ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+			 INV_ICM42607_SLEW_RATE_2NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+				 INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+			 INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  val);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+	const struct inv_icm42607_hw *hw;
+	struct device *dev = &spi->dev;
+	struct regmap *regmap;
+
+	hw = spi_get_device_match_data(spi);
+	if (!hw)
+		return dev_err_probe(dev, -ENODEV, "Failed to get SPI data\n");
+
+	if (spi->mode & SPI_3WIRE)
+		return dev_err_probe(dev, -ENODEV, "SPI 3-wire mode not supported\n");
+
+	regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to register spi regmap\n");
+
+	return inv_icm42607_core_probe(regmap, hw,
+				       inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	},
+	{
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-spi",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_spi_id_table,
+	.probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:02 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:02 -0500
Subject: [PATCH V12 5/9] iio: imu: inv_icm42607: Add PM support for icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add power management support for the ICM42607 device driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  18 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 131 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |   1 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   |   1 +
 4 files changed, 151 insertions(+)

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index c85d3b74166f..28edc12d5373 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -9,6 +9,7 @@
 #include <linux/bits.h>
 #include <linux/iio/iio.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time.h>
@@ -105,11 +106,19 @@ struct inv_icm42607_hw {
 	u8 whoami;
 };
 
+struct inv_icm42607_suspended {
+	enum inv_icm42607_sensor_mode gyro;
+	enum inv_icm42607_sensor_mode accel;
+	bool temp;
+};
+
 /**
  *  struct inv_icm42607_state - driver state variables
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
  *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @suspended:		suspended sensors configuration.
+ *  @vddio_en:		I/O voltage status for runtime PM.
  *  @lock:		lock for serializing multiple registers access.
  *  @conf:		chip sensors configurations.
  *  @orientation:	sensor chip orientation relative to main hardware.
@@ -118,6 +127,8 @@ struct inv_icm42607_state {
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
 	struct regulator *vddio_supply;
+	struct inv_icm42607_suspended suspended;
+	bool vddio_en;
 	struct mutex lock;
 	struct inv_icm42607_conf conf;
 	struct iio_mount_matrix orientation;
@@ -339,11 +350,18 @@ struct inv_icm42607_state {
 #define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
 #define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
 
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS			(2 * USEC_PER_MSEC)
+
 typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
 
 extern const struct regmap_config inv_icm42607_regmap_config;
 extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 5d40f1ee53d6..8073317088ec 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -11,6 +11,7 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time.h>
@@ -102,6 +103,56 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+				      enum inv_icm42607_sensor_mode gyro,
+				      enum inv_icm42607_sensor_mode accel,
+				      bool temp, unsigned int *sleep_ms)
+{
+	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
+	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
+	bool oldtemp = st->conf.temp_en;
+	unsigned int sleepval_ms;
+	unsigned int val;
+	int ret;
+
+	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+		return 0;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+	/*
+	 * Note that temp being enabled here doesn't affect PM since
+	 * per 10.25 of the datasheet the clock will be off by default
+	 * if both the gyro and accel modes are off.
+	 */
+	if (!temp)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	st->conf.gyro.mode = gyro;
+	st->conf.accel.mode = accel;
+	st->conf.temp_en = temp;
+
+	sleepval_ms = 0;
+	if (temp && !oldtemp)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_TEMP_STARTUP_TIME_MS);
+
+	if (accel != oldaccel)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
+
+	if (gyro != oldgyro)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_GYRO_STARTUP_TIME_MS);
+
+	if (sleep_ms)
+		*sleep_ms = sleepval_ms;
+	else if (sleepval_ms)
+		fsleep(sleepval_ms * USEC_PER_MSEC);
+
+	return 0;
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
@@ -213,12 +264,17 @@ static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
 {
 	int ret;
 
+	if (st->vddio_en)
+		return 0;
+
 	ret = regulator_enable(st->vddio_supply);
 	if (ret)
 		return ret;
 
 	fsleep(INV_ICM42607_POWER_UP_TIME_US);
 
+	st->vddio_en = true;
+
 	return 0;
 }
 
@@ -226,7 +282,12 @@ static void inv_icm42607_disable_vddio_reg(void *_data)
 {
 	struct inv_icm42607_state *st = _data;
 
+	if (!st->vddio_en)
+		return;
+
 	regulator_disable(st->vddio_supply);
+
+	st->vddio_en = false;
 }
 
 int inv_icm42607_core_probe(struct regmap *regmap,
@@ -241,6 +302,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (!st)
 		return -ENOMEM;
 
+	dev_set_drvdata(dev, st);
+
 	ret = devm_mutex_init(dev, &st->lock);
 	if (ret)
 		return ret;
@@ -276,10 +339,78 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (ret)
 		return ret;
 
+	ret = devm_pm_runtime_set_active_enabled(dev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(dev);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
 
+static int inv_icm42607_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		return ret;
+
+	inv_icm42607_disable_vddio_reg(st);
+
+	return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* save sensors state */
+	st->suspended.gyro = st->conf.gyro.mode;
+	st->suspended.accel = st->conf.accel.mode;
+	st->suspended.temp = st->conf.temp_en;
+
+	return inv_icm42607_set_pwr_mgmt0(st, INV_ICM42607_SENSOR_MODE_OFF,
+					  INV_ICM42607_SENSOR_MODE_OFF, false,
+					  NULL);
+}
+
+static int inv_icm42607_runtime_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* restore sensors state */
+	return inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
+					  st->suspended.accel,
+					  st->suspended.temp, NULL);
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+	SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
+		       inv_icm42607_runtime_resume,
+		       NULL)
+};
+
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
index a1484f32c5d9..6e7310db5598 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -85,6 +85,7 @@ static struct i2c_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-i2c",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_id,
 	.probe = inv_icm42607_probe,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
index 0c8deb1f33e2..e361a692a32f 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -95,6 +95,7 @@ static struct spi_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-spi",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_spi_id_table,
 	.probe = inv_icm42607_probe,
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:04 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:04 -0500
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-8-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add icm42607 accelerometer sensor for icm42607.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  34 ++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 376 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  61 +++
 4 files changed, 472 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index c04953ed42ce..d74b23b1e1be 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 53dd23509a53..e236e5aa61cb 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -86,6 +86,17 @@ enum inv_icm42607_filter_bw {
 	INV_ICM42607_FILTER_BW_NB
 };
 
+/* Low-Power mode sensor data filter (averaging) */
+enum inv_icm42607_filter_avg {
+	INV_ICM42607_FILTER_AVG_2X = 0,
+	INV_ICM42607_FILTER_AVG_4X = 1,
+	INV_ICM42607_FILTER_AVG_8X = 2,
+	INV_ICM42607_FILTER_AVG_16X = 3,
+	INV_ICM42607_FILTER_AVG_32X = 4,
+	INV_ICM42607_FILTER_AVG_64X = 5,
+	/* values 6 and 7 also correspond to 64x. */
+};
+
 /* Signed so that negative values can signify an invalid condition. */
 struct inv_icm42607_sensor_conf {
 	int mode;
@@ -93,6 +104,7 @@ struct inv_icm42607_sensor_conf {
 	int odr;
 	int filter;
 };
+#define INV_ICM42607_SENSOR_CONF_INIT		{ -1, -1, -1, -1 }
 
 struct inv_icm42607_conf {
 	struct inv_icm42607_sensor_conf gyro;
@@ -117,6 +129,7 @@ struct inv_icm42607_suspended {
  *  @buffer:		data transfer buffer aligned for DMA.
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
+ *  @indio_accel:	accelerometer IIO device.
  *  @vddio_supply:	I/O voltage regulator for the chip.
  *  @suspended:		suspended sensors configuration.
  *  @vddio_en:		I/O voltage status for runtime PM.
@@ -128,6 +141,7 @@ struct inv_icm42607_state {
 	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
+	struct iio_dev *indio_accel;
 	struct regulator *vddio_supply;
 	struct inv_icm42607_suspended suspended;
 	bool vddio_en;
@@ -136,6 +150,16 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 };
 
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @power_mode:		sensor requested power mode (for common frequencies)
+ * @filter:		sensor filter.
+ */
+struct inv_icm42607_sensor_state {
+	enum inv_icm42607_sensor_mode power_mode;
+	int filter;
+};
+
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
 
 /* Register Map for User Bank 0 */
@@ -365,6 +389,14 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan);
+
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -372,4 +404,6 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
+
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
new file mode 100644
index 000000000000..5e260ddad641
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)		\
+{									\
+	.type = IIO_ACCEL,						\
+	.modified = 1,							\
+	.channel2 = _modifier,						\
+	.info_mask_separate =						\
+		BIT(IIO_CHAN_INFO_RAW),					\
+	.info_mask_shared_by_type =					\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_type_available =				\
+		BIT(IIO_CHAN_INFO_SCALE),				\
+	.info_mask_shared_by_all =					\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.info_mask_shared_by_all_available =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
+	.scan_index = _index,						\
+	.scan_type = {							\
+		.sign = 's',						\
+		.realbits = 16,						\
+		.storagebits = 16,					\
+		.endianness = IIO_BE,					\
+	},								\
+	.ext_info = _ext_info,						\
+}
+
+enum inv_icm42607_accel_scan {
+	INV_ICM42607_ACCEL_SCAN_X,
+	INV_ICM42607_ACCEL_SCAN_Y,
+	INV_ICM42607_ACCEL_SCAN_Z,
+	INV_ICM42607_ACCEL_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP),
+};
+
+static int inv_icm42607_accel_read_sensor(struct iio_dev *indio_dev,
+					  struct iio_chan_spec const *chan,
+					  s16 *val)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable accel sensor */
+	conf.mode = accel_st->power_mode;
+	conf.filter = accel_st->filter;
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read accel register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_accel_scale_nano[][2] = {
+	[INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 },
+	[INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 },
+	[INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 },
+	[INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 }
+};
+
+static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev,
+					 int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.accel.fs;
+
+	*val = inv_icm42607_accel_scale_nano[idx][0];
+	*val2 = inv_icm42607_accel_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev,
+					  int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_accel_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_accel_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_accel_conf(st, &conf, NULL);
+}
+
+/* IIO format int + micro , values 0-5 reserved. */
+static const int inv_icm42607_accel_odr[][2] = {
+	[INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 },
+	[INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 },
+	[INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 },
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 }
+};
+
+static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
+				       int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.accel.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_accel_odr[i][0];
+	*val2 = inv_icm42607_accel_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
+					int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
+		if (val == inv_icm42607_accel_odr[idx][0] &&
+		    val2 == inv_icm42607_accel_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ACCEL:
+		break;
+	case IIO_TEMP:
+		if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+			return inv_icm42607_temp_read_raw(indio_dev, chan,
+							  val, val2, mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_accel_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_read_avail(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 const int **vals,
+					 int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_accel_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_accel_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_accel_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
+						struct iio_chan_spec const *chan,
+						long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_accel_info = {
+	.read_raw = inv_icm42607_accel_read_raw,
+	.read_avail = inv_icm42607_accel_read_avail,
+	.write_raw = inv_icm42607_accel_write_raw,
+	.write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_state *accel_st;
+	struct iio_dev *indio_dev;
+	const char *name;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	accel_st = iio_priv(indio_dev);
+
+	accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+	accel_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_accel_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_accel_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 549fe248e600..86ddbf72858c 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -103,6 +103,15 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan)
+{
+	const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+	return &st->orientation;
+}
+
 static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 				      enum inv_icm42607_sensor_mode gyro,
 				      enum inv_icm42607_sensor_mode accel,
@@ -153,6 +162,53 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.accel;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		if (conf->mode == INV_ICM42607_SENSOR_MODE_LOW_POWER) {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
+		} else {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
+					 conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+		}
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -364,6 +420,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
 	pm_runtime_use_autosuspend(dev);
 
+	/* Initialize IIO device for Accel */
+	st->indio_accel = inv_icm42607_accel_init(st);
+	if (IS_ERR(st->indio_accel))
+		return PTR_ERR(st->indio_accel);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:25:59 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:25:59 -0500
Subject: [PATCH V12 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the ICM42607 and ICM42607P inertial measurement unit.

This device is functionally very similar to the icm42600 series with a
very different register layout. The driver does not require an
interrupt for these specific chip revisions.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../bindings/iio/imu/invensense,icm42600.yaml  | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 9b2af104f186..81b6e85decd5 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
       - invensense,icm42600
       - invensense,icm42602
       - invensense,icm42605
+      - invensense,icm42607
+      - invensense,icm42607p
       - invensense,icm42622
       - invensense,icm42631
       - invensense,icm42686
@@ -67,10 +69,24 @@ properties:
 required:
   - compatible
   - reg
-  - interrupts
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - invensense,icm42600
+              - invensense,icm42602
+              - invensense,icm42605
+              - invensense,icm42622
+              - invensense,icm42631
+              - invensense,icm42686
+              - invensense,icm42688
+    then:
+      required:
+        - interrupts
 
 unevaluatedProperties: false
 
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:00 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:00 -0500
Subject: [PATCH V12 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the core component of a new inv_icm42607 driver. This includes
a few setup functions and the full register definition in the
header file, as well as the bits necessary to compile and probe the
device when used on an i2c bus.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  18 +
 drivers/iio/imu/inv_icm42607/Makefile         |   7 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 352 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 285 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  97 +++++
 7 files changed, 761 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c

diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb6..8bab4616be20 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
 source "drivers/iio/imu/inv_icm45600/Kconfig"
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c9..3268dc2371ae 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
 obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
 
 obj-y += inv_icm42600/
+obj-y += inv_icm42607/
 obj-y += inv_icm45600/
 obj-y += inv_mpu6050/
 
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 000000000000..083c212087ab
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+	tristate
+	select IIO_BUFFER
+	select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+	tristate "InvenSense ICM-42607 I2C driver"
+	depends on I2C
+	select INV_ICM42607
+	select REGMAP_I2C
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over I2C.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-i2c.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 000000000000..32046e2727d7
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..c85d3b74166f
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+	INV_ICM42607_SLEW_RATE_20_60NS = 0,
+	INV_ICM42607_SLEW_RATE_12_36NS = 1,
+	INV_ICM42607_SLEW_RATE_6_19NS = 2,
+	INV_ICM42607_SLEW_RATE_4_14NS = 3,
+	INV_ICM42607_SLEW_RATE_2_6NS = 4,
+	INV_ICM42607_SLEW_RATE_2NS = 5,
+	INV_ICM42607_SLEW_RATE_NB
+};
+
+enum inv_icm42607_sensor_mode {
+	INV_ICM42607_SENSOR_MODE_OFF = 0,
+	INV_ICM42607_SENSOR_MODE_STANDBY = 1,
+	INV_ICM42607_SENSOR_MODE_LOW_POWER = 2,
+	INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3,
+	INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+	INV_ICM42607_GYRO_FS_2000DPS = 0,
+	INV_ICM42607_GYRO_FS_1000DPS = 1,
+	INV_ICM42607_GYRO_FS_500DPS = 2,
+	INV_ICM42607_GYRO_FS_250DPS = 3,
+	INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+	INV_ICM42607_ACCEL_FS_16G = 0,
+	INV_ICM42607_ACCEL_FS_8G = 1,
+	INV_ICM42607_ACCEL_FS_4G = 2,
+	INV_ICM42607_ACCEL_FS_2G = 3,
+	INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values  - Note Gyro does not support ODR less than 12.5Hz */
+enum inv_icm42607_odr {
+	INV_ICM42607_ODR_1600HZ = 5,
+	INV_ICM42607_ODR_800HZ = 6,
+	INV_ICM42607_ODR_400HZ = 7,
+	INV_ICM42607_ODR_200HZ = 8,
+	INV_ICM42607_ODR_100HZ = 9,
+	INV_ICM42607_ODR_50HZ = 10,
+	INV_ICM42607_ODR_25HZ = 11,
+	INV_ICM42607_ODR_12_5HZ = 12,
+	INV_ICM42607_ODR_6_25HZ_LP = 13,
+	INV_ICM42607_ODR_3_125HZ_LP = 14,
+	INV_ICM42607_ODR_1_5625HZ_LP = 15,
+	INV_ICM42607_ODR_NB
+};
+
+/* Low-Noise mode sensor data filter (bandwidth) */
+enum inv_icm42607_filter_bw {
+	INV_ICM42607_FILTER_BYPASS = 0,
+	INV_ICM42607_FILTER_BW_180HZ = 1,
+	INV_ICM42607_FILTER_BW_121HZ = 2,
+	INV_ICM42607_FILTER_BW_73HZ = 3,
+	INV_ICM42607_FILTER_BW_53HZ = 4,
+	INV_ICM42607_FILTER_BW_34HZ = 5,
+	INV_ICM42607_FILTER_BW_25HZ = 6,
+	INV_ICM42607_FILTER_BW_16HZ = 7,
+	INV_ICM42607_FILTER_BW_NB
+};
+
+/* Signed so that negative values can signify an invalid condition. */
+struct inv_icm42607_sensor_conf {
+	int mode;
+	int fs;
+	int odr;
+	int filter;
+};
+
+struct inv_icm42607_conf {
+	struct inv_icm42607_sensor_conf gyro;
+	struct inv_icm42607_sensor_conf accel;
+	bool temp_en;
+};
+
+struct inv_icm42607_hw {
+	const char *name;
+	const struct inv_icm42607_conf *conf;
+	u8 whoami;
+};
+
+/**
+ *  struct inv_icm42607_state - driver state variables
+ *  @hw:		Hardware specific data.
+ *  @map:		regmap pointer.
+ *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @lock:		lock for serializing multiple registers access.
+ *  @conf:		chip sensors configurations.
+ *  @orientation:	sensor chip orientation relative to main hardware.
+ */
+struct inv_icm42607_state {
+	const struct inv_icm42607_hw *hw;
+	struct regmap *map;
+	struct regulator *vddio_supply;
+	struct mutex lock;
+	struct inv_icm42607_conf conf;
+	struct iio_mount_matrix orientation;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY			0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG			0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE		BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE		BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET		0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET	BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH	BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1			0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2			0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3			0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG			0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED		BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL		BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH	BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW		0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED		BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL		BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH	BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW		0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1			0x09
+#define INV_ICM42607_REG_TEMP_DATA0			0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1			0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0			0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1			0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0			0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1			0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0			0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1			0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0			0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1			0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0			0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1			0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0			0x16
+#define INV_ICM42607_DATA_INVALID			-32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH			0x17
+#define INV_ICM42607_REG_TMST_FSYNCL			0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0			0x31
+#define INV_ICM42607_REG_APEX_DATA1			0x32
+#define INV_ICM42607_REG_APEX_DATA2			0x33
+#define INV_ICM42607_REG_APEX_DATA3			0x34
+#define INV_ICM42607_REG_APEX_DATA4			0x1D
+#define INV_ICM42607_REG_APEX_DATA5			0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0			0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL		BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE			BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK		GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0			0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0			0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0			0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK		GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1			0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1			0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK		GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0			0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN	BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN		BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN	BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1			0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE		BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE		BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE		BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE		BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG			0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK		GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE		BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE			BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN			BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1			0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE			BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2			0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3			0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm)		\
+		cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX			(2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE		8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE		16
+
+#define INV_ICM42607_REG_INT_SOURCE0			0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1			0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3			0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4			0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN		BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN		BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0			0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1			0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0			0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	\
+	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42607_REG_INTF_CONFIG1			0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN		BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN		BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK		GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT		0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL		1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF		2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY		0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY		BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS			0x3A
+#define INV_ICM42607_INT_STATUS_ST			BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC			BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY			BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE		BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS		BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL		BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY			BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2			0x3B
+#define INV_ICM42607_INT_STATUS2_SMD			BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3			0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET		BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF		BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET		BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET			BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH			0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL			0x3E
+#define INV_ICM42607_REG_FIFO_DATA			0x3F
+
+#define INV_ICM42607_REG_ACCEL_WOM_X_THR		0x4b
+#define INV_ICM42607_REG_ACCEL_WOM_Y_THR		0x4c
+#define INV_ICM42607_REG_ACCEL_WOM_Z_THR		0x4d
+
+#define INV_ICM42607_REG_WHOAMI				0x75
+#define INV_ICM42607P_WHOAMI				0x60
+#define INV_ICM42607_WHOAMI				0x67
+
+/* Timings as listed in section 3 of datasheet */
+#define INV_ICM42607_POWER_UP_TIME_US			(100 * USEC_PER_MSEC)
+#define INV_ICM42607_RESET_TIME_MS			1
+#define INV_ICM42607_ACCEL_STARTUP_TIME_MS		10
+#define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
+#define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..5d40f1ee53d6
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+
+#include "inv_icm42607.h"
+
+static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
+	case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
+	case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
+	case INV_ICM42607_REG_WHOAMI:
+		return true;
+	}
+
+	return false;
+}
+
+static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
+	case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
+	case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
+		return true;
+	}
+
+	return false;
+}
+
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY:
+	case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+	case INV_ICM42607_REG_APEX_CONFIG0:
+	case INV_ICM42607_REG_FIFO_CONFIG2 ... INV_ICM42607_REG_FIFO_CONFIG3:
+	case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+	case INV_ICM42607_REG_INT_STATUS_DRDY:
+	case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = inv_icm42607_is_writeable_reg,
+	.readable_reg = inv_icm42607_is_readable_reg,
+	.volatile_reg = inv_icm42607_is_volatile_reg,
+	.max_register = INV_ICM42607_REG_WHOAMI,
+	.cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+	.gyro = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_GYRO_FS_1000DPS,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.accel = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_ACCEL_FS_4G,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.temp_en = false,
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+	.whoami = INV_ICM42607_WHOAMI,
+	.name = "icm42607",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+	.whoami = INV_ICM42607P_WHOAMI,
+	.name = "icm42607p",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
+static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
+				 const struct inv_icm42607_conf *conf)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+	/*
+	 * No temperature enable reg in datasheet, but BSP driver selected RC
+	 * oscillator clock in LP mode when temperature was disabled.
+	 */
+	if (!conf->temp_en)
+		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+	val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+	val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+				 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+				 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	st->conf = *conf;
+
+	return 0;
+}
+
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	const struct device *dev = regmap_get_device(st->map);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+	if (ret)
+		return ret;
+
+	/* Warn, but don't fail. */
+	if (val != st->hw->whoami)
+		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+			 val, st->hw->whoami, st->hw->name);
+
+	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+	if (ret)
+		return ret;
+
+	fsleep(1 * USEC_PER_MSEC);
+
+	/*
+	 * No polling interval specified in datasheet, so use reset time as
+	 * polling interval and 10x reset time as timeout period.
+	 */
+	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+				       1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "reset error, reset done bit not set\n");
+
+	/* Sync the regcache again after a reset. */
+	regcache_mark_dirty(st->map);
+	ret = regcache_sync(st->map);
+	if (ret)
+		return ret;
+
+	ret = inv_icm42607_bus_setup(st);
+	if (ret)
+		return ret;
+
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+			 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+				 val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+	int ret;
+
+	ret = regulator_enable(st->vddio_supply);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+	return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+	struct inv_icm42607_state *st = _data;
+
+	regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	struct device *dev = regmap_get_device(regmap);
+	struct inv_icm42607_state *st;
+	int ret;
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
+	st->hw = hw;
+	st->map = regmap;
+
+	ret = iio_read_mount_matrix(dev, &st->orientation);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to retrieve mounting matrix\n");
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get vdd regulator\n");
+
+	st->vddio_supply = devm_regulator_get(dev, "vddio");
+	if (IS_ERR(st->vddio_supply))
+		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+				     "Failed to get vddio regulator\n");
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+	if (ret)
+		return ret;
+
+	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+	ret = inv_icm42607_setup(st, inv_icm42607_bus_setup);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 000000000000..a1484f32c5d9
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+			 INV_ICM42607_SLEW_RATE_12_36NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+				 INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+			 INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  val);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = i2c_get_match_data(client);
+	if (!hw)
+		return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n");
+
+	regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to register i2c regmap\n");
+
+	return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	}, {
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-i2c",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_id,
+	.probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607x I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:03 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:03 -0500
Subject: [PATCH V12 6/9] iio: imu: inv_icm42607: Add Temp Support in icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add functions for reading temperature sensor data.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |  1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  5 ++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 18 +++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  | 76 +++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  | 37 +++++++++
 5 files changed, 137 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index be109102e203..c04953ed42ce 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 28edc12d5373..53dd23509a53 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -114,6 +114,7 @@ struct inv_icm42607_suspended {
 
 /**
  *  struct inv_icm42607_state - driver state variables
+ *  @buffer:		data transfer buffer aligned for DMA.
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
  *  @vddio_supply:	I/O voltage regulator for the chip.
@@ -124,6 +125,7 @@ struct inv_icm42607_suspended {
  *  @orientation:	sensor chip orientation relative to main hardware.
  */
 struct inv_icm42607_state {
+	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
 	struct regulator *vddio_supply;
@@ -363,6 +365,9 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 8073317088ec..549fe248e600 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -153,6 +153,24 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+			 INV_ICM42607_FILTER_BW_34HZ);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+				 INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+					  st->conf.accel.mode, enable,
+					  sleep_ms);
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
new file mode 100644
index 000000000000..b259fc9c9fd2
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp)
+{
+	struct device *dev = regmap_get_device(st->map);
+	__be16 *raw;
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_temp_conf(st, true, NULL);
+	if (ret)
+		return ret;
+
+	raw = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1,
+			       raw, sizeof(*raw));
+	if (ret)
+		return ret;
+
+	*temp = be16_to_cpup(raw);
+	if (*temp == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 temp;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_temp_read(st, &temp);
+		if (ret)
+			return ret;
+		*val = temp;
+		return IIO_VAL_INT;
+	/*
+	 * T?C = (temp / 128) + 25
+	 * Tm?C = 1000 * ((temp * 100 / 12800) + 25)
+	 * scale: 100000 / 12800 ~= 7.8125
+	 * offset: 3200
+	 */
+	case IIO_CHAN_INFO_SCALE:
+		*val = 7;
+		*val2 = 812500000;
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 3200;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
new file mode 100644
index 000000000000..cb7b460ffb44
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_TEMP_H_
+#define INV_ICM42607_TEMP_H_
+
+#include <linux/bitops.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+#define INV_ICM42607_TEMP_CHAN(_index)				\
+{								\
+	.type = IIO_TEMP,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW) |			\
+		BIT(IIO_CHAN_INFO_OFFSET) |			\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.info_mask_shared_by_all_available =			\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+	},							\
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long mask);
+
+#endif
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:05 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:05 -0500
Subject: [PATCH V12 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-9-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add gyroscope functions to the icm42607 driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |   8 +
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  48 +++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 370 ++++++++++++++++++
 4 files changed, 427 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index d74b23b1e1be..7b907e019601 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_gyro.o
 inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index e236e5aa61cb..203271b9ef7a 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -130,6 +130,7 @@ struct inv_icm42607_suspended {
  *  @hw:		Hardware specific data.
  *  @map:		regmap pointer.
  *  @indio_accel:	accelerometer IIO device.
+ *  @indio_gyro:	gyroscope IIO device.
  *  @vddio_supply:	I/O voltage regulator for the chip.
  *  @suspended:		suspended sensors configuration.
  *  @vddio_en:		I/O voltage status for runtime PM.
@@ -142,6 +143,7 @@ struct inv_icm42607_state {
 	const struct inv_icm42607_hw *hw;
 	struct regmap *map;
 	struct iio_dev *indio_accel;
+	struct iio_dev *indio_gyro;
 	struct regulator *vddio_supply;
 	struct inv_icm42607_suspended suspended;
 	bool vddio_en;
@@ -397,6 +399,10 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 				struct inv_icm42607_sensor_conf *conf,
 				unsigned int *sleep_ms);
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -404,6 +410,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st);
+
 struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
 
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 86ddbf72858c..6b5185d8e321 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -209,6 +209,49 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 					  st->conf.temp_en, sleep_ms);
 }
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.gyro;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK,
+				 conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK,
+				  conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
+				 conf->filter);
+		ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+					 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -425,6 +468,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (IS_ERR(st->indio_accel))
 		return PTR_ERR(st->indio_accel);
 
+	/* Initialize IIO device for Gyro */
+	st->indio_gyro = inv_icm42607_gyro_init(st);
+	if (IS_ERR(st->indio_gyro))
+		return PTR_ERR(st->indio_gyro);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
new file mode 100644
index 000000000000..155ca089af9f
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info)	\
+{								\
+	.type = IIO_ANGL_VEL,					\
+	.modified = 1,						\
+	.channel2 = _modifier,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW),				\
+	.info_mask_shared_by_type =				\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_type_available =			\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.info_mask_shared_by_all_available =			\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+		.endianness = IIO_BE,				\
+	},							\
+	.ext_info = _ext_info,					\
+}
+
+enum inv_icm42607_gyro_scan {
+	INV_ICM42607_GYRO_SCAN_X,
+	INV_ICM42607_GYRO_SCAN_Y,
+	INV_ICM42607_GYRO_SCAN_Z,
+	INV_ICM42607_GYRO_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP),
+};
+
+static int inv_icm42607_gyro_read_sensor(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 s16 *val)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	unsigned int reg;
+	__be16 *data;
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_GYRO_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable gyro sensor */
+	conf.mode = gyro_st->power_mode;
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read gyro register data */
+	data = &st->buffer[0];
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+	if (ret)
+		return ret;
+
+	*val = be16_to_cpup(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_gyro_scale_nano[][2] = {
+	[INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 },
+	[INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 },
+	[INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 },
+	[INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 },
+};
+
+static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev,
+					int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.gyro.fs;
+
+	*val = inv_icm42607_gyro_scale_nano[idx][0];
+	*val2 = inv_icm42607_gyro_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev,
+					 int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano);
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_gyro_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_gyro_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
+}
+
+static const int inv_icm42607_gyro_odr[][2] = {
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+};
+
+static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st,
+				      int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.gyro.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_gyro_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_gyro_odr[i][0];
+	*val2 = inv_icm42607_gyro_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
+				       int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); ++idx) {
+		if (val == inv_icm42607_gyro_odr[idx][0] &&
+		    val2 == inv_icm42607_gyro_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ANGL_VEL:
+		break;
+	case IIO_TEMP:
+		if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+			return inv_icm42607_temp_read_raw(indio_dev, chan,
+							  val, val2, mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_gyro_read_sensor(indio_dev, chan, &data);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_gyro_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_read_avail(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					const int **vals,
+					int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_gyro_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_gyro_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_gyro_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
+					       struct iio_chan_spec const *chan,
+					       long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_gyro_info = {
+	.read_raw = inv_icm42607_gyro_read_raw,
+	.read_avail = inv_icm42607_gyro_read_avail,
+	.write_raw = inv_icm42607_gyro_write_raw,
+	.write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *gyro_st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	gyro_st = iio_priv(indio_dev);
+
+	gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_gyro_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_gyro_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
-- 
2.43.0



From macroalpha82 at gmail.com  Thu Jun 11 13:26:06 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Thu, 11 Jun 2026 15:26:06 -0500
Subject: [PATCH V12 9/9] arm64: dts: rockchip: Add icm42607p IMU for RG-DS
In-Reply-To: <20260611202607.85376-1-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
Message-ID: <20260611202607.85376-10-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix
was tested with iio-sensor-proxy and reports correct orientation.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
index 8d906ab02c5f..b770bfd5268d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
@@ -871,7 +871,13 @@ aw87391_pa_r: audio-codec at 5b {
 		sound-name-prefix = "Right Amp";
 	};
 
-	/* invensense,icm42607p at 0x68 */
+	icm42607p: imu at 68 {
+		compatible = "invensense,icm42607p";
+		reg = <0x68>;
+		mount-matrix = "-1", "0", "0",
+			       "0", "1", "0",
+			       "0", "0", "-1";
+	};
 };
 
 &i2c3 {
-- 
2.43.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:19 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:19 +0300
Subject: [PATCH v4 0/8] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
Message-ID: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>

This series provides a set of bug fixes and cleanups for the Rockchip
Samsung HDPTX PHY driver.

The first part of the series addresses clock rate calculation and
synchronization issues.  Specifically, it fixes edge cases where the PHY
PLL is pre-programmed by an external component (like a bootloader) or
when changing the color depth (bpc) while keeping the modeline constant.
Because the Common Clock Framework .set_rate() callback might not be
invoked if the pixel clock remains unchanged, this previously led to
out-of-sync states between CCF and the actual HDMI PHY configuration.

The second part focuses on code cleanups and modernizing the register
access.  Now that dw_hdmi_qp driver has fully switched to using
phy_configure(), we can drop the deprecated TMDS rate setup workarounds
and the restrict_rate_change flag logic.  Finally, it refactors the
driver to consistently use standard bitfield macros.

Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v4:
- Added new patches to address new findings from Sashiko:
  * Prevent divide-by-zero when computing clk rate
  * Fix rate recalculation for 3.2GHz FRL
- Updated patch "Consistently use bitfield macros" to handle a few more
  bit operations
- Link to v3: https://patch.msgid.link/20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16 at collabora.com

Changes in v3:
- Replaced div_u64() with DIV_ROUND_CLOSEST_ULL() in Patch 1 (Sashiko)
- Fixed theoretical usage_count unbalanced issue in Patch 2 (Sashiko)
- Rebased series onto latest phy/next
- Link to v2: https://patch.msgid.link/20260511-hdptx-clk-fixes-v2-0-664e41379cab at collabora.com

Changes in v2:
- Collected Tested-by tags from Thomas and Simon
- Fixed a typo in commit description of patch 1
- Added a comment in patch 2 explaining why PLL config errors are
  ignored for rk_hdptx_phy_consumer_get()
- Added a missed FIELD_GET conversion for lcpll_hw.pms_sdiv in patch 6
- Rebased onto latest phy/fixes
- Link to v1: https://lore.kernel.org/r/20260227-hdptx-clk-fixes-v1-0-f998f2762d0f at collabora.com

---
Cristian Ciocaltea (8):
      phy: rockchip: samsung-hdptx: Fix rate recalculation for high bpc
      phy: rockchip: samsung-hdptx: Prevent divide-by-zero when computing clk rate
      phy: rockchip: samsung-hdptx: Fix rate recalculation for 3.2GHz FRL
      phy: rockchip: samsung-hdptx: Handle uncommitted PHY config changes
      phy: rockchip: samsung-hdptx: Drop TMDS rate setup workaround
      phy: rockchip: samsung-hdptx: Drop restrict_rate_change handling
      phy: rockchip: samsung-hdptx: Simplify GRF access with FIELD_PREP_WM16()
      phy: rockchip: samsung-hdptx: Consistently use bitfield macros

 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 266 +++++++++++-----------
 1 file changed, 130 insertions(+), 136 deletions(-)
---
base-commit: 293e19f416fa3f233a2fb013258f7abcb39ad6ed
change-id: 20260227-hdptx-clk-fixes-47426632f862



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:20 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:20 +0300
Subject: [PATCH v4 1/8] phy: rockchip: samsung-hdptx: Fix rate
 recalculation for high bpc
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-1-ce5e1d456cda@collabora.com>

The PHY PLL can be programmed by an external component, e.g. the
bootloader, just before the recalc_rate() callback is invoked during
devm_clk_hw_register() in the probe path.

Therefore rk_hdptx_phy_clk_recalc_rate() finds the PLL enabled and
attempts to compute the clock rate, while making use of the bpc value
from the HDMI PHY configuration, which always defaults to 8 because
phy_configure() was not run at that point.  As a consequence, the
(re)calculated rate is incorrect when the actual bpc was higher than 8.

Do not rely on any of the hdmi_cfg members when computing the clock rate
and, instead, read the required input data (i.e. bpc), directly from the
hardware registers.

Fixes: 3481fc04d969 ("phy: rockchip: samsung-hdptx: Compute clk rate from PLL config")
Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 2d973bc37f07..710603afff86 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -2168,7 +2168,7 @@ 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;
+	u32 mode, bpc, val;
 	int ret, i;
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(0008), &mode);
@@ -2266,6 +2266,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	if (ret)
 		return 0;
 	ropll_hw.pms_sdiv = ((val & PLL_PCG_POSTDIV_SEL_MASK) >> 4) + 1;
+	bpc = (FIELD_GET(PLL_PCG_CLK_SEL_MASK, val) << 1) + 8;
 
 	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
 	if (ropll_hw.sdm_en) {
@@ -2280,7 +2281,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 			fout = fout + sdm;
 	}
 
-	return div_u64(fout * 2, ropll_hw.pms_sdiv * 10);
+	return DIV_ROUND_CLOSEST_ULL(fout * 2 * 8, ropll_hw.pms_sdiv * 10 * bpc);
 }
 
 static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
@@ -2288,19 +2289,13 @@ static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw,
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 	u32 status;
-	u64 rate;
 	int ret;
 
 	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);
-
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
-		return rate;
-
-	return DIV_ROUND_CLOSEST_ULL(rate * 8, hdptx->hdmi_cfg.bpc);
+	return rk_hdptx_phy_clk_calc_rate_from_pll_cfg(hdptx);
 }
 
 static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:21 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:21 +0300
Subject: [PATCH v4 2/8] phy: rockchip: samsung-hdptx: Prevent
 divide-by-zero when computing clk rate
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-2-ce5e1d456cda@collabora.com>

Calculating 'sdm' fraction in rk_hdptx_phy_clk_calc_rate_from_pll_cfg()
could trigger a divide-by-zero, as it uses div_u64() with a denominator
read directly from hardware: the values ropll_hw.sdm_deno,
ropll_hw.sdc_deno, ropll_hw.sdc_n, and ropll_hw.sdc_num are populated
from PLL registers which, in theory, could be left by the bootloader
uninitialized/misconfigured.

Provide the necessary sanitization to avoid trusting the hardware state.

Reported-by: Sashiko <sashiko-bot at kernel.org>
Closes: https://sashiko.dev/#/patchset/20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16 at collabora.com?part=1
Fixes: 3481fc04d969 ("phy: rockchip: samsung-hdptx: Compute clk rate from PLL config")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 710603afff86..8c044381b83a 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -2270,10 +2270,15 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 
 	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;
 	if (ropll_hw.sdm_en) {
+		val = 16U * ropll_hw.sdm_deno *
+		      (ropll_hw.sdc_deno * ropll_hw.sdc_n - ropll_hw.sdc_num);
+		if (!val) {
+			dev_dbg(hdptx->dev, "%s invalid ROPLL hw state\n", __func__);
+			return 0;
+		}
+
 		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));
+			      ropll_hw.pms_mdiv * ropll_hw.sdm_num, val);
 
 		if (ropll_hw.sdm_num_sign)
 			fout = fout - sdm;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:22 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:22 +0300
Subject: [PATCH v4 3/8] phy: rockchip: samsung-hdptx: Fix rate
 recalculation for 3.2GHz FRL
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-3-ce5e1d456cda@collabora.com>

rk_hdptx_phy_clk_calc_rate_from_pll_cfg() is currently unable to handle
cascade mode for the 3.2GHz FRL operating mode, as it relies solely on
LCPLL_LCVCO_MODE_EN_MASK to determinate the rate from the
rk_hdptx_frl_lcpll_cfg array.  Since there is no entry for this
particular rate, the function returns 0.

This is the only rate which requires LC_REF_CLK_SEL to be set in
GRF_HDPTX_CON0, hence extend the FRL matching accordingly.

Reported-by: Sashiko <sashiko-bot at kernel.org>
Closes: https://sashiko.dev/#/patchset/20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16 at collabora.com?part=1
Fixes: de5dba833118 ("phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support")
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 33 ++++++++++++++++-------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 8c044381b83a..b210c1a88b25 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -2206,16 +2206,31 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 			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];
+		ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &val);
+		if (ret)
+			return 0;
 
-			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;
+		if (val & LC_REF_CLK_SEL) {
+			if (lcpll_hw.pms_mdiv == 0x6b &&
+			    lcpll_hw.sdm_num_sign == 0x01 &&
+			    lcpll_hw.sdm_num == 0x02 &&
+			    lcpll_hw.sdm_deno == 0x09 &&
+			    lcpll_hw.sdc_n == FIELD_GET(LCPLL_SDC_N_MASK, 0x02))
+				return FRL_8G4L_RATE;
+		} else {
+			const struct lcpll_config *cfg;
+
+			for (i = 0; i < ARRAY_SIZE(rk_hdptx_frl_lcpll_cfg); i++) {
+				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__);

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:23 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:23 +0300
Subject: [PATCH v4 4/8] phy: rockchip: samsung-hdptx: Handle uncommitted
 PHY config changes
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-4-ce5e1d456cda@collabora.com>

Any changes to the PHY link rate and/or color depth done via the HDMI
PHY configuration API are not immediately programmed into the hardware,
but are delayed until the PHY usage count gets incremented from 0 to 1,
that is when it is powered on or when the PLL clock exposed through
the CCF API is prepared, whichever comes first.

Since the clock might remain in prepared state after subsequent PHY
config changes, the programming can also be triggered via
clk_ops.set_rate().  However, from the clock consumer perspective (i.e.
VOP2 display controller), the (pixel) clock rate doesn't vary with bpc,
as that is handled internally by the PHY and reflected in the TDMS
character rate only.

As a consequence, changing the bpc while preserving the modeline may
lead to out-of-sync issues between CCF and HDMI PHY config state,
because the .set_rate() callback is not invoked when clock rate remains
constant.  This may also happen when the PHY PLL has been pre-programmed
by an external entity, e.g. the bootloader, which is actually a
regression introduced by the recent FRL patches.

Introduce a pll_config_dirty flag to keep track of uncommitted PHY
config changes and use it in clk_ops.determine_rate() to invalidate the
current clock rate (as known by CCF) and, consequently, ensure those
changes are programmed into hardware via clk_ops.set_rate().

Moreover, proceed with a similar fix in phy_ops.power_on() callback, to
handle the scenario where the CCF API is not used due to operating in
FRL mode, while the clock is still in a prepared state and thus
preventing rk_hdptx_phy_consumer_get() to apply the updated PHY
configuration.

Fixes: de5dba833118 ("phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support")
Fixes: 9d0ec51d7c22 ("phy: rockchip: samsung-hdptx: Add high color depth management")
Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 84 +++++++++++++----------
 1 file changed, 48 insertions(+), 36 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index b210c1a88b25..25bd821cd039 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -413,6 +413,7 @@ struct rk_hdptx_phy {
 
 	/* clk provider */
 	struct clk_hw hw;
+	bool pll_config_dirty;
 	bool restrict_rate_change;
 
 	atomic_t usage_count;
@@ -1260,13 +1261,19 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 
 static int rk_hdptx_pll_cmn_config(struct rk_hdptx_phy *hdptx)
 {
+	int ret;
+
 	if (hdptx->hdmi_cfg.rate <= HDMI20_MAX_RATE)
-		return rk_hdptx_tmds_ropll_cmn_config(hdptx);
+		ret = rk_hdptx_tmds_ropll_cmn_config(hdptx);
+	else if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
+		ret = rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+	else
+		ret = rk_hdptx_frl_lcpll_cmn_config(hdptx);
 
-	if (hdptx->hdmi_cfg.rate == FRL_8G4L_RATE)
-		return rk_hdptx_frl_lcpll_ropll_cmn_config(hdptx);
+	if (!ret)
+		hdptx->pll_config_dirty = false;
 
-	return rk_hdptx_frl_lcpll_cmn_config(hdptx);
+	return ret;
 }
 
 static int rk_hdptx_frl_lcpll_mode_config(struct rk_hdptx_phy *hdptx)
@@ -1347,25 +1354,22 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
 		return 0;
 
 	ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status);
-	if (ret)
-		goto dec_usage;
-
-	if (status & HDPTX_O_PLL_LOCK_DONE)
-		dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n");
+	if (ret) {
+		atomic_dec(&hdptx->usage_count);
+		return ret;
+	}
 
 	if (mode == PHY_MODE_DP) {
 		rk_hdptx_dp_reset(hdptx);
 	} else {
-		ret = rk_hdptx_pll_cmn_config(hdptx);
-		if (ret)
-			goto dec_usage;
+		/*
+		 * Ignore PLL config errors at this point as pll_config_dirty
+		 * was not reset and, therefore, operation will be retried.
+		 */
+		rk_hdptx_pll_cmn_config(hdptx);
 	}
 
 	return 0;
-
-dec_usage:
-	atomic_dec(&hdptx->usage_count);
-	return ret;
 }
 
 static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
@@ -1700,13 +1704,18 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		if (ret)
 			rk_hdptx_phy_consumer_put(hdptx, true);
 	} else {
-		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+		if (hdptx->pll_config_dirty)
+			ret = rk_hdptx_pll_cmn_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) {
+			regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+				     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+
+			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);
@@ -2081,7 +2090,10 @@ static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opt
 			dev_err(hdptx->dev, "invalid hdmi params for phy configure\n");
 		} else {
 			hdptx->restrict_rate_change = true;
-			dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+			hdptx->pll_config_dirty = true;
+
+			dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
+				hdptx->hdmi_cfg.mode ? "FRL" : "TMDS",
 				hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
 		}
 
@@ -2323,8 +2335,19 @@ static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
 {
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
-		return hdptx->hdmi_cfg.rate;
+	/*
+	 * Invalidate current clock rate to ensure rk_hdptx_phy_clk_set_rate()
+	 * will be invoked to commit PLL configuration.
+	 */
+	if (hdptx->pll_config_dirty) {
+		req->rate = 0;
+		return 0;
+	}
+
+	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+		req->rate = hdptx->hdmi_cfg.rate;
+		return 0;
+	}
 
 	/*
 	 * FIXME: Temporarily allow altering TMDS char rate via CCF.
@@ -2356,17 +2379,6 @@ 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 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 link rate change since determine_rate() */
-	if (hdptx->hdmi_cfg.rate != link_rate) {
-		dev_warn(hdptx->dev, "Reverting unexpected rate change from %llu to %llu\n",
-			 link_rate, hdptx->hdmi_cfg.rate);
-		hdptx->hdmi_cfg.rate = link_rate;
-	}
 
 	/*
 	 * The link rate would be normally programmed in HW during

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:24 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:24 +0300
Subject: [PATCH v4 5/8] phy: rockchip: samsung-hdptx: Drop TMDS rate setup
 workaround
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-5-ce5e1d456cda@collabora.com>

Since commit ba9c2fe18c17 ("drm/rockchip: dw_hdmi_qp: Switch to
phy_configure()") the TMDS rate setup doesn't rely anymore on the
unconventional usage of the bus width, instead it is managed exclusively
through the HDMI PHY configuration API.

Drop the now obsolete workaround to retrieve the TMDS character rate via
phy_get_bus_width() during power_on().

While at it, get rid of the extra call to rk_hdptx_phy_consumer_put() by
moving the statement at the end of the function.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 27 +++++------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 25bd821cd039..35997087d61c 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1660,22 +1660,6 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 	enum phy_mode mode = phy_get_mode(phy);
 	int ret, lane;
 
-	if (mode != PHY_MODE_DP) {
-		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.
-			 * Will be removed as soon the switch to the HDMI PHY
-			 * configuration API has been completed on both ends.
-			 */
-			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.rate, hdptx->hdmi_cfg.bpc);
-	}
-
 	ret = rk_hdptx_phy_consumer_get(hdptx);
 	if (ret)
 		return ret;
@@ -1701,9 +1685,10 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 		rk_hdptx_dp_pll_init(hdptx);
 
 		ret = rk_hdptx_dp_aux_init(hdptx);
-		if (ret)
-			rk_hdptx_phy_consumer_put(hdptx, true);
 	} else {
+		dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__,
+			hdptx->hdmi_cfg.rate, hdptx->hdmi_cfg.bpc);
+
 		if (hdptx->pll_config_dirty)
 			ret = rk_hdptx_pll_cmn_config(hdptx);
 
@@ -1716,11 +1701,11 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 			else
 				ret = rk_hdptx_tmds_ropll_mode_config(hdptx);
 		}
-
-		if (ret)
-			rk_hdptx_phy_consumer_put(hdptx, true);
 	}
 
+	if (ret)
+		rk_hdptx_phy_consumer_put(hdptx, true);
+
 	return ret;
 }
 

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:25 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:25 +0300
Subject: [PATCH v4 6/8] phy: rockchip: samsung-hdptx: Drop
 restrict_rate_change handling
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-6-ce5e1d456cda@collabora.com>

Since commit 6efbd0f46dd8 ("phy: rockchip: samsung-hdptx: Restrict
altering TMDS char rate via CCF"), adjusting the rate via the Common
Clock Framework API has been disallowed.

To avoid breaking existing users until switching to the PHY config API,
it introduced a temporary exception to the rule, controlled via the
'restrict_rate_change' flag.

As the API transition completed, remove the now deprecated exception
logic.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 42 +++++------------------
 1 file changed, 8 insertions(+), 34 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 35997087d61c..b74a433c7e53 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -414,7 +414,6 @@ struct rk_hdptx_phy {
 	/* clk provider */
 	struct clk_hw hw;
 	bool pll_config_dirty;
-	bool restrict_rate_change;
 
 	atomic_t usage_count;
 
@@ -2074,7 +2073,6 @@ 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->restrict_rate_change = true;
 			hdptx->pll_config_dirty = true;
 
 			dev_dbg(hdptx->dev, "%s %s rate=%llu bpc=%u\n", __func__,
@@ -2321,41 +2319,17 @@ static int rk_hdptx_phy_clk_determine_rate(struct clk_hw *hw,
 	struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw);
 
 	/*
-	 * Invalidate current clock rate to ensure rk_hdptx_phy_clk_set_rate()
-	 * will be invoked to commit PLL configuration.
+	 * For uncommitted PLL configuration, invalidate the current clock rate
+	 * to ensure rk_hdptx_phy_clk_set_rate() will be always invoked.
+	 * Otherwise, restrict the rate according to the PHY link setup.
 	 */
-	if (hdptx->pll_config_dirty) {
+	if (hdptx->pll_config_dirty)
 		req->rate = 0;
-		return 0;
-	}
-
-	if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL) {
+	else if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
 		req->rate = hdptx->hdmi_cfg.rate;
-		return 0;
-	}
-
-	/*
-	 * FIXME: Temporarily allow altering TMDS char rate via CCF.
-	 * 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 && req->rate != hdptx->hdmi_cfg.rate) {
-		struct phy_configure_opts_hdmi hdmi = {
-			.tmds_char_rate = req->rate,
-		};
-
-		int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi, &hdptx->hdmi_cfg);
-
-		if (ret)
-			return ret;
-	}
-
-	/*
-	 * The TMDS char rate shall be adjusted via phy_configure() only,
-	 * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with
-	 * a different rate argument.
-	 */
-	req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8, hdptx->hdmi_cfg.bpc);
+	else
+		req->rate = DIV_ROUND_CLOSEST_ULL(hdptx->hdmi_cfg.rate * 8,
+						  hdptx->hdmi_cfg.bpc);
 
 	return 0;
 }

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:27 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:27 +0300
Subject: [PATCH v4 8/8] phy: rockchip: samsung-hdptx: Consistently use
 bitfield macros
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-8-ce5e1d456cda@collabora.com>

Make the code more robust and improve readability by using the available
bitfield macros (e.g. FIELD_PREP, FIELD_GET) whenever possible, instead
of open coding the related bit operations.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 30 +++++++++++++++--------
 1 file changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 88b48f5f946d..d8646f24e05e 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -53,6 +53,12 @@
 /* CMN_REG(001e) */
 #define LCPLL_PI_EN_MASK		BIT(5)
 #define LCPLL_100M_CLK_EN_MASK		BIT(0)
+/* CMN_REG(0022) */
+#define ANA_LCPLL_PMS_PDIV_MASK		GENMASK(7, 4)
+#define ANA_LCPLL_PMS_REFDIV_MASK	GENMASK(3, 0)
+/* CMN_REG(0023) */
+#define LCPLL_PMS_SDIV_RBR_MASK		GENMASK(7, 4)
+#define LCPLL_PMS_SDIV_HBR_MASK		GENMASK(3, 0)
 /* CMN_REG(0025) */
 #define LCPLL_PMS_IQDIV_RSTN_MASK	BIT(4)
 /* CMN_REG(0028) */
@@ -1157,9 +1163,11 @@ static int rk_hdptx_frl_lcpll_cmn_config(struct rk_hdptx_phy *hdptx)
 	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);
+		     FIELD_PREP(ANA_LCPLL_PMS_PDIV_MASK, cfg->pms_pdiv) |
+		     FIELD_PREP(ANA_LCPLL_PMS_REFDIV_MASK, cfg->pms_refdiv));
 	regmap_write(hdptx->regmap, CMN_REG(0023),
-		     (cfg->pms_sdiv << 4) | cfg->pms_sdiv);
+		     FIELD_PREP(LCPLL_PMS_SDIV_RBR_MASK, cfg->pms_sdiv) |
+		     FIELD_PREP(LCPLL_PMS_SDIV_HBR_MASK, 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);
@@ -1229,8 +1237,10 @@ static int rk_hdptx_tmds_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv);
 	regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc);
 	regmap_write(hdptx->regmap, CMN_REG(0059),
-		     (cfg->pms_pdiv << 4) | cfg->pms_refdiv);
-	regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4);
+		     FIELD_PREP(ANA_ROPLL_PMS_PDIV_MASK, cfg->pms_pdiv) |
+		     FIELD_PREP(ANA_ROPLL_PMS_REFDIV_MASK, cfg->pms_refdiv));
+	regmap_write(hdptx->regmap, CMN_REG(005a),
+		     FIELD_PREP(ROPLL_PMS_SDIV_RBR_MASK, cfg->pms_sdiv));
 
 	regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK,
 			   FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en));
@@ -2177,7 +2187,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 		ret = regmap_read(hdptx->regmap, CMN_REG(0023), &val);
 		if (ret)
 			return 0;
-		lcpll_hw.pms_sdiv = val & 0xf;
+		lcpll_hw.pms_sdiv = FIELD_GET(LCPLL_PMS_SDIV_HBR_MASK, val);
 
 		ret = regmap_read(hdptx->regmap, CMN_REG(002B), &val);
 		if (ret)
@@ -2197,7 +2207,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 		ret = regmap_read(hdptx->regmap, CMN_REG(002D), &val);
 		if (ret)
 			return 0;
-		lcpll_hw.sdc_n = (val & LCPLL_SDC_N_MASK) >> 1;
+		lcpll_hw.sdc_n = FIELD_GET(LCPLL_SDC_N_MASK, val);
 
 		ret = regmap_read(hdptx->grf, GRF_HDPTX_CON0, &val);
 		if (ret)
@@ -2238,12 +2248,12 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	ret = regmap_read(hdptx->regmap, CMN_REG(005E), &val);
 	if (ret)
 		return 0;
-	ropll_hw.sdm_en = val & ROPLL_SDM_EN_MASK;
+	ropll_hw.sdm_en = FIELD_GET(ROPLL_SDM_EN_MASK, val);
 
 	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;
+	ropll_hw.sdm_num_sign = FIELD_GET(ROPLL_SDM_NUM_SIGN_RBR_MASK, val);
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(0065), &val);
 	if (ret)
@@ -2258,7 +2268,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	ret = regmap_read(hdptx->regmap, CMN_REG(0069), &val);
 	if (ret)
 		return 0;
-	ropll_hw.sdc_n = (val & ROPLL_SDC_N_RBR_MASK) + 3;
+	ropll_hw.sdc_n = FIELD_GET(ROPLL_SDC_N_RBR_MASK, val) + 3;
 
 	ret = regmap_read(hdptx->regmap, CMN_REG(006c), &val);
 	if (ret)
@@ -2273,7 +2283,7 @@ static u64 rk_hdptx_phy_clk_calc_rate_from_pll_cfg(struct rk_hdptx_phy *hdptx)
 	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;
+	ropll_hw.pms_sdiv = FIELD_GET(PLL_PCG_POSTDIV_SEL_MASK, val) + 1;
 	bpc = (FIELD_GET(PLL_PCG_CLK_SEL_MASK, val) << 1) + 8;
 
 	fout = PLL_REF_CLK * ropll_hw.pms_mdiv;

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:45:26 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:45:26 +0300
Subject: [PATCH v4 7/8] phy: rockchip: samsung-hdptx: Simplify GRF access
 with FIELD_PREP_WM16()
In-Reply-To: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
References: <20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda@collabora.com>
Message-ID: <20260612-hdptx-clk-fixes-v4-7-ce5e1d456cda@collabora.com>

The 16 most significant bits of the general-purpose register (GRF) are
used as a write-enable mask for the remaining 16 bits.

Make use of the recently introduced FIELD_PREP_WM16() macro to avoid
open-coding the bit shift operations and improve code readability.

Tested-by: Thomas Niederpr?m <dubito at online.de>
Tested-by: Simon Wright <simon at symple.nz>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 52 +++++++++++------------
 1 file changed, 25 insertions(+), 27 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index b74a433c7e53..88b48f5f946d 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
- * Copyright (c) 2024 Collabora Ltd.
+ * Copyright (c) 2024-2026 Collabora Ltd.
  *
  * Author: Algea Cao <algea.cao at rock-chips.com>
  * Author: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/delay.h>
+#include <linux/hw_bitfield.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -949,7 +950,9 @@ static void rk_hdptx_pre_power_up(struct rk_hdptx_phy *hdptx)
 	reset_control_assert(hdptx->rsts[RST_CMN].rstc);
 	reset_control_assert(hdptx->rsts[RST_INIT].rstc);
 
-	val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16;
+	val = (FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 }
 
@@ -960,8 +963,8 @@ static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx)
 
 	reset_control_deassert(hdptx->rsts[RST_LANE].rstc);
 
-	val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 |
-	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
+	val = (FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
 	/* 3 lanes FRL mode */
@@ -990,16 +993,15 @@ static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx)
 	u32 val;
 	int ret;
 
-	val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 |
-	       HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN;
+	val = (FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 
 	usleep_range(10, 15);
 	reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
 
 	usleep_range(10, 15);
-	val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN;
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 1));
 
 	usleep_range(10, 15);
 	reset_control_deassert(hdptx->rsts[RST_CMN].rstc);
@@ -1037,7 +1039,9 @@ static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx)
 	reset_control_assert(hdptx->rsts[RST_CMN].rstc);
 	reset_control_assert(hdptx->rsts[RST_INIT].rstc);
 
-	val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16;
+	val = (FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+	       FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0, val);
 }
 
@@ -1135,7 +1139,7 @@ static int rk_hdptx_frl_lcpll_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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 0));
 
 	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);
@@ -1178,8 +1182,7 @@ static int rk_hdptx_frl_lcpll_ropll_cmn_config(struct rk_hdptx_phy *hdptx)
 	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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 1));
 
 	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);
@@ -1218,7 +1221,7 @@ 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);
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(LC_REF_CLK_SEL, 0));
 
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_common_cmn_init_seq);
 	rk_hdptx_multi_reg_write(hdptx, rk_hdptx_tmds_cmn_init_seq);
@@ -1336,11 +1339,9 @@ static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
 			   FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
 
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x0));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0));
+		     FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0) |
+		     FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 0) |
+		     FIELD_PREP_WM16(HDPTX_I_BGR_EN, 0));
 }
 
 static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx)
@@ -1616,9 +1617,8 @@ static int rk_hdptx_dp_aux_init(struct rk_hdptx_phy *hdptx)
 			   FIELD_PREP(OVRD_SB_VREG_EN_MASK, 0x1));
 
 	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x1));
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x1));
+		     FIELD_PREP_WM16(HDPTX_I_BGR_EN, 1) |
+		     FIELD_PREP_WM16(HDPTX_I_BIAS_EN, 1));
 	usleep_range(20, 25);
 
 	reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
@@ -1665,7 +1665,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 
 	if (mode == PHY_MODE_DP) {
 		regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-			     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x1));
+			     FIELD_PREP_WM16(HDPTX_MODE_SEL, 1));
 
 		for (lane = 0; lane < 4; lane++) {
 			regmap_update_bits(hdptx->regmap, LANE_REG(031e) + 0x400 * lane,
@@ -1693,7 +1693,7 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
 
 		if (!ret) {
 			regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-				     HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+				     FIELD_PREP_WM16(HDPTX_MODE_SEL, 0));
 
 			if (hdptx->hdmi_cfg.mode == PHY_HDMI_MODE_FRL)
 				ret = rk_hdptx_frl_lcpll_mode_config(hdptx);
@@ -1828,8 +1828,7 @@ static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx,
 	u32 bw, status;
 	int ret;
 
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 0));
 
 	switch (dp->link_rate) {
 	case 1620:
@@ -1885,8 +1884,7 @@ static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx,
 	regmap_update_bits(hdptx->regmap, CMN_REG(0095), DP_TX_LINK_BW_MASK,
 			   FIELD_PREP(DP_TX_LINK_BW_MASK, bw));
 
-	regmap_write(hdptx->grf, GRF_HDPTX_CON0,
-		     HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x1));
+	regmap_write(hdptx->grf, GRF_HDPTX_CON0, FIELD_PREP_WM16(HDPTX_I_PLL_EN, 1));
 
 	ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS,
 				       status, FIELD_GET(HDPTX_O_PLL_LOCK_DONE, status),

-- 
2.54.0



From cristian.ciocaltea at collabora.com  Thu Jun 11 16:58:18 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 02:58:18 +0300
Subject: [PATCH v3 0/6] phy: rockchip: samsung-hdptx: Clock fixes and API
 transition cleanups
In-Reply-To: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
References: <20260611-hdptx-clk-fixes-v3-0-67b1b0c00e16@collabora.com>
Message-ID: <25f0a87d-0607-49eb-b297-b45c11b4df1b@collabora.com>

Hi,

On 6/11/26 3:31 PM, Cristian Ciocaltea wrote:
> This series provides a set of bug fixes and cleanups for the Rockchip
> Samsung HDPTX PHY driver.
> 
> The first part of the series (i.e. PATCH 1 & 2) addresses clock rate
> calculation and synchronization issues.  Specifically, it fixes edge
> cases where the PHY PLL is pre-programmed by an external component (like
> a bootloader) or when changing the color depth (bpc) while keeping the
> modeline constant.  Because the Common Clock Framework .set_rate()
> callback might not be invoked if the pixel clock remains unchanged, this
> previously led to out-of-sync states between CCF and the actual HDMI PHY
> configuration.
> 
> The second part focuses on code cleanups and modernizing the register
> access.  Now that dw_hdmi_qp driver has fully switched to using
> phy_configure(), we can drop the deprecated TMDS rate setup workarounds
> and the restrict_rate_change flag logic.  Finally, it refactors the
> driver to consistently use standard bitfield macros.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
> Changes in v3:
> - Replaced div_u64() with DIV_ROUND_CLOSEST_ULL() in Patch 1 (Sashiko)
> - Fixed theoretical usage_count unbalanced issue in Patch 2 (Sashiko)
> - Rebased series onto latest phy/next
> - Link to v2: https://patch.msgid.link/20260511-hdptx-clk-fixes-v2-0-664e41379cab at collabora.com
Please use v4 as I added two more patches to address latest findings from Sashiko:

https://lore.kernel.org/all/20260612-hdptx-clk-fixes-v4-0-ce5e1d456cda at collabora.com/

Thanks,
Cristian


From mripard at kernel.org  Fri Jun 12 01:52:38 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Jun 2026 10:52:38 +0200
Subject: [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0
 scrambler callbacks
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-11-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-11-445eb54ee1ed@collabora.com>
Message-ID: <20260612-attractive-dashing-mule-309598@houat>

On Tue, Jun 02, 2026 at 01:44:11AM +0300, Cristian Ciocaltea wrote:
> Connect the bridge connector's .scrambler_{enable|disable} callbacks to
> the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
> DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.
> 
> This completes the bridge connector plumbing so that the SCDC
> scrambling helpers can control source-side scrambling through the
> bridge chain.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
>  drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
>  1 file changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
> index 9d21b1b57b0d..d048ab49eade 100644
> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
> @@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
>  	return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
>  }
>  
> +static int drm_bridge_connector_scrambler_enable(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_scrambler_enable(bridge);
> +}
> +
> +static int drm_bridge_connector_scrambler_disable(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_scrambler_disable(bridge);
> +}
> +
>  static const struct drm_edid *
>  drm_bridge_connector_read_edid(struct drm_connector *connector)
>  {
> @@ -580,7 +606,7 @@ 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, hdr_drm and spd are set dynamically during init */
> +	/* scrambler, audio, hdr_drm and spd are set dynamically during init */
>  };
>  
>  static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
> @@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>  			     !bridge->funcs->hdmi_clear_spd_infoframe))
>  				return ERR_PTR(-EINVAL);
>  
> +			if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
> +			    (!bridge->funcs->hdmi_scrambler_enable ||
> +			     !bridge->funcs->hdmi_scrambler_disable))
> +				return ERR_PTR(-EINVAL);
> +
>  			bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
>  
>  			if (bridge->supported_formats)
> @@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>  			bridge_connector->hdmi_funcs.spd =
>  				drm_bridge_connector_hdmi_spd_infoframe;
>  
> +		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
> +			bridge_connector->hdmi_funcs.scrambler_enable =
> +				drm_bridge_connector_scrambler_enable;
> +			bridge_connector->hdmi_funcs.scrambler_disable =
> +				drm_bridge_connector_scrambler_disable;
> +			connector->hdmi.scrambler_supported = true;
> +		}
> +

I think we're taking this backwards. The scrambler support isn't
optional: either the controller supports HDMI < 2.0, and then it doesn't
exist, or it supports >= 2.0 and then it's mandatory.

You're considering it optional here, when it's never actually optional
(unlike YUV420 for example)

I still think we should list, somehow, the capabilities of the
controller to the helpers, like max tmds rate supported, formats, etc.
We've so far put everything as an argument to drmm_connector_hdmi_init
but it becomes a bit overloaded, and I wonder if introducing a callback
wouldn't solve this, kind of like what we have for planes and formats.

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-rockchip/attachments/20260612/d1550f89/attachment.sig>

From cristian.ciocaltea at collabora.com  Fri Jun 12 03:01:29 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 13:01:29 +0300
Subject: [PATCH v2] MAINTAINERS: Track dw-hdmi-qp under Rockchip DRM
 drivers
Message-ID: <20260612-maintainers-rk-drm-upd-v2-1-3ff65fc41a93@collabora.com>

The DW HDMI QP TX library was developed for and is currently only used
by Rockchip platforms.  Add it to the Rockchip DRM drivers section to
ensure all relevant parties are kept in the loop on any changes.

As its file paths fall outside the generic wildcard patterns defined in
the ARM/Rockchip SoC support section, also add the
linux-rockchip at lists.infradead.org mailing list to avoid any
notification gaps.

Acked-by: Andy Yan <andy.yan at rock-chips.com>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
---
Changes in v2:
- Collected Acked-by from Andy
- Removed the RFC prefix
- Rebased onto next-20260611
- Link to v1: https://patch.msgid.link/20260506-maintainers-rk-drm-upd-v1-1-f67537b4bb29 at collabora.com
---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index f1caa6e5198b..ac68fdd9879e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8849,11 +8849,14 @@ M:	Sandy Huang <hjc at rock-chips.com>
 M:	Heiko St?bner <heiko at sntech.de>
 M:	Andy Yan <andy.yan at rock-chips.com>
 L:	dri-devel at lists.freedesktop.org
+L:	linux-rockchip at lists.infradead.org
 S:	Maintained
 T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
 F:	Documentation/devicetree/bindings/display/rockchip/
+F:	drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.*
 F:	drivers/gpu/drm/ci/xfails/rockchip*
 F:	drivers/gpu/drm/rockchip/
+F:	include/drm/bridge/dw_hdmi_qp.h
 
 DRM DRIVERS FOR STI
 M:	Alain Volmat <alain.volmat at foss.st.com>

---
base-commit: ec039126b7fac4e3af35ebccaa7c6f9b6875ba81
change-id: 20260506-maintainers-rk-drm-upd-c463f6b04769



From jic23 at kernel.org  Fri Jun 12 03:42:30 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Fri, 12 Jun 2026 11:42:30 +0100
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <PH0PR19MB997338CE11110E16E7FB668E3BA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
	<20260610175455.19006-4-macroalpha82@gmail.com>
	<20260611120943.7119975b@jic23-huawei>
	<PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
	<20260611172022.4d138820@jic23-huawei>
	<PH0PR19MB997338CE11110E16E7FB668E3BA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <20260612114230.0fd2f391@jic23-huawei>

On Thu, 11 Jun 2026 11:31:09 -0500
Chris Morgan <macromorgan at hotmail.com> wrote:

> On Thu, Jun 11, 2026 at 05:20:22PM +0100, Jonathan Cameron wrote:
> > On Thu, 11 Jun 2026 09:32:38 -0500
> > Chris Morgan <macromorgan at hotmail.com> wrote:
> >   
> > > On Thu, Jun 11, 2026 at 12:09:43PM +0100, Jonathan Cameron wrote:  
> > > > On Wed, 10 Jun 2026 12:54:47 -0500
> > > > Chris Morgan <macroalpha82 at gmail.com> wrote:
> > > >     
> > > > > From: Chris Morgan <macromorgan at hotmail.com>
> > > > > 
> > > > > Add the core component of a new inv_icm42607 driver. This includes
> > > > > a few setup functions and the full register definition in the
> > > > > header file.
> > > > > 
> > > > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>    
> > > > Hi Chris,
> > > > 
> > > > A couple more minor things from a fresh read.
> > > > 
> > > > Thanks
> > > > 
> > > > Jonathan
> > > >     
> > > > > ---
> > > > >  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
> > > > >  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
> > > > >  2 files changed, 531 insertions(+)
> > > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > > 
> > > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > > > new file mode 100644
> > > > > index 000000000000..716fc0f1c3fd
> > > > > --- /dev/null
> > > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h    
> > > >     
> > > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > > new file mode 100644
> > > > > index 000000000000..334264120b42
> > > > > --- /dev/null
> > > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c    
> > > >     
> > > > > +
> > > > > +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> > > > > +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> > > > > +{
> > > > > +	const struct device *dev = regmap_get_device(st->map);
> > > > > +	unsigned int val;
> > > > > +	int ret;
> > > > > +
> > > > > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	/* Warn, but don't fail. */
> > > > > +	if (val != st->hw->whoami)
> > > > > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > > > > +			 val, st->hw->whoami, st->hw->name);
> > > > > +
> > > > > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > > > > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > > > > +
> > > > > +	/*
> > > > > +	 * No polling interval specified in datasheet, so use reset time as
> > > > > +	 * polling interval and 10x reset time as timeout period.
> > > > > +	 */
> > > > > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > > > > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> > > > > +	if (ret)
> > > > > +		return dev_err_probe(dev, ret,
> > > > > +				     "reset error, reset done bit not set\n");
> > > > > +
> > > > > +	/* Sync the regcache again after a reset. */
> > > > > +	regcache_mark_dirty(st->map);
> > > > > +	ret = regcache_sync(st->map);    
> > > > 
> > > > Sashiko raised the point that you don't have a writeable register list for the regmap
> > > > and so potentially we at very least write a bunch of stuff that isn't needed.
> > > > I doubt it's actually a problem or you would have seen it, but nice little optimization
> > > > to reduce what is written.    
> > > 
> > > I will add such a list, I'd put it in patch 4 unless you think I should
> > > merge patch 3 and 4 to make the driver compileable at the first commit
> > > of code (will push the number of lines to the ~850/900 range though).
> > >   
> > I'm fine with them split but don't mind if Andy prefers them combined.
> > His comment on adding a COMPILE_TEST option would allow that to be
> > built, but it is a bit odd to do it just for that purpose.
> > 
> > Jonathan
> >   
> 
> I'm going to add the i2c stuff to this series, and then do the SPI
> on the next patch. That should add only a little bit to this one but
> still ensure the very first (code) commit has something to compile.
> I'm going to avoid doing COMPILE_TEST unless collectively you all
> think I should.
> 
> I'm still racing to try and get this one done before the merge
> window opens up, but I'm pretty sure it's already too late at
> this point. I'll refrain from submitting updates once the window opens
> though.
Unfortunately you are correct. IIO in practice closes around 10 days before
the merge window to give time to both expose new things to testing in linux-next
and to allow time for Greg KH to merge my pull request into char-misc (which
is the path IIO takes to upstream)

Sorry about that, and whilst no need to rush as a result, we also don't
stop merging IIO stuff in the merge window, it just sits in the testing
branch until I can rebase that on rc1 and then push it out for linux-next
to pick up.

Thanks,

Jonathan
> 
> Thank you,
> Chris
> 



From mripard at kernel.org  Fri Jun 12 05:04:07 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Jun 2026 14:04:07 +0200
Subject: [PATCH v7 25/30] drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC
 scrambling helpers
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-25-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-25-445eb54ee1ed@collabora.com>
Message-ID: <20260612-primitive-chital-of-tempering-18bc7c@houat>

Hi,

On Tue, Jun 02, 2026 at 01:44:25AM +0300, Cristian Ciocaltea wrote:
> Replace the vc4-local scrambling implementation with the newly
> introduced DRM common SCDC scrambling infrastructure:
> 
> - Advertise source-side scrambling support by setting
>   connector->hdmi.scrambling_supported based on the variant's
>   max_pixel_clock before drmm_connector_hdmi_init().
> 
> - Provide minimal .scrambler_{enable|disable} connector callbacks that
>   only toggle the VC5 HDMI_SCRAMBLER_CTL register.  Sink-side SCDC
>   programming and periodic status monitoring are now delegated to
>   drm_scdc_{start|stop}_scrambling().
> 
> - Replace vc4_hdmi_enable_scrambling() with a conditional call to
>   drm_scdc_start_scrambling() in post_crtc_enable, gated on
>   conn_state->hdmi.scrambler_needed (computed by the HDMI state helper).
> 
> - Replace vc4_hdmi_disable_scrambling() with drm_scdc_stop_scrambling()
>   in post_crtc_disable.
> 
> - Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
>   the .detect_ctx() path to
>   drm_atomic_helper_connector_hdmi_hotplug_ctx() which internally calls
>   drm_scdc_sync_status() to trigger a CRTC reset on reconnection.
> 
> - Drop the local scrambling_work delayed workqueue and scdc_enabled
>   flag, now tracked by the common drm_connector_hdmi layer.
> 
> - Drop vc4_hdmi_supports_scrambling() and
>   vc4_hdmi_mode_needs_scrambling() helpers, inlining the remaining 4KP60
>   warning with an explicit drm_hdmi_compute_mode_clock() check.
> 
> - Seed connector->hdmi.scrambler_enabled = true in connector_init() to
>   ensure drm_scdc_stop_scrambling() runs at boot and disables any stale
>   scrambling state left by the bootloader.
> 
> No functional change is expected for the supported modes.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

I'd really like it to be broken down into several patches:

> ---
>  drivers/gpu/drm/vc4/vc4_hdmi.c | 265 ++++++-----------------------------------
>  drivers/gpu/drm/vc4/vc4_hdmi.h |   8 --
>  2 files changed, 35 insertions(+), 238 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> index 046ac4f43ba8..02f6ca6ab52b 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> @@ -114,31 +114,6 @@
>  #define HSM_MIN_CLOCK_FREQ	120000000
>  #define CEC_CLOCK_FREQ 40000
>  
> -static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
> -{
> -	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
> -
> -	lockdep_assert_held(&vc4_hdmi->mutex);
> -
> -	if (!display->is_hdmi)
> -		return false;
> -
> -	if (!display->hdmi.scdc.supported ||
> -	    !display->hdmi.scdc.scrambling.supported)
> -		return false;
> -
> -	return true;
> -}
> -
> -static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
> -					   unsigned int bpc,
> -					   enum drm_output_color_format fmt)
> -{
> -	unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
> -
> -	return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
> -}
> -
>  static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
>  {
>  	struct drm_debugfs_entry *entry = m->private;
> @@ -272,124 +247,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
>  static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
>  #endif
>  
> -static int vc4_hdmi_reset_link(struct drm_connector *connector,
> -			       struct drm_modeset_acquire_ctx *ctx)
> -{
> -	struct drm_device *drm;
> -	struct vc4_hdmi *vc4_hdmi;
> -	struct drm_connector_state *conn_state;
> -	struct drm_crtc_state *crtc_state;
> -	struct drm_crtc *crtc;
> -	bool scrambling_needed;
> -	u8 config;
> -	int ret;
> -
> -	if (!connector)
> -		return 0;
> -
> -	drm = connector->dev;
> -	ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
> -	if (ret)
> -		return ret;
> -
> -	conn_state = connector->state;
> -	crtc = conn_state->crtc;
> -	if (!crtc)
> -		return 0;
> -
> -	ret = drm_modeset_lock(&crtc->mutex, ctx);
> -	if (ret)
> -		return ret;
> -
> -	crtc_state = crtc->state;
> -	if (!crtc_state->active)
> -		return 0;
> -
> -	vc4_hdmi = connector_to_vc4_hdmi(connector);
> -	mutex_lock(&vc4_hdmi->mutex);
> -
> -	if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
> -		mutex_unlock(&vc4_hdmi->mutex);
> -		return 0;
> -	}
> -
> -	scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
> -							   vc4_hdmi->output_bpc,
> -							   vc4_hdmi->output_format);
> -	if (!scrambling_needed) {
> -		mutex_unlock(&vc4_hdmi->mutex);
> -		return 0;
> -	}
> -
> -	if (conn_state->commit &&
> -	    !try_wait_for_completion(&conn_state->commit->hw_done)) {
> -		mutex_unlock(&vc4_hdmi->mutex);
> -		return 0;
> -	}
> -
> -	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
> -	if (ret < 0) {
> -		drm_err(drm, "Failed to read TMDS config: %d\n", ret);
> -		mutex_unlock(&vc4_hdmi->mutex);
> -		return 0;
> -	}
> -
> -	if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
> -		mutex_unlock(&vc4_hdmi->mutex);
> -		return 0;
> -	}
> -
> -	mutex_unlock(&vc4_hdmi->mutex);
> -
> -	/*
> -	 * HDMI 2.0 says that one should not send scrambled data
> -	 * prior to configuring the sink scrambling, and that
> -	 * TMDS clock/data transmission should be suspended when
> -	 * changing the TMDS clock rate in the sink. So let's
> -	 * just do a full modeset here, even though some sinks
> -	 * would be perfectly happy if were to just reconfigure
> -	 * the SCDC settings on the fly.
> -	 */
> -	return drm_atomic_helper_reset_crtc(crtc, ctx);
> -}

This one doesn't look functionally equivalent to me to
drm_scdc_reset_crtc: this part was, in part, making sure we would only
reset the scrambler if it was enabled in the first place.
drm_scdc_reset_crtc() doesn't and will always trigger a modeset on
hotplug. That's unnecessary and a significant functional different.

I'd argue that it's drm_scdc_reset_crtc() that needs to align to what
vc4 was doing, not the opposite.

> -static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
> -				    struct drm_modeset_acquire_ctx *ctx,
> -				    enum drm_connector_status status)
> -{
> -	struct drm_connector *connector = &vc4_hdmi->connector;
> -	int ret;
> -
> -	/*
> -	 * NOTE: This function should really be called with vc4_hdmi->mutex
> -	 * held, but doing so results in reentrancy issues since
> -	 * cec_s_phys_addr() might call .adap_enable, which leads to that
> -	 * funtion being called with our mutex held.
> -	 *
> -	 * A similar situation occurs with vc4_hdmi_reset_link() that
> -	 * will call into our KMS hooks if the scrambling was enabled.
> -	 *
> -	 * Concurrency isn't an issue at the moment since we don't share
> -	 * any state with any of the other frameworks so we can ignore
> -	 * the lock for now.
> -	 */
> -
> -	drm_atomic_helper_connector_hdmi_hotplug(connector, status);
> -
> -	if (status != connector_status_connected)
> -		return;
> -
> -	for (;;) {
> -		ret = vc4_hdmi_reset_link(connector, ctx);
> -		if (ret == -EDEADLK) {
> -			drm_modeset_backoff(ctx);
> -			continue;
> -		}
> -
> -		break;
> -	}
> -}
> -
>  static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>  					 struct drm_modeset_acquire_ctx *ctx,
>  					 bool force)
> @@ -401,8 +258,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>  	/*
>  	 * NOTE: This function should really take vc4_hdmi->mutex, but
>  	 * doing so results in reentrancy issues since
> -	 * vc4_hdmi_handle_hotplug() can call into other functions that
> -	 * would take the mutex while it's held here.
> +	 * drm_atomic_helper_connector_hdmi_hotplug_ctx() can call into other
> +	 * functions that would take the mutex while it's held here.
>  	 *
>  	 * Concurrency isn't an issue at the moment since we don't share
>  	 * any state with any of the other frameworks so we can ignore
> @@ -425,10 +282,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>  			status = connector_status_connected;
>  	}
>  
> -	vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
> +	ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector, status, ctx);
> +
>  	pm_runtime_put(&vc4_hdmi->pdev->dev);
>  
> -	return status;
> +	return ret == -EDEADLK ? ret : status;
>  }
>  
>  static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
> @@ -441,9 +299,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
>  	if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
>  		struct drm_device *drm = connector->dev;
>  		const struct drm_display_mode *mode;
> +		unsigned long long clock;
>  
>  		list_for_each_entry(mode, &connector->probed_modes, head) {
> -			if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
> +			clock = drm_hdmi_compute_mode_clock(mode, 8,
> +							    DRM_OUTPUT_COLOR_FORMAT_RGB444);
> +			if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {

This should be a patch of its own, but I think we should turn
vc4_hdmi_mode_needs_scrambling() into a helper, instead of checking the
clock rate in every driver that might need it. From a logical standpoint
it's equivalent, but not from a semantic one.

>  				drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
>  				drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
>  			}
> @@ -540,6 +401,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
>  	if (vc4_hdmi->variant->supports_hdr)
>  		max_bpc = 12;
>  
> +	connector->hdmi.scrambler_supported =
> +		vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
> +
>  	ret = drmm_connector_hdmi_init(dev, connector,
>  				       "Broadcom", "Videocore",
>  				       &vc4_hdmi_connector_funcs,
> @@ -561,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
>  
>  	drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
>  
> +	/*
> +	 * Since we don't know the state of the controller and its
> +	 * display (if any), let's assume it's always enabled.
> +	 * drm_scdc_stop_scrambling() will thus run at boot, make
> +	 * sure it's disabled, and avoid any inconsistency.
> +	 */
> +	connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
> +
>  	/*
>  	 * Some of the properties below require access to state, like bpc.
>  	 * Allocate some default initial connector state with our reset helper.
> @@ -786,93 +658,30 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
>  					buffer, len);
>  }
>  
> -#define SCRAMBLING_POLLING_DELAY_MS	1000
> -
> -static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
> +static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
>  {
> -	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> -	struct drm_connector *connector = &vc4_hdmi->connector;
> -	struct drm_device *drm = connector->dev;
> -	const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
> +	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
>  	unsigned long flags;
> -	int idx;
> -
> -	lockdep_assert_held(&vc4_hdmi->mutex);
> -
> -	if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
> -		return;
> -
> -	if (!vc4_hdmi_mode_needs_scrambling(mode,
> -					    vc4_hdmi->output_bpc,
> -					    vc4_hdmi->output_format))
> -		return;
> -
> -	if (!drm_dev_enter(drm, &idx))
> -		return;

drm_dev_enter should be kept here

> -	drm_scdc_set_high_tmds_clock_ratio(connector, true);
> -	drm_scdc_set_scrambling(connector, true);
>  
>  	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
>  	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
>  		   VC5_HDMI_SCRAMBLER_CTL_ENABLE);
>  	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>  
> -	drm_dev_exit(idx);

And exit here.

> -static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
> +static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
>  {
> -	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
> -	struct drm_connector *connector = &vc4_hdmi->connector;
> -	struct drm_device *drm = connector->dev;
> +	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
>  	unsigned long flags;
> -	int idx;
> -
> -	lockdep_assert_held(&vc4_hdmi->mutex);
> -
> -	if (!vc4_hdmi->scdc_enabled)
> -		return;
> -
> -	vc4_hdmi->scdc_enabled = false;
> -
> -	if (delayed_work_pending(&vc4_hdmi->scrambling_work))
> -		cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
> -
> -	if (!drm_dev_enter(drm, &idx))
> -		return;

Ditto

>  	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
>  	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
>  		   ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
>  	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>  
> -	drm_scdc_set_scrambling(connector, false);
> -	drm_scdc_set_high_tmds_clock_ratio(connector, false);
> -
> -	drm_dev_exit(idx);
> -}
> -
> -static void vc4_hdmi_scrambling_wq(struct work_struct *work)
> -{
> -	struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
> -						 struct vc4_hdmi,
> -						 scrambling_work);
> -	struct drm_connector *connector = &vc4_hdmi->connector;
> -
> -	if (drm_scdc_get_scrambling_status(connector))
> -		return;
> -
> -	drm_scdc_set_high_tmds_clock_ratio(connector, true);
> -	drm_scdc_set_scrambling(connector, true);
> -
> -	queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
> -			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
> +	return 0;
>  }
>  
>  static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
> @@ -917,7 +726,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
>  		spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>  	}
>  
> -	vc4_hdmi_disable_scrambling(encoder);
> +	drm_scdc_stop_scrambling(&vc4_hdmi->connector);

I don't think the names here are right. It's not *only* related to scdc
but also to the HDMI controller. I'm fine with using a scdc prefix but
only for the things related to scdc. This is related (in part) to the
HDMI controller, so it should use a drm_connector_hdmi prefix.

>  	drm_dev_exit(idx);
>  
> @@ -1625,6 +1434,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
>  	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
>  	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
>  	bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
> +	struct drm_connector_state *conn_state;
>  	unsigned long flags;
>  	int ret;
>  	int idx;
> @@ -1693,7 +1503,10 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
>  	}
>  
>  	vc4_hdmi_recenter_fifo(vc4_hdmi);
> -	vc4_hdmi_enable_scrambling(encoder);
> +
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +	if (conn_state && conn_state->hdmi.scrambler_needed)
> +		drm_scdc_start_scrambling(connector);

And the nice thing with a drm_connector_hdmi_* prefix is that you don't
have to shoehorn it into SCDC support anymore, so you can take a state
as an argument, and do the check in the helper instead of doing it in
every driver and hoping they get it right.

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-rockchip/attachments/20260612/c5cf019c/attachment.sig>

From mripard at kernel.org  Fri Jun 12 05:06:29 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Jun 2026 14:06:29 +0200
Subject: [PATCH v7 02/30] drm/connector: Add HDMI 2.0 scrambler
 infrastructure
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-2-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-2-445eb54ee1ed@collabora.com>
Message-ID: <20260612-subtle-shapeless-rattlesnake-4b6af8@houat>

On Tue, Jun 02, 2026 at 01:44:02AM +0300, Cristian Ciocaltea wrote:
> Add the connector-level infrastructure to support HDMI 2.0 scrambling:
> 
> - A scrambler_supported flag to indicate whether the source supports the
>   scrambling capability, in which case the newly introduced
>   .scrambler_{enable|disable}() callbacks in drm_connector_hdmi_funcs
>   are mandatory
> - A scrambler_needed flag to be managed by the hdmi state helpers based
>   on the negotiated TMDS character rate and the source/sink scrambling
>   capabilities
> - A scrambler_enabled flag to track whether scrambling is currently
>   active
> - A delayed work item (scdc_work) with an associated callback (scdc_cb)
>   to monitor sink-side scrambling status and retry the setup if the sink
>   resets it
> 
> These are intended to be used by SCDC scrambling helpers to coordinate
> scrambling setup and teardown between the source driver and the DRM
> core.
> 
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> ---
>  drivers/gpu/drm/drm_connector.c | 18 +++++++++
>  include/drm/drm_connector.h     | 81 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 99 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index a5d13b92b665..526dc2931b8a 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
>  	}
>  }
>  
> +static void drm_connector_hdmi_scdc_work(struct work_struct *work)
> +{
> +	struct drm_connector *connector;
> +	struct drm_connector_hdmi *hdmi;
> +
> +	hdmi = container_of(to_delayed_work(work), struct drm_connector_hdmi,
> +			    scdc_work);
> +	connector = container_of(hdmi, struct drm_connector, hdmi);
> +
> +	if (hdmi->scdc_cb)
> +		hdmi->scdc_cb(connector);
> +}
> +
>  static int drm_connector_init_only(struct drm_device *dev,
>  				   struct drm_connector *connector,
>  				   const struct drm_connector_funcs *funcs,
> @@ -285,6 +298,7 @@ static int drm_connector_init_only(struct drm_device *dev,
>  	mutex_init(&connector->edid_override_mutex);
>  	mutex_init(&connector->hdmi.infoframes.lock);
>  	mutex_init(&connector->hdmi_audio.lock);
> +	INIT_DELAYED_WORK(&connector->hdmi.scdc_work, drm_connector_hdmi_scdc_work);
>  	connector->edid_blob_ptr = NULL;
>  	connector->epoch_counter = 0;
>  	connector->tile_blob_ptr = NULL;
> @@ -606,6 +620,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>  	    !hdmi_funcs->hdmi.write_infoframe)
>  		return -EINVAL;
>  
> +	if (connector->hdmi.scrambler_supported &&
> +	    (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable))
> +		return -EINVAL;
> +
>  	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
>  	if (ret)
>  		return ret;
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 529755c2e862..f1c5c15a6cce 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -28,6 +28,7 @@
>  #include <linux/ctype.h>
>  #include <linux/hdmi.h>
>  #include <linux/notifier.h>
> +#include <linux/workqueue.h>
>  #include <drm/drm_mode_object.h>
>  #include <drm/drm_util.h>
>  #include <drm/drm_property.h>
> @@ -1057,6 +1058,19 @@ struct drm_connector_hdmi_state {
>  	 * @tmds_char_rate: TMDS Character Rate, in Hz.
>  	 */
>  	unsigned long long tmds_char_rate;
> +
> +	/**
> +	 * @scrambler_needed: Whether HDMI 2.0 SCDC scrambling is required
> +	 * for the negotiated mode/bpc/format.
> +	 *
> +	 * Computed by drm_atomic_helper_connector_hdmi_check() from
> +	 * @tmds_char_rate and the source/sink scrambling capabilities.
> +	 *
> +	 * Per HDMI 2.0, scrambling is mandatory above 340 MHz TMDS
> +	 * character rate. Optional scrambling at lower rates is
> +	 * deliberately not requested by the helper.
> +	 */
> +	bool scrambler_needed;
>  };
>  
>  /**
> @@ -1358,6 +1372,36 @@ struct drm_connector_hdmi_funcs {
>  	 */
>  	const struct drm_edid *(*read_edid)(struct drm_connector *connector);
>  
> +	/**
> +	 * @scrambler_enable:
> +	 *
> +	 * This callback is invoked through @drm_scdc_start_scrambling during
> +	 * a commit to setup SCDC scrambling and high TMDS clock ratio on
> +	 * source side.
> +	 *
> +	 * The @scrambler_enable callback is mandatory if HDMI 2.0 is to be
> +	 * supported.
> +	 *
> +	 * Returns:
> +	 * 0 on success, a negative error code otherwise
> +	 */
> +	int (*scrambler_enable)(struct drm_connector *connector);
> +
> +	/**
> +	 * @scrambler_disable:
> +	 *
> +	 * This callback is invoked through @drm_scdc_stop_scrambling during
> +	 * a commit to disable SCDC scrambling and high TMDS clock ratio on
> +	 * source side.
> +	 *
> +	 * The @scrambler_disable callback is mandatory if HDMI 2.0 is to be
> +	 * supported.
> +	 *
> +	 * Returns:
> +	 * 0 on success, a negative error code otherwise
> +	 */
> +	int (*scrambler_disable)(struct drm_connector *connector);
> +
>  	/**
>  	 * @avi:
>  	 *
> @@ -1960,6 +2004,43 @@ struct drm_connector_hdmi {
>  	 */
>  	unsigned long supported_formats;
>  
> +	/**
> +	 * @scrambler_supported: Indicates whether the HDMI controller
> +	 * (source) supports HDMI 2.0 SCDC scrambling.
> +	 *
> +	 * When true, @drm_connector_hdmi_funcs.scrambler_enable and
> +	 * @drm_connector_hdmi_funcs.scrambler_disable are mandatory.
> +	 * This is enforced by drmm_connector_hdmi_init().
> +	 *
> +	 * For HDMI bridge based drivers using drm_bridge_connector_init(),
> +	 * this is propagated automatically from bridges that set the
> +	 * DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
> +	 * Other drivers must set this field on @connector->hdmi before calling
> +	 * drmm_connector_hdmi_init().
> +	 */
> +	bool scrambler_supported;
> +
> +	/**
> +	 * @scrambler_enabled: Tracks whether HDMI 2.0 scrambler is currently enabled.
> +	 */
> +	bool scrambler_enabled;

This is already in the state. Why do you need to copy it over here, and
if you do, you'll need a lock.

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-rockchip/attachments/20260612/2bfe408a/attachment-0001.sig>

From mripard at kernel.org  Fri Jun 12 06:43:06 2026
From: mripard at kernel.org (Maxime Ripard)
Date: Fri, 12 Jun 2026 15:43:06 +0200
Subject: [PATCH v7 04/30] drm/display: scdc_helper: Add HDMI 2.0
 scrambling management helpers
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-4-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-4-445eb54ee1ed@collabora.com>
Message-ID: <20260612-cordial-steadfast-cow-fcaf01@houat>

On Tue, Jun 02, 2026 at 01:44:04AM +0300, Cristian Ciocaltea wrote:
> +/**
> + * drm_scdc_start_scrambling - activate scrambling and monitor SCDC status
> + * @connector: connector
> + *
> + * Enables scrambling and high TMDS clock ratio on both source and sink sides.
> + * Additionally, use a delayed work item to monitor the scrambling status on
> + * the sink side and retry the operation, as some displays refuse to set the
> + * scrambling bit right away.
> + *
> + * Returns:
> + * Zero if scrambling is set successfully, an error code otherwise.
> + */
> +int drm_scdc_start_scrambling(struct drm_connector *connector)
> +{
> +	struct drm_display_info *info = &connector->display_info;
> +	struct drm_connector_hdmi *hdmi = &connector->hdmi;
> +	int ret;
> +	u8 ver;
> +
> +	if (!hdmi->scrambler_supported) {
> +		drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!info->is_hdmi ||
> +	    !info->hdmi.scdc.supported ||
> +	    !info->hdmi.scdc.scrambling.supported) {
> +		drm_scdc_dbg(connector, "Sink doesn't support scrambling.\n");
> +		return -EINVAL;
> +	}
> +
> +	drm_scdc_dbg(connector, "Enabling scrambling\n");
> +
> +	ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &ver);
> +	if (ret) {
> +		drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
> +			      min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
> +	if (ret) {
> +		drm_scdc_dbg(connector, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
> +		return ret;
> +	}
> +
> +	hdmi->scdc_cb = drm_scdc_monitor_scrambler;
> +	WRITE_ONCE(hdmi->scrambler_enabled, true);
> +
> +	ret = drm_scdc_try_scrambling_setup(connector);
> +	if (!ret)
> +		ret = hdmi->funcs->scrambler_enable(connector);
> +
> +	if (ret) {
> +		WRITE_ONCE(hdmi->scrambler_enabled, false);
> +		cancel_delayed_work_sync(&hdmi->scdc_work);
> +		hdmi->scdc_cb = NULL;
> +
> +		drm_scdc_set_scrambling(connector, false);
> +		drm_scdc_set_high_tmds_clock_ratio(connector, false);
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(drm_scdc_start_scrambling);

This is also pretty significantly different than what vc4 implemented. I
don't necessarily mind, but claiming that it's functionally equivalent
isn't true. I think it would be a much better strategy to turn the vc4
code into helpers as is because it's been merged 4 years ago and we know
it's solid.

Then, if you want to add additional checks and constraints (like the
SCDC_SINK_VERSION) that's fine, but it should come on top, and with its
own explanation.

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-rockchip/attachments/20260612/1d97f4af/attachment.sig>

From macromorgan at hotmail.com  Fri Jun 12 06:59:11 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Fri, 12 Jun 2026 08:59:11 -0500
Subject: [PATCH V11 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260612114230.0fd2f391@jic23-huawei>
References: <20260610175455.19006-1-macroalpha82@gmail.com>
 <20260610175455.19006-4-macroalpha82@gmail.com>
 <20260611120943.7119975b@jic23-huawei>
 <PH0PR19MB9973387E29375D4E8F28C6B9D9A51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
 <20260611172022.4d138820@jic23-huawei>
 <PH0PR19MB997338CE11110E16E7FB668E3BA51B2@PH0PR19MB997338.namprd19.prod.outlook.com>
 <20260612114230.0fd2f391@jic23-huawei>
Message-ID: <PH0PR19MB997338A8FD439C0528B96048BDA5182@PH0PR19MB997338.namprd19.prod.outlook.com>

On Fri, Jun 12, 2026 at 11:42:30AM +0100, Jonathan Cameron wrote:
> On Thu, 11 Jun 2026 11:31:09 -0500
> Chris Morgan <macromorgan at hotmail.com> wrote:
> 
> > On Thu, Jun 11, 2026 at 05:20:22PM +0100, Jonathan Cameron wrote:
> > > On Thu, 11 Jun 2026 09:32:38 -0500
> > > Chris Morgan <macromorgan at hotmail.com> wrote:
> > >   
> > > > On Thu, Jun 11, 2026 at 12:09:43PM +0100, Jonathan Cameron wrote:  
> > > > > On Wed, 10 Jun 2026 12:54:47 -0500
> > > > > Chris Morgan <macroalpha82 at gmail.com> wrote:
> > > > >     
> > > > > > From: Chris Morgan <macromorgan at hotmail.com>
> > > > > > 
> > > > > > Add the core component of a new inv_icm42607 driver. This includes
> > > > > > a few setup functions and the full register definition in the
> > > > > > header file.
> > > > > > 
> > > > > > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>    
> > > > > Hi Chris,
> > > > > 
> > > > > A couple more minor things from a fresh read.
> > > > > 
> > > > > Thanks
> > > > > 
> > > > > Jonathan
> > > > >     
> > > > > > ---
> > > > > >  drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 334 ++++++++++++++++++
> > > > > >  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 197 +++++++++++
> > > > > >  2 files changed, 531 insertions(+)
> > > > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > > > >  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > > > 
> > > > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > > > > > new file mode 100644
> > > > > > index 000000000000..716fc0f1c3fd
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h    
> > > > >     
> > > > > > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..334264120b42
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c    
> > > > >     
> > > > > > +
> > > > > > +static int inv_icm42607_setup(struct inv_icm42607_state *st,
> > > > > > +			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
> > > > > > +{
> > > > > > +	const struct device *dev = regmap_get_device(st->map);
> > > > > > +	unsigned int val;
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	/* Warn, but don't fail. */
> > > > > > +	if (val != st->hw->whoami)
> > > > > > +		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
> > > > > > +			 val, st->hw->whoami, st->hw->name);
> > > > > > +
> > > > > > +	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
> > > > > > +			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	fsleep(INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC);
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * No polling interval specified in datasheet, so use reset time as
> > > > > > +	 * polling interval and 10x reset time as timeout period.
> > > > > > +	 */
> > > > > > +	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
> > > > > > +				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
> > > > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC),
> > > > > > +				       (INV_ICM42607_RESET_TIME_MS * USEC_PER_MSEC * 10));
> > > > > > +	if (ret)
> > > > > > +		return dev_err_probe(dev, ret,
> > > > > > +				     "reset error, reset done bit not set\n");
> > > > > > +
> > > > > > +	/* Sync the regcache again after a reset. */
> > > > > > +	regcache_mark_dirty(st->map);
> > > > > > +	ret = regcache_sync(st->map);    
> > > > > 
> > > > > Sashiko raised the point that you don't have a writeable register list for the regmap
> > > > > and so potentially we at very least write a bunch of stuff that isn't needed.
> > > > > I doubt it's actually a problem or you would have seen it, but nice little optimization
> > > > > to reduce what is written.    
> > > > 
> > > > I will add such a list, I'd put it in patch 4 unless you think I should
> > > > merge patch 3 and 4 to make the driver compileable at the first commit
> > > > of code (will push the number of lines to the ~850/900 range though).
> > > >   
> > > I'm fine with them split but don't mind if Andy prefers them combined.
> > > His comment on adding a COMPILE_TEST option would allow that to be
> > > built, but it is a bit odd to do it just for that purpose.
> > > 
> > > Jonathan
> > >   
> > 
> > I'm going to add the i2c stuff to this series, and then do the SPI
> > on the next patch. That should add only a little bit to this one but
> > still ensure the very first (code) commit has something to compile.
> > I'm going to avoid doing COMPILE_TEST unless collectively you all
> > think I should.
> > 
> > I'm still racing to try and get this one done before the merge
> > window opens up, but I'm pretty sure it's already too late at
> > this point. I'll refrain from submitting updates once the window opens
> > though.
> Unfortunately you are correct. IIO in practice closes around 10 days before
> the merge window to give time to both expose new things to testing in linux-next
> and to allow time for Greg KH to merge my pull request into char-misc (which
> is the path IIO takes to upstream)
> 
> Sorry about that, and whilst no need to rush as a result, we also don't
> stop merging IIO stuff in the merge window, it just sits in the testing
> branch until I can rebase that on rc1 and then push it out for linux-next
> to pick up.
> 
> Thanks,

No worries. I think I'm down to 2 bugs with sashiko that I'll try to
quash, then I can move on to other stuff. Note that when it complains
about the temperature sensor and power management that's a false
positive. I tried to put a note there to give it a hint but it doesn't
seem to want to take it.

If I haven't communicated it previously, thank you again for your help
with this. I thought adding an accelerometer to my handheld would be
easy, but I do appreciate everything you and the other maintainers have
helped me with.

Chris

> 
> Jonathan
> > 
> > Thank you,
> > Chris
> > 
> 


From tzimmermann at suse.de  Fri Jun 12 06:46:21 2026
From: tzimmermann at suse.de (Thomas Zimmermann)
Date: Fri, 12 Jun 2026 15:46:21 +0200
Subject: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in
 hotplug_event()
In-Reply-To: <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
Message-ID: <c7866bc4-bf37-4f8c-ae64-2d1d3a23f1ef@suse.de>



Am 02.06.26 um 00:44 schrieb Cristian Ciocaltea:
> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
> only stores a return value that is never used beyond the immediate
> return statement.  This simplifies the code without behavior changes.
>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>

Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>

But why is this patch hidden in this series? It has nothing to do with 
HDMI support.

> ---
>   drivers/gpu/drm/drm_fb_helper.c | 11 +++--------
>   1 file changed, 3 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
> index 7b11a582f8ec..3316bb00a662 100644
> --- a/drivers/gpu/drm/drm_fb_helper.c
> +++ b/drivers/gpu/drm/drm_fb_helper.c
> @@ -1744,21 +1744,17 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
>    */
>   int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
>   {
> -	int err = 0;
> -
>   	if (!drm_fbdev_emulation || !fb_helper)
>   		return 0;
>   
>   	mutex_lock(&fb_helper->lock);
> -	if (fb_helper->deferred_setup) {
> -		err = __drm_fb_helper_initial_config_and_unlock(fb_helper);
> -		return err;
> -	}
> +	if (fb_helper->deferred_setup)
> +		return __drm_fb_helper_initial_config_and_unlock(fb_helper);
>   
>   	if (!fb_helper->fb || !drm_master_internal_acquire(fb_helper->dev)) {
>   		fb_helper->delayed_hotplug = true;
>   		mutex_unlock(&fb_helper->lock);
> -		return err;
> +		return 0;
>   	}
>   
>   	drm_master_internal_release(fb_helper->dev);
> @@ -1802,4 +1798,3 @@ bool drm_fb_helper_gem_is_fb(const struct drm_fb_helper *fb_helper,
>   	return gem == obj;
>   }
>   EXPORT_SYMBOL_GPL(drm_fb_helper_gem_is_fb);
> -
>

-- 
--
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 detlev.casanova at collabora.com  Fri Jun 12 07:26:22 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Jun 2026 10:26:22 -0400
Subject: [PATCH 1/3] media: v4l2: Add callback for show_fdinfo
In-Reply-To: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
References: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
Message-ID: <20260612-v4l2-add-fdinfo-v1-1-723211abc861@collabora.com>

Allow v4l2 drivers to add information in the fdinfo file matching the
opened /dev/videoX file.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/v4l2-core/v4l2-dev.c | 10 ++++++++++
 include/media/v4l2-dev.h           |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 6ce623a1245a..3878fa2ff73e 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -481,6 +481,15 @@ static int v4l2_release(struct inode *inode, struct file *filp)
 	return ret;
 }
 
+/* Override for the show_fdinfo function */
+static void v4l2_show_fdinfo(struct seq_file *m, struct file *filp)
+{
+	struct video_device *vdev = video_devdata(filp);
+
+	if (vdev->fops->show_fdinfo)
+		vdev->fops->show_fdinfo(m, filp);
+}
+
 static const struct file_operations v4l2_fops = {
 	.owner = THIS_MODULE,
 	.read = v4l2_read,
@@ -494,6 +503,7 @@ static const struct file_operations v4l2_fops = {
 #endif
 	.release = v4l2_release,
 	.poll = v4l2_poll,
+	.show_fdinfo = v4l2_show_fdinfo,
 };
 
 /**
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 2e0f6d2e6a78..1635ab186f21 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -212,6 +212,7 @@ struct v4l2_file_operations {
 	int (*mmap) (struct file *, struct vm_area_struct *);
 	int (*open) (struct file *);
 	int (*release) (struct file *);
+	void (*show_fdinfo)(struct seq_file *, struct file *);
 };
 
 /*

-- 
2.54.0



From detlev.casanova at collabora.com  Fri Jun 12 07:26:21 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Jun 2026 10:26:21 -0400
Subject: [PATCH 0/3] media: Add fdinfo support for v4l2 drivers
Message-ID: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>

fdinfo is useful to poll information from the driver.
Unlike the ftrace interface, it lets userspace tools get a snapshot of
the state of the driver at their own pace, instead of getting events for
each driver status change.

This works better to get information like HW usage time or clock
frequencies, as well as memory usage.
This patch set focuses on mem2mem drivers that are per-frame based and
an implementation is proposed for the Verisilicon Hantro driver, limited
to clock frequencies and HW usage time.

An example of usage of this from userspace is implemented in v4l2top:

https://github.com/cazou/v4l2top

checkpatch.pl warning: The 2 arguments in the show_fdinfo callback
definition are kept unnamed to match with the rest of the struct
definition.

Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
Christopher Healy (2):
      docs: media: add documentation for media client usage stats
      media: hantro: add per-context fdinfo usage stats

Detlev Casanova (1):
      media: v4l2: Add callback for show_fdinfo

 .../userspace-api/media/drivers/index.rst          |  1 +
 .../media/drivers/media-usage-stats.rst            | 84 ++++++++++++++++++++++
 drivers/media/platform/verisilicon/hantro.h        |  5 ++
 drivers/media/platform/verisilicon/hantro_drv.c    | 22 ++++++
 drivers/media/v4l2-core/v4l2-dev.c                 | 10 +++
 include/media/v4l2-dev.h                           |  1 +
 6 files changed, 123 insertions(+)
---
base-commit: acb7500801e98639f6d8c2d796ed9f64cba83d3a
change-id: 20260610-v4l2-add-fdinfo-a790fceab329

Best regards,
--  
Detlev Casanova <detlev.casanova at collabora.com>



From detlev.casanova at collabora.com  Fri Jun 12 07:26:23 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Jun 2026 10:26:23 -0400
Subject: [PATCH 2/3] docs: media: add documentation for media client usage
 stats
In-Reply-To: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
References: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
Message-ID: <20260612-v4l2-add-fdinfo-v1-2-723211abc861@collabora.com>

From: Christopher Healy <healych at amazon.com>

Document the media fdinfo interface for per-file-descriptor usage
statistics exposed by stateless V4L2 codec drivers via
/proc/<pid>/fdinfo/<fd>.

This interface is specific to stateless (request API based) codec
devices where the kernel driver has per-job visibility into hardware
execution. Stateful codecs cannot support this because their firmware
manages job scheduling opaquely.

The specification defines media- prefixed keys for engine utilization
time, hardware cycle counts, and operating frequency, following the
same conventions as the DRM fdinfo mechanism documented in
drm-usage-stats.rst.

Signed-off-by: Christopher Healy <healych at amazon.com>
---
 .../userspace-api/media/drivers/index.rst          |  1 +
 .../media/drivers/media-usage-stats.rst            | 84 ++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 02967c9b18d6..61879738836c 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -34,6 +34,7 @@ For more details see the file COPYING in the source distribution of Linux.
 	imx-uapi
 	mali-c55
 	max2175
+	media-usage-stats
 	npcm-video
 	omap3isp-uapi
 	thp7312
diff --git a/Documentation/userspace-api/media/drivers/media-usage-stats.rst b/Documentation/userspace-api/media/drivers/media-usage-stats.rst
new file mode 100644
index 000000000000..835a74902e6e
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/media-usage-stats.rst
@@ -0,0 +1,84 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _media-usage-stats:
+
+==========================
+Media client usage stats
+==========================
+
+Stateless V4L2 codec drivers can optionally expose per-file-descriptor usage
+statistics via ``/proc/<pid>/fdinfo/<fd>``. This is analogous to the DRM fdinfo
+mechanism documented in :ref:`drm-client-usage-stats`, but uses the ``media-``
+key prefix for V4L2 media devices.
+
+This interface is specific to stateless (request API based) codec devices,
+including both decoders and encoders. With stateless codecs, the kernel driver
+explicitly submits each frame to the hardware and receives a completion
+interrupt, providing a clean per-job boundary that can be attributed to the
+submitting file descriptor.
+
+Stateful codec devices cannot support this interface because their firmware
+manages job scheduling internally. The kernel driver submits bitstream data
+but has no visibility into per-frame hardware execution timing.
+
+Implementation
+==============
+
+The V4L2 core provides the plumbing: drivers implement the ``show_fdinfo``
+callback in ``struct v4l2_file_operations``, and the core wires it into the
+kernel ``struct file_operations`` so that ``/proc/<pid>/fdinfo/<fd>`` output
+includes the driver-provided keys.
+
+File format specification
+=========================
+
+- File shall contain one key value pair per one line of text.
+- Colon character (``:``) must be used to delimit keys and values.
+- All standardised keys shall be prefixed with ``media-``.
+- Driver-specific keys shall be prefixed with ``driver_name-``.
+
+Mandatory keys
+--------------
+
+- media-driver: <valstr>
+
+  String shall contain the name of the media driver.
+
+Utilization keys
+----------------
+
+- media-engine-<keystr>: <uint> ns
+
+  Time in nanoseconds that the hardware engine spent busy processing work
+  belonging to this file descriptor. The ``<keystr>`` identifies the engine
+  (e.g. ``decoder``, ``encoder``).
+
+  Values are not required to be constantly monotonic if it makes the driver
+  implementation easier, but are required to catch up with the previously
+  reported larger value within a reasonable period.
+
+Frequency keys
+--------------
+
+- media-maxfreq-<keystr>: <uint> Hz
+
+  Maximum operating frequency of the engine identified by ``<keystr>``.
+
+- media-curfreq-<keystr>: <uint> Hz
+
+  Current operating frequency of the engine identified by ``<keystr>``.
+
+Example output
+==============
+
+::
+
+  media-driver:           hantro-vpu
+  media-engine-decoder:   123456789 ns
+  media-maxfreq-decoder:  600000000 Hz
+  media-curfreq-decoder:  600000000 Hz
+
+Driver specific implementations
+===============================
+
+* Hantro VPU (``drivers/media/platform/verisilicon/``)

-- 
2.54.0



From detlev.casanova at collabora.com  Fri Jun 12 07:26:24 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Jun 2026 10:26:24 -0400
Subject: [PATCH 3/3] media: hantro: add per-context fdinfo usage stats
In-Reply-To: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
References: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
Message-ID: <20260612-v4l2-add-fdinfo-v1-3-723211abc861@collabora.com>

From: Christopher Healy <healych at amazon.com>

Add per-file-descriptor hardware utilization tracking to the Hantro
VPU stateless codec driver, exposed via /proc/<pid>/fdinfo/<fd>.

Record a ktime timestamp when each job is submitted to hardware in
device_run(), and accumulate the elapsed nanoseconds when the job
completes in hantro_job_finish(). Report the accumulated time along
with the current clock frequency through the new V4L2 show_fdinfo
callback.

The output uses a media- key prefix with the following keys:
  media-driver:           driver name
  media-engine-<eng>:     accumulated busy time in nanoseconds
  media-maxfreq-<eng>:    maximum engine frequency in Hz
  media-curfreq-<eng>:    current engine frequency in Hz

Where <eng> is "decoder" or "encoder" depending on the context.

This enables userspace monitoring tools to compute per-process decoder
and encoder utilization. The current and max frequency keys report the
same value today since the driver lacks devfreq support, but will
diverge once DVFS is added, allowing userspace to approximate true
capacity utilization without any fdinfo code changes. A future series
can add hardware cycle counter support (via media-cycles-<eng>) for
exact utilization under DVFS, with no changes to the existing uAPI.

Signed-off-by: Christopher Healy <healych at amazon.com>
Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
---
 drivers/media/platform/verisilicon/hantro.h     |  5 +++++
 drivers/media/platform/verisilicon/hantro_drv.c | 22 ++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 0353de154a1e..10287e5cebac 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -16,6 +16,7 @@
 #include <linux/videodev2.h>
 #include <linux/wait.h>
 #include <linux/clk.h>
+#include <linux/ktime.h>
 #include <linux/reset.h>
 
 #include <media/v4l2-ctrls.h>
@@ -268,6 +269,10 @@ struct hantro_ctx {
 	struct hantro_postproc_ctx postproc;
 	bool need_postproc;
 
+	/* Statistics for debugging and performance measurements. */
+	ktime_t start_time;
+	u64 total_ns;
+
 	/* Specific for particular codec modes. */
 	union {
 		struct hantro_h264_dec_hw_ctx h264_dec;
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 2e81877f640f..139c2e6a83aa 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -90,6 +90,8 @@ static void hantro_job_finish(struct hantro_dev *vpu,
 			      struct hantro_ctx *ctx,
 			      enum vb2_buffer_state result)
 {
+	ctx->total_ns += ktime_to_ns(ktime_sub(ktime_get(), ctx->start_time));
+
 	pm_runtime_put_autosuspend(vpu->dev);
 
 	clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
@@ -186,6 +188,8 @@ static void device_run(void *priv)
 
 	v4l2_m2m_buf_copy_metadata(src, dst);
 
+	ctx->start_time = ktime_get();
+
 	if (ctx->codec_ops->run(ctx))
 		goto err_cancel_job;
 
@@ -701,10 +705,28 @@ static int hantro_release(struct file *filp)
 	return 0;
 }
 
+static void hantro_show_fdinfo(struct seq_file *m, struct file *f)
+{
+	struct hantro_ctx *ctx = file_to_ctx(f);
+	struct hantro_dev *vpu = ctx->dev;
+
+	seq_printf(m, "media-driver:\t%s\n", DRIVER_NAME);
+	seq_printf(m, "media-engine-%s:\t%llu ns\n",
+		   ctx->is_encoder ? "encoder" : "decoder",
+		   ctx->total_ns);
+	seq_printf(m, "media-maxfreq-%s:\t%lu Hz\n",
+		   ctx->is_encoder ? "encoder" : "decoder",
+		   clk_get_rate(vpu->clocks[0].clk));
+	seq_printf(m, "media-curfreq-%s:\t%lu Hz\n",
+		   ctx->is_encoder ? "encoder" : "decoder",
+		   clk_get_rate(vpu->clocks[0].clk));
+}
+
 static const struct v4l2_file_operations hantro_fops = {
 	.owner = THIS_MODULE,
 	.open = hantro_open,
 	.release = hantro_release,
+	.show_fdinfo = hantro_show_fdinfo,
 	.poll = v4l2_m2m_fop_poll,
 	.unlocked_ioctl = video_ioctl2,
 	.mmap = v4l2_m2m_fop_mmap,

-- 
2.54.0



From robh at kernel.org  Fri Jun 12 08:12:06 2026
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Jun 2026 10:12:06 -0500
Subject: [PATCH v2 1/5] ASoC: dt-bindings: rockchip-spdif: Correct SPDIF
 clock descriptions
In-Reply-To: <20260602101608.45137-2-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
 <20260602101608.45137-2-phucduc.bui@gmail.com>
Message-ID: <178127712594.1038565.14609439013063781178.robh@kernel.org>


On Tue, 02 Jun 2026 17:16:04 +0700, phucduc.bui at gmail.com wrote:
> From: bui duc phuc <phucduc.bui at gmail.com>
> 
> Update the binding descriptions to match the actual clock usage, where
> 'mclk' is the controller clock and 'hclk' is the bus clock.
> 
> Signed-off-by: bui duc phuc <phucduc.bui at gmail.com>
> ---
> 
> Changes in v2:
>   - Update commit message based on Krzysztof's review
> 
>  Documentation/devicetree/bindings/sound/rockchip-spdif.yaml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From nicolas.dufresne at collabora.com  Fri Jun 12 08:18:13 2026
From: nicolas.dufresne at collabora.com (Nicolas Dufresne)
Date: Fri, 12 Jun 2026 11:18:13 -0400
Subject: [PATCH 3/3] media: hantro: add per-context fdinfo usage stats
In-Reply-To: <20260612-v4l2-add-fdinfo-v1-3-723211abc861@collabora.com>
References: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
	 <20260612-v4l2-add-fdinfo-v1-3-723211abc861@collabora.com>
Message-ID: <a83b7ce30ffc423128e3a3b7d5a03baa8cba6216.camel@collabora.com>

Hi,

Le vendredi 12 juin 2026 ? 10:26 -0400, Detlev Casanova a ?crit?:
> From: Christopher Healy <healych at amazon.com>
> 
> Add per-file-descriptor hardware utilization tracking to the Hantro
> VPU stateless codec driver, exposed via /proc/<pid>/fdinfo/<fd>.
> 
> Record a ktime timestamp when each job is submitted to hardware in
> device_run(), and accumulate the elapsed nanoseconds when the job
> completes in hantro_job_finish(). Report the accumulated time along
> with the current clock frequency through the new V4L2 show_fdinfo
> callback.
> 
> The output uses a media- key prefix with the following keys:
> ? media-driver:?????????? driver name
> ? media-engine-<eng>:???? accumulated busy time in nanoseconds
> ? media-maxfreq-<eng>:??? maximum engine frequency in Hz
> ? media-curfreq-<eng>:??? current engine frequency in Hz
> 
> Where <eng> is "decoder" or "encoder" depending on the context.
> 
> This enables userspace monitoring tools to compute per-process decoder
> and encoder utilization. The current and max frequency keys report the
> same value today since the driver lacks devfreq support, but will
> diverge once DVFS is added, allowing userspace to approximate true
> capacity utilization without any fdinfo code changes. A future series
> can add hardware cycle counter support (via media-cycles-<eng>) for
> exact utilization under DVFS, with no changes to the existing uAPI.
> 
> Signed-off-by: Christopher Healy <healych at amazon.com>
> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
> ---
> ?drivers/media/platform/verisilicon/hantro.h???? |? 5 +++++
> ?drivers/media/platform/verisilicon/hantro_drv.c | 22 ++++++++++++++++++++++
> ?2 files changed, 27 insertions(+)
> 
> diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
> index 0353de154a1e..10287e5cebac 100644
> --- a/drivers/media/platform/verisilicon/hantro.h
> +++ b/drivers/media/platform/verisilicon/hantro.h
> @@ -16,6 +16,7 @@
> ?#include <linux/videodev2.h>
> ?#include <linux/wait.h>
> ?#include <linux/clk.h>
> +#include <linux/ktime.h>
> ?#include <linux/reset.h>
> ?
> ?#include <media/v4l2-ctrls.h>
> @@ -268,6 +269,10 @@ struct hantro_ctx {
> ?	struct hantro_postproc_ctx postproc;
> ?	bool need_postproc;
> ?
> +	/* Statistics for debugging and performance measurements. */
> +	ktime_t start_time;
> +	u64 total_ns;
> +
> ?	/* Specific for particular codec modes. */
> ?	union {
> ?		struct hantro_h264_dec_hw_ctx h264_dec;
> diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
> index 2e81877f640f..139c2e6a83aa 100644
> --- a/drivers/media/platform/verisilicon/hantro_drv.c
> +++ b/drivers/media/platform/verisilicon/hantro_drv.c
> @@ -90,6 +90,8 @@ static void hantro_job_finish(struct hantro_dev *vpu,
> ?			????? struct hantro_ctx *ctx,
> ?			????? enum vb2_buffer_state result)
> ?{
> +	ctx->total_ns += ktime_to_ns(ktime_sub(ktime_get(), ctx->start_time));
> +
> ?	pm_runtime_put_autosuspend(vpu->dev);
> ?
> ?	clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
> @@ -186,6 +188,8 @@ static void device_run(void *priv)
> ?
> ?	v4l2_m2m_buf_copy_metadata(src, dst);
> ?
> +	ctx->start_time = ktime_get();
> +
> ?	if (ctx->codec_ops->run(ctx))
> ?		goto err_cancel_job;
> ?
> @@ -701,10 +705,28 @@ static int hantro_release(struct file *filp)
> ?	return 0;
> ?}
> ?
> +static void hantro_show_fdinfo(struct seq_file *m, struct file *f)
> +{
> +	struct hantro_ctx *ctx = file_to_ctx(f);
> +	struct hantro_dev *vpu = ctx->dev;
> +
> +	seq_printf(m, "media-driver:\t%s\n", DRIVER_NAME);
> +	seq_printf(m, "media-engine-%s:\t%llu ns\n",
> +		?? ctx->is_encoder ? "encoder" : "decoder",
> +		?? ctx->total_ns);
> +	seq_printf(m, "media-maxfreq-%s:\t%lu Hz\n",
> +		?? ctx->is_encoder ? "encoder" : "decoder",
> +		?? clk_get_rate(vpu->clocks[0].clk));
> +	seq_printf(m, "media-curfreq-%s:\t%lu Hz\n",
> +		?? ctx->is_encoder ? "encoder" : "decoder",
> +		?? clk_get_rate(vpu->clocks[0].clk));

Similar to what was done in DRM helpers, I would create a common structure,
maybe in a v4l2-stats library (or some better name). The driver would fill that
structure directly, or through helpers (such as software timer helper, cycle
count translation helper), and finally, this show_fd_info() would be a one
liners, just like DRM do.

This will ensure full consistency in the trace, and avoid possible future
unresolvable compatibility issue due to past mistakes. If we ever let a bug
through (of course we won't :-D) all driver will have the same bug, and it will
be easier to not break userspace.

Nicolas

> +}
> +
> ?static const struct v4l2_file_operations hantro_fops = {
> ?	.owner = THIS_MODULE,
> ?	.open = hantro_open,
> ?	.release = hantro_release,
> +	.show_fdinfo = hantro_show_fdinfo,
> ?	.poll = v4l2_m2m_fop_poll,
> ?	.unlocked_ioctl = video_ioctl2,
> ?	.mmap = v4l2_m2m_fop_mmap,
-------------- 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-rockchip/attachments/20260612/5cf7d4ab/attachment.sig>

From alchark at flipper.net  Fri Jun 12 08:34:13 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 12 Jun 2026 19:34:13 +0400
Subject: [PATCH 0/4] mfd: Add support for the MCU in the UGREEN DH2300 NAS
Message-ID: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>

UGREEN DH2300 is a 2-bay SATA NAS based on the Rockchip RK3576 SoC. It
includes an embedded controller connected over I2C which won't let the
drives power up without its register being poked first, which precludes
the use of the device for its main purpose.

There is no public documentation or source code available, but apparently
the MCU is also responsible for a hardware watchdog function and some type
of wake functionality, so this series implements an MFD-regulator
separation right away to allow for adding these functions properly later
on.

For now though a single-bit write to the MCU seems to be sufficient to get
the drives to work with only a board DTS addition [1] - to be submitted
separately.

[1] https://github.com/flipperdevices/flipper-linux-kernel/blob/2c1c5ee609f6ed4c77e9e5428df91e98b3f50cce/arch/arm64/boot/dts/rockchip/rk3576-nasync-dh2300.dts

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
Alexey Charkov (4):
      dt-bindings: vendor-prefixes: Add Ugreen Group Limited
      dt-bindings: mfd: Add UGREEN NASync DH2300 MCU
      mfd: Add support for UGREEN NASync DH2300 MCU
      regulator: Add support for UGREEN NASync DH2300 MCU SATA power gate

 .../devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml | 62 +++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml       |  2 +
 MAINTAINERS                                        |  7 ++
 drivers/mfd/Kconfig                                | 16 +++++
 drivers/mfd/Makefile                               |  1 +
 drivers/mfd/ugreen-dh2300-mcu.c                    | 60 ++++++++++++++++
 drivers/regulator/Kconfig                          | 12 ++++
 drivers/regulator/Makefile                         |  1 +
 drivers/regulator/ugreen-dh2300-mcu-regulator.c    | 80 ++++++++++++++++++++++
 9 files changed, 241 insertions(+)
---
base-commit: ec039126b7fac4e3af35ebccaa7c6f9b6875ba81
change-id: 20260612-dh2300-mcu-5354d1f5f11a

Best regards,
--  
Alexey Charkov <alchark at flipper.net>



From alchark at flipper.net  Fri Jun 12 08:34:14 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 12 Jun 2026 19:34:14 +0400
Subject: [PATCH 1/4] dt-bindings: vendor-prefixes: Add Ugreen Group Limited
In-Reply-To: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
Message-ID: <20260612-dh2300-mcu-v1-1-ab8db1617bc0@flipper.net>

Add Ugreen Group Limited, a consumer technology company producing a range
of smart charging, office audio and visual, and smart storage products.

Link: https://www.ugreen.com/
Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 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 dd94c50e97f9..274e52421a5b 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1757,6 +1757,8 @@ patternProperties:
     description: Ufi Space Co., Ltd.
   "^ugoos,.*":
     description: Ugoos Industrial Co., Ltd.
+  "^ugreen,.*":
+    description: Ugreen Group Limited
   "^ultrapower,.*":
     description: Beijing Ultrapower Software Co., Ltd.
   "^uni-t,.*":

-- 
2.53.0



From alchark at flipper.net  Fri Jun 12 08:34:15 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 12 Jun 2026 19:34:15 +0400
Subject: [PATCH 2/4] dt-bindings: mfd: Add UGREEN NASync DH2300 MCU
In-Reply-To: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
Message-ID: <20260612-dh2300-mcu-v1-2-ab8db1617bc0@flipper.net>

Document the UGREEN NASync DH2300 embedded controller (HC32F005 MCU),
which is responsible for gating the SATA drive-bay power rail and
providing a hardware watchdog.

This is based on disassebly of a GPL binary from vendor firmware for which
no source code could be found, so parts of it can be inaccurate. Only
the power gating function is confirmed.

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 .../devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml | 62 ++++++++++++++++++++++
 MAINTAINERS                                        |  5 ++
 2 files changed, 67 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml b/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
new file mode 100644
index 000000000000..847970c609cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/ugreen,dh2300-mcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UGREEN NASync DH2300 embedded controller
+
+maintainers:
+  - Alexey Charkov <alchark at flipper.net>
+
+description:
+  The UGREEN NASync DH2300 NAS carries a HC32F005 microcontroller on I2C that
+  acts as a board embedded controller. It gates power to the SATA drive bays
+  through an internal register and apparently also serves as a watchdog
+  (unconfirmed, as vendor kernel sources are unavailable, works without it)
+
+properties:
+  compatible:
+    const: ugreen,dh2300-mcu
+
+  reg:
+    maxItems: 1
+
+  regulator:
+    type: object
+    $ref: /schemas/regulator/regulator.yaml#
+    unevaluatedProperties: false
+    description:
+      The SATA drive-bay power gate controlled by the MCU.
+
+  watchdog-gpios:
+    description:
+      Optional GPIO line used to ping the hardware watchdog function of the MCU
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/pinctrl/rockchip.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        embedded-controller at 4c {
+            compatible = "ugreen,dh2300-mcu";
+            reg = <0x4c>;
+            watchdog-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
+
+            sata_power: regulator {
+                regulator-name = "sata-power";
+                vin-supply = <&vcc12v_dcin>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index f1caa6e5198b..ca27df7cd684 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27633,6 +27633,11 @@ L:	linux-input at vger.kernel.org
 S:	Maintained
 F:	drivers/hid/hid-udraw-ps3.c
 
+UGREEN DH2300 MCU MFD DRIVER
+M:	Alexey Charkov <alchark at flipper.net>
+S:	Maintained
+F:	Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
+
 UHID USERSPACE HID IO DRIVER
 M:	David Rheinsberg <david at readahead.eu>
 L:	linux-input at vger.kernel.org

-- 
2.53.0



From alchark at flipper.net  Fri Jun 12 08:34:16 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 12 Jun 2026 19:34:16 +0400
Subject: [PATCH 3/4] mfd: Add support for UGREEN NASync DH2300 MCU
In-Reply-To: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
Message-ID: <20260612-dh2300-mcu-v1-3-ab8db1617bc0@flipper.net>

Add a driver for the HC32F005 MCU used as an embedded controller on the
UGREEN NASync DH2300 NAS.

This part provides the shared I2C regmap to be used by function-specific
sub-devices, and instantiates the SATA drive-bay power gate regulator.
Implemented as an MFD to allow for other functions of the MCU to be added
later: vendor binaries imply that it also provides a hardware watchdog
and somehow serves as a wake source, but so far only the SATA power gating
function has been confirmed in absence of documentation and sources for the
vendor firmware.

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 MAINTAINERS                     |  1 +
 drivers/mfd/Kconfig             | 16 +++++++++++
 drivers/mfd/Makefile            |  1 +
 drivers/mfd/ugreen-dh2300-mcu.c | 60 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ca27df7cd684..9578a06fe651 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27637,6 +27637,7 @@ UGREEN DH2300 MCU MFD DRIVER
 M:	Alexey Charkov <alchark at flipper.net>
 S:	Maintained
 F:	Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
+F:	drivers/mfd/ugreen-dh2300-mcu.c
 
 UHID USERSPACE HID IO DRIVER
 M:	David Rheinsberg <david at readahead.eu>
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 763ce6a34782..5a2ad75bd9c9 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1947,6 +1947,22 @@ config MFD_TPS6594_SPI
 	  This driver can also be built as a module.  If so, the module
 	  will be called tps6594-spi.
 
+config MFD_UGREEN_DH2300_MCU
+	tristate "UGREEN NASync DH2300 embedded controller"
+	depends on I2C
+	depends on OF
+	select MFD_CORE
+	select REGMAP_I2C
+	help
+	  Say yes here to enable support for the HC32F005 microcontroller found
+	  on the UGREEN NASync DH2300 NAS, where it acts as a board embedded
+	  controller. This core driver sets up the shared register map and
+	  instantiates the function sub-devices (the SATA drive-bay power
+	  regulator).
+
+	  This driver can also be built as a module. If so, the module will be
+	  called ugreen-dh2300-mcu.
+
 config TWL4030_CORE
 	bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support"
 	depends on I2C=y
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index dd4bb7e77c33..6247239bcfe1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -109,6 +109,7 @@ obj-$(CONFIG_MFD_TPS65912_SPI)  += tps65912-spi.o
 obj-$(CONFIG_MFD_TPS6594)	+= tps6594-core.o
 obj-$(CONFIG_MFD_TPS6594_I2C)	+= tps6594-i2c.o
 obj-$(CONFIG_MFD_TPS6594_SPI)	+= tps6594-spi.o
+obj-$(CONFIG_MFD_UGREEN_DH2300_MCU)	+= ugreen-dh2300-mcu.o
 obj-$(CONFIG_MENELAUS)		+= menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)	+= twl-core.o twl4030-irq.o twl6030-irq.o
diff --git a/drivers/mfd/ugreen-dh2300-mcu.c b/drivers/mfd/ugreen-dh2300-mcu.c
new file mode 100644
index 000000000000..5184b0c98759
--- /dev/null
+++ b/drivers/mfd/ugreen-dh2300-mcu.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Core driver for the UGREEN NASync DH2300 embedded controller (HC32F005 MCU).
+ *
+ * The microcontroller sits on I2C and exposes an 8-bit register map. It is a
+ * multi-function device: SATA drive-bay power gate, hardware watchdog and
+ * possibly other functions
+ */
+
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define UGREEN_DH2300_MCU_REG_MAX	0x94
+
+static const struct regmap_config ugreen_dh2300_mcu_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = UGREEN_DH2300_MCU_REG_MAX,
+};
+
+static const struct mfd_cell ugreen_dh2300_mcu_cells[] = {
+	{ .name = "ugreen-dh2300-mcu-regulator" },
+};
+
+static int ugreen_dh2300_mcu_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct regmap *regmap;
+
+	regmap = devm_regmap_init_i2c(client, &ugreen_dh2300_mcu_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "failed to initialise regmap\n");
+
+	return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+				    ugreen_dh2300_mcu_cells,
+				    ARRAY_SIZE(ugreen_dh2300_mcu_cells),
+				    NULL, 0, NULL);
+}
+
+static const struct of_device_id ugreen_dh2300_mcu_of_match[] = {
+	{ .compatible = "ugreen,dh2300-mcu" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ugreen_dh2300_mcu_of_match);
+
+static struct i2c_driver ugreen_dh2300_mcu_driver = {
+	.driver = {
+		.name = "ugreen-dh2300-mcu",
+		.of_match_table = ugreen_dh2300_mcu_of_match,
+	},
+	.probe = ugreen_dh2300_mcu_probe,
+};
+module_i2c_driver(ugreen_dh2300_mcu_driver);
+
+MODULE_DESCRIPTION("UGREEN NASync DH2300 embedded controller core driver");
+MODULE_LICENSE("GPL");

-- 
2.53.0



From alchark at flipper.net  Fri Jun 12 08:34:17 2026
From: alchark at flipper.net (Alexey Charkov)
Date: Fri, 12 Jun 2026 19:34:17 +0400
Subject: [PATCH 4/4] regulator: Add support for UGREEN NASync DH2300 MCU
 SATA power gate
In-Reply-To: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
Message-ID: <20260612-dh2300-mcu-v1-4-ab8db1617bc0@flipper.net>

Add a driver for the SATA drive-bay power gate function of the UGREEN
NASync DH2300 embedded controller (HC32F005 MCU).

This is a simple on/off regulator, controlled by bit 0 of register 0x41,
with inverted polarity (0 = enabled, 1 = disabled). Boot-time default is
disabled, so this driver is required to use the NAS functionality.

Signed-off-by: Alexey Charkov <alchark at flipper.net>
---
 MAINTAINERS                                     |  1 +
 drivers/regulator/Kconfig                       | 12 ++++
 drivers/regulator/Makefile                      |  1 +
 drivers/regulator/ugreen-dh2300-mcu-regulator.c | 80 +++++++++++++++++++++++++
 4 files changed, 94 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9578a06fe651..2fc84be86e46 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27638,6 +27638,7 @@ M:	Alexey Charkov <alchark at flipper.net>
 S:	Maintained
 F:	Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
 F:	drivers/mfd/ugreen-dh2300-mcu.c
+F:	drivers/regulator/ugreen-dh2300-mcu-regulator.c
 
 UHID USERSPACE HID IO DRIVER
 M:	David Rheinsberg <david at readahead.eu>
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a54a549196fe..e692ff864806 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1812,6 +1812,18 @@ config REGULATOR_TWL4030
 	  This driver supports the voltage regulators provided by
 	  this family of companion chips.
 
+config REGULATOR_UGREEN_DH2300_MCU
+	tristate "UGREEN NASync DH2300 MCU SATA power regulator"
+	depends on MFD_UGREEN_DH2300_MCU
+	help
+	  Say yes here to enable support for the SATA drive-bay power gate of
+	  the UGREEN NASync DH2300 embedded controller. The regulator is a
+	  sub-device of the ugreen-dh2300-mcu MFD core and is normally consumed
+	  by the SATA controllers via their target-supply.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called ugreen-dh2300-mcu-regulator.
+
 config REGULATOR_UNIPHIER
 	tristate "UniPhier regulator driver"
 	depends on ARCH_UNIPHIER || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 134eee274dbf..44956d795923 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -206,6 +206,7 @@ obj-$(CONFIG_REGULATOR_TPS6594) += tps6594-regulator.o
 obj-$(CONFIG_REGULATOR_TPS65132) += tps65132-regulator.o
 obj-$(CONFIG_REGULATOR_TPS68470) += tps68470-regulator.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o
+obj-$(CONFIG_REGULATOR_UGREEN_DH2300_MCU) += ugreen-dh2300-mcu-regulator.o
 obj-$(CONFIG_REGULATOR_UNIPHIER) += uniphier-regulator.o
 obj-$(CONFIG_REGULATOR_RZG2L_VBCTRL) += renesas-usb-vbus-regulator.o
 obj-$(CONFIG_REGULATOR_VCTRL) += vctrl-regulator.o
diff --git a/drivers/regulator/ugreen-dh2300-mcu-regulator.c b/drivers/regulator/ugreen-dh2300-mcu-regulator.c
new file mode 100644
index 000000000000..69fda90f7ace
--- /dev/null
+++ b/drivers/regulator/ugreen-dh2300-mcu-regulator.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SATA drive-bay power gate for the UGREEN NASync DH2300 embedded controller
+ * (HC32F005 MCU).
+ *
+ * The microcontroller gates the SATA bay power rail through register 0x41.
+ * The polarity is inverted: writing 0 enables the rail, writing 1 disables it
+ * (the controller latches "off" out of reset).
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define UGREEN_DH2300_MCU_REG_SATA_POWER	0x41
+
+static const struct regulator_ops ugreen_dh2300_sata_ops = {
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+};
+
+static const struct regulator_desc ugreen_dh2300_sata_desc = {
+	.name = "sata-power",
+	.enable_is_inverted = true,
+	.enable_mask = 0x01,
+	.enable_reg = UGREEN_DH2300_MCU_REG_SATA_POWER,
+	.supply_name = "vin",
+	.ops = &ugreen_dh2300_sata_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int ugreen_dh2300_mcu_regulator_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	struct device_node *np;
+
+	np = of_get_child_by_name(dev->parent->of_node, "regulator");
+	if (!np)
+		return dev_err_probe(dev, -ENODEV,
+				     "missing regulator child node\n");
+
+	config.dev = dev;
+	config.of_node = np;
+	config.regmap = dev_get_regmap(dev->parent, NULL);
+	if (!config.regmap) {
+		of_node_put(np);
+		return dev_err_probe(dev, -ENODEV,
+				     "no regmap available from parent\n");
+	}
+
+	config.init_data = of_get_regulator_init_data(dev, np,
+						      &ugreen_dh2300_sata_desc);
+
+	rdev = devm_regulator_register(dev, &ugreen_dh2300_sata_desc, &config);
+	of_node_put(np);
+	if (IS_ERR(rdev))
+		return dev_err_probe(dev, PTR_ERR(rdev),
+				     "failed to register regulator\n");
+
+	return 0;
+}
+
+static struct platform_driver ugreen_dh2300_mcu_regulator_driver = {
+	.driver = {
+		.name = "ugreen-dh2300-mcu-regulator",
+	},
+	.probe = ugreen_dh2300_mcu_regulator_probe,
+};
+module_platform_driver(ugreen_dh2300_mcu_regulator_driver);
+
+MODULE_DESCRIPTION("UGREEN NASync DH2300 MCU SATA power regulator");
+MODULE_LICENSE("GPL");

-- 
2.53.0



From quentin.schulz at cherry.de  Fri Jun 12 08:38:25 2026
From: quentin.schulz at cherry.de (Quentin Schulz)
Date: Fri, 12 Jun 2026 17:38:25 +0200
Subject: [PATCH v2] arm64: dts: rockchip: fix emmc reset polarity on
 px30-cobra
In-Reply-To: <20260609081728.30616-2-jakobunt@gmail.com>
References: <20260609081728.30616-2-jakobunt@gmail.com>
Message-ID: <2710972a-ba6a-48d3-8551-1db5639d7d98@cherry.de>

Hi Jakob,

On 6/9/26 10:17 AM, Jakob Unterwurzacher wrote:
> From: Jakob Unterwurzacher <jakob.unterwurzacher at cherry.de>
> 
> Technically, the reset signal is active low - it's called RST_n after all.
> 
> But it is ignored completely unless RST_n_FUNCTION=1 (byte 162 in extcsd)
> is set in the emmc. It is 0 per default.
> 
> For emmcs that have RST_n_FUNCTION=1 we failed like this:
> 
> 	[    3.074480] mmc1: Failed to initialize a non-removable card
> 
> With this change they work normally.
> 
> Cc: stable at vger.kernel.org
> Fixes: bb510ddc9d3e ("arm64: dts: rockchip: add px30-cobra base dtsi and board variants")

Tested-by: Quentin Schulz <quentin.schulz at cherry.de>

Thanks!
Quentin


From sebastian.reichel at collabora.com  Fri Jun 12 08:57:39 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 17:57:39 +0200
Subject: [PATCH v4 07/16] phy: rockchip: usbdp: Support single-lane DP
In-Reply-To: <f29df43b-111d-471b-8579-0196596fc32b@linaro.org>
References: <20260428-rockchip-usbdp-cleanup-v4-0-7775671ece22@collabora.com>
 <20260428-rockchip-usbdp-cleanup-v4-7-7775671ece22@collabora.com>
 <f29df43b-111d-471b-8579-0196596fc32b@linaro.org>
Message-ID: <aiwrNQhPsqlqDB-Z@venus>

Hi,

On Wed, May 06, 2026 at 04:53:07PM +0200, Neil Armstrong wrote:
> > @@ -537,6 +538,13 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
> >    * <0 1>                  dpln0         dpln1       usbrx         usbtx
> >    * <2 3>                  usbrx         usbtx       dpln0         dpln1
> >    * ---------------------------------------------------------------------------
> > + * if 1 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x>;
> > + * sample as follow:
> > + * ---------------------------------------------------------------------------
> > + *                        B11-B10       A2-A3       A11-A10       B2-B3
> > + * rockchip,dp-lane-mux   ln0(tx/rx)    ln1(tx)     ln2(tx/rx)    ln3(tx)
> > + * <0>                    dpln0         \           usbrx         usbtx
> > + * ---------------------------------------------------------------------------
> >    */
> >   static void rk_udphy_dplane_select(struct rk_udphy *udphy)
> > @@ -544,18 +552,18 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
> >   	const struct rk_udphy_cfg *cfg = udphy->cfgs;
> >   	u32 value = 0;
> > -	switch (udphy->mode) {
> > -	case UDPHY_MODE_DP:
> > -		value |= 2 << udphy->dp_lane_sel[2] * 2;
> > +	switch (udphy->dp_lanes) {
> > +	case 4:
> >   		value |= 3 << udphy->dp_lane_sel[3] * 2;
> > +		value |= 2 << udphy->dp_lane_sel[2] * 2;
> >   		fallthrough;
> > -	case UDPHY_MODE_DP_USB:
> > -		value |= 0 << udphy->dp_lane_sel[0] * 2;
> > +	case 2:
> >   		value |= 1 << udphy->dp_lane_sel[1] * 2;
> > -		break;
> > +		fallthrough;
> > -	case UDPHY_MODE_USB:
> > +	case 1:
> > +		value |= 0 << udphy->dp_lane_sel[0] * 2;
> 
> What's the point of keeping this no-op calculation ?

This function is cleaned up in a later patch to no longer have the
switch/case at all ("Cleanup DP lane selection function"). I kept
the no-op calculation here, since it IMHO makes it easier to understand
the cleanup patch and will be optimized away by the compiler anyways.

(I will send out a new patch series in a jiffy)

Greetings,

-- Sebastian
-------------- 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-rockchip/attachments/20260612/d34a5a6a/attachment.sig>

From sebastian.reichel at collabora.com  Fri Jun 12 09:21:41 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:41 +0200
Subject: [PATCH v5 03/18] phy: rockchip: usbdp: Keep clocks running on PHY
 re-init
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-3-efc83069869f@collabora.com>

When a mode change is required rk_udphy_power_on() disables
the clocks and then calls rk_udphy_setup(), which then enables
all the clocks again before continuing with rk_udphy_init().

Considering that rk_udphy_init() does assert the reset lines,
re-enabling the clocks is just delaying things. Avoid it by
directly calling rk_udphy_init().

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 744cc7c642f4..98562a888b42 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1012,8 +1012,7 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 
-		rk_udphy_disable(udphy);
-		ret = rk_udphy_setup(udphy);
+		ret = rk_udphy_init(udphy);
 		if (ret)
 			return ret;
 	}

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:38 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:38 +0200
Subject: [PATCH v5 00/18] phy: rockchip: usbdp: Fixes, DP 1-lane support
 and cleanups
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>

This series overhauls the Rockchip USBDP driver; apart from a
a bunch of cleanups and small improvements the main goal is to
get the driver ready for proper USB-C DP AltMode support. At
the moment it only contains a semi-working state.

Once this series has landed, it unblocks enabling proper USB-C
DP AltMode on the RK3588 and RK3576 platforms incl. runtime PM
for the Synopsys DesignWare DisplayPort controller.

Apart from this series, further changes are required on the
DRM side. There are no compile-time dependencies between the
DRM side and the PHY side, but the PHY side must be applied
to avoid SErrors once runtime PM is added to the DisplayPort
controller driver. Thus it would be really good to land this
series ASAP as it blocks the DRM side.

Changes in v5:
- Link to v4: https://lore.kernel.org/r/20260428-rockchip-usbdp-cleanup-v4-0-7775671ece22 at collabora.com
- Picked up Acked-by from Rob Herring for DT binding
- Fix typos in commit messages/comments
- Add Fixes tag to "Do not looe USB3 PHY status" patch
- Collect Reviewed-by: Neil Armstrong for multiple patches
- Drop now unused code from "Drop DP HPD handling" patch (Sashiko)
- Ignore mux events not involving DP AltMode (Sashiko)
- Add new patch to support going back from DP only mode to USB combo
  mode; technically this is a fix, but DP mode does not yet work
  upstream, so it does not matter (Sashiko)
- Add new patch adding a few debug messages, which are useful
  to investigate potential hotplug issues in the future
- Sashiko comments about the DT binding and property usage
  are wrong as the first port is for the superspeed lanes
  used for DP and USB, while the last port is just about
  DP aux. I ignored them.
- There is a pre-existing bug, that can already be hit with the
  upstream kernel and that the series doesn't fix properly:
  Accessing the USB3 controller registers requires the USB PHY
  running, since it provides a clock. Re-initializing the PHY
  means there is a race-condition - if the system tries to access
  the USB3 controller in parallel to the re-init, the system will
  hang and/or fail with an SError. By keeping the clocks running
  and only asserting the resets this time is minimized by this
  series. A proper fix for this will be looked into independently
  from this series.
- I used v7.1-rc6 as base, but the driver has no changes since
  6.18 even in linux-next and there are no pending patches for
  it on the mailinglist either, so it applies to *any* recent
  kernel branch.

Changes in v4:
- Link to v3: https://lore.kernel.org/r/20260313-rockchip-usbdp-cleanup-v3-0-3e8fe89a35b5 at collabora.com
- rebased to v7.1-rc1 (no changes)
- Update DRM bridge registration patch to avoid registration when DP aux
  port is not connected to anything, since this results in errors and some
  boards use USBDP instances for USB3 only.
- Add patch renaming mode_change into phy_needs_reinit
- Add patch to re-init PHY on orientation change
- Add patch to factor out lane_mux_sel setup
- Add patch to handle mutex via guard functions

Changes in v3:
- Link to v2: https://lore.kernel.org/r/20260213-rockchip-usbdp-cleanup-v2-0-b67ec225f96e at collabora.com
- Add patch to register the USBDP PHY as DRM bridge
- Add patch to describe ports in DT binding (used by the DRM bridge)
- Add patch to drop HPD handling from the PHY

Changes in v2:
- Link to v1: https://lore.kernel.org/r/20260203-rockchip-usbdp-cleanup-v1-0-16a6f92ed176 at collabora.com
- Added new patches to fix USB3 SError

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
Frank Wang (1):
      phy: rockchip: usbdp: Amend SSC modulation deviation

Sebastian Reichel (15):
      dt-bindings: phy: rockchip-usbdp: add improved ports scheme
      phy: rockchip: usbdp: Do not lose USB3 PHY status
      phy: rockchip: usbdp: Keep clocks running on PHY re-init
      phy: rockchip: usbdp: Add missing mode_change update
      phy: rockchip: usbdp: Rename DP lane functions
      phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST
      phy: rockchip: usbdp: Cleanup DP lane selection function
      phy: rockchip: usbdp: Register DP aux bridge
      phy: rockchip: usbdp: Drop DP HPD handling
      phy: rockchip: usbdp: Rename mode_change to phy_needs_reinit
      phy: rockchip: usbdp: Re-init the PHY on orientation change
      phy: rockchip: usbdp: Factor out lane_mux_sel setup
      phy: rockchip: usbdp: Use guard functions for mutex
      phy: rockchip: usbdp: Support going from DP-only mode to USB mode
      phy: rockchip: usbdp: Add some extra debug messages

William Wu (1):
      phy: rockchip: usbdp: Fix LFPS detect threshold control

Zhang Yubing (1):
      phy: rockchip: usbdp: Support single-lane DP

 .../bindings/phy/phy-rockchip-usbdp.yaml           |  23 ++
 drivers/phy/rockchip/Kconfig                       |   2 +
 drivers/phy/rockchip/phy-rockchip-usbdp.c          | 357 +++++++++------------
 3 files changed, 181 insertions(+), 201 deletions(-)
---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: 20260203-rockchip-usbdp-cleanup-5b59dfb561a3

Best regards,
-- 
Sebastian Reichel <sebastian.reichel at collabora.com>



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:40 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:40 +0200
Subject: [PATCH v5 02/18] phy: rockchip: usbdp: Do not lose USB3 PHY status
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-2-efc83069869f@collabora.com>

By default (i.e. without manually enabling runtime PM) DWC3 requests the
USB3 PHY once and keeps it enabled all the time. When DisplayPort is
being requested later on, a mode change is needed. This re-initializes
the PHY. During re-initialization the status variable has incorrectly
been cleared, which means the tracking information for USB3 is lost.

This is not an immediate problem, since the DP side keeps the PHY
enabled. But once DP is toggled off, the whole PHY will be disabled.
This is a problem, because the USB side still needs it powered.

Fix things by not clearing the status flags.

Fixes: 2f70bbddeb45 ("phy: rockchip: add usbdp combo phy driver")
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index fba35510d88c..744cc7c642f4 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -1009,7 +1009,6 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 			rk_udphy_u3_port_disable(udphy, false);
 	} else if (udphy->mode_change) {
 		udphy->mode_change = false;
-		udphy->status = UDPHY_MODE_NONE;
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:42 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:42 +0200
Subject: [PATCH v5 04/18] phy: rockchip: usbdp: Amend SSC modulation
 deviation
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-4-efc83069869f@collabora.com>

From: Frank Wang <frank.wang at rock-chips.com>

Move SSC modulation deviation into private config of clock

 - 24M: 0x00d4[5:0] = 0x30
 - 26M: 0x00d4[5:0] = 0x33

Signed-off-by: Frank Wang <frank.wang at rock-chips.com>
[Taken over from rockchip's kernel tree; register 0x00d4 is not
described in the TRM]
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 98562a888b42..1f686844c337 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -350,7 +350,8 @@ static const struct reg_sequence rk_udphy_24m_refclk_cfg[] = {
 	{0x0a64, 0xa8}, {0x1a3c, 0xd0},
 	{0x1a44, 0xd0}, {0x1a48, 0x01},
 	{0x1a4c, 0x0d}, {0x1a54, 0xe0},
-	{0x1a5c, 0xe0}, {0x1a64, 0xa8}
+	{0x1a5c, 0xe0}, {0x1a64, 0xa8},
+	{0x00d4, 0x30}
 };
 
 static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = {
@@ -377,7 +378,7 @@ static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = {
 	{0x0c30, 0x0e}, {0x0c48, 0x06},
 	{0x1c30, 0x0e}, {0x1c48, 0x06},
 	{0x028c, 0x18}, {0x0af0, 0x00},
-	{0x1af0, 0x00}
+	{0x1af0, 0x00}, {0x00d4, 0x33}
 };
 
 static const struct reg_sequence rk_udphy_init_sequence[] = {
@@ -412,8 +413,7 @@ static const struct reg_sequence rk_udphy_init_sequence[] = {
 	{0x0070, 0x7d}, {0x0074, 0x68},
 	{0x0af4, 0x1a}, {0x1af4, 0x1a},
 	{0x0440, 0x3f}, {0x10d4, 0x08},
-	{0x20d4, 0x08}, {0x00d4, 0x30},
-	{0x0024, 0x6e},
+	{0x20d4, 0x08}, {0x0024, 0x6e}
 };
 
 static inline int rk_udphy_grfreg_write(struct regmap *base,

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:39 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:39 +0200
Subject: [PATCH v5 01/18] dt-bindings: phy: rockchip-usbdp: add improved
 ports scheme
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-1-efc83069869f@collabora.com>

Currently the Rockchip USBDP PHY is missing a documented port scheme.
Meanwhile upstream RK3588 DTS files are a bit messy and use different
port schemes. The upstream USBDP PHY Linux kernel driver does not yet
parse the ports at all and thus does not create any implicit ABI either.

But with the current mess it is not possible to properly support USB-C
DP AltMode. Thus this introduces a proper port scheme following roughly
the ports design of the Qualcomm QMP USB4-USB3-DP PHY controller binding
with a slight difference that there is an additional port for the
USB-C SBU port as the Rockchip USB-DP PHY also contains the SBU mux.

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 .../bindings/phy/phy-rockchip-usbdp.yaml           | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
index 8b7059d5b182..f728acf057e4 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-usbdp.yaml
@@ -114,6 +114,29 @@ properties:
       A port node to link the PHY to a TypeC controller for the purpose of
       handling orientation switching.
 
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+    properties:
+      port at 0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Output endpoint of the PHY for USB (or DP when configured into 4 lane
+          mode), which should point to the superspeed port of a USB connector.
+
+      port at 1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Incoming endpoint from the USB 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:
+          Output endpoint of the PHY for DP, which should either point to the
+          SBU port of a USB-C connector or a DisplayPort connector input port.
+
 required:
   - compatible
   - reg

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:46 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:46 +0200
Subject: [PATCH v5 08/18] phy: rockchip: usbdp: Rename DP lane functions
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-8-efc83069869f@collabora.com>

The common prefix for DisplayPort related functions is rk_udphy_dp_
(with a final _), so update the two DP lane functions to follow that
scheme.

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index bf8394174294..6d7ca11b308e 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -547,7 +547,7 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
  * ---------------------------------------------------------------------------
  */
 
-static void rk_udphy_dplane_select(struct rk_udphy *udphy)
+static void rk_udphy_dp_lane_select(struct rk_udphy *udphy)
 {
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	u32 value = 0;
@@ -576,7 +576,7 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
 }
 
-static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes)
+static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 {
 	u32 val = 0;
 	int i;
@@ -1072,9 +1072,9 @@ static int rk_udphy_dp_phy_power_on(struct phy *phy)
 	if (ret)
 		goto unlock;
 
-	rk_udphy_dplane_enable(udphy, udphy->dp_lanes);
+	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
 
-	rk_udphy_dplane_select(udphy);
+	rk_udphy_dp_lane_select(udphy);
 
 unlock:
 	mutex_unlock(&udphy->mutex);
@@ -1092,7 +1092,7 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
 	mutex_lock(&udphy->mutex);
-	rk_udphy_dplane_enable(udphy, 0);
+	rk_udphy_dp_lane_enable(udphy, 0);
 	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
 	mutex_unlock(&udphy->mutex);
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:43 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:43 +0200
Subject: [PATCH v5 05/18] phy: rockchip: usbdp: Fix LFPS detect threshold
 control
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-5-efc83069869f@collabora.com>

From: William Wu <william.wu at rock-chips.com>

According to the LFPS Tx Low Power/LFPS Rx Detect Threshold [1],
the device under test(DUT) must not respond if LFPS below the
minimum LFPS Rx Detect Threshold 100mV. Test fail on Rockchip
platforms, because the default LFPS detect threshold is set to
65mV.

The USBDP PHY LFPS detect threshold voltage could be set to
30mV ~ 140mV, and since there could be 10-20% PVT variation,
we set LFPS detect threshold voltage to 110mV.

[1] https://compliance.usb.org/resources/LFPS_Rx_Tx_Low_Power_Compliance_Update_Rev5.pdf

Signed-off-by: William Wu <william.wu at rock-chips.com>
[Taken over from rockchip's kernel tree; the registers are not described
in the TRM]
Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 1f686844c337..97e53b933225 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -413,7 +413,8 @@ static const struct reg_sequence rk_udphy_init_sequence[] = {
 	{0x0070, 0x7d}, {0x0074, 0x68},
 	{0x0af4, 0x1a}, {0x1af4, 0x1a},
 	{0x0440, 0x3f}, {0x10d4, 0x08},
-	{0x20d4, 0x08}, {0x0024, 0x6e}
+	{0x20d4, 0x08}, {0x0024, 0x6e},
+	{0x09c0, 0x0a}, {0x19c0, 0x0a}
 };
 
 static inline int rk_udphy_grfreg_write(struct regmap *base,

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:48 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:48 +0200
Subject: [PATCH v5 10/18] phy: rockchip: usbdp: Cleanup DP lane selection
 function
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-10-efc83069869f@collabora.com>

Use FIELD_PREP_WM16() helpers to simplify the DP lane selection
logic.

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 28 +++++++---------------------
 1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 1bfc365e2b2c..beab20e4c512 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -550,30 +550,16 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
 static void rk_udphy_dp_lane_select(struct rk_udphy *udphy)
 {
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
-	u32 value = 0;
-
-	switch (udphy->dp_lanes) {
-	case 4:
-		value |= 3 << udphy->dp_lane_sel[3] * 2;
-		value |= 2 << udphy->dp_lane_sel[2] * 2;
-		fallthrough;
-
-	case 2:
-		value |= 1 << udphy->dp_lane_sel[1] * 2;
-		fallthrough;
+	u32 value = FIELD_PREP_WM16(DP_LANE_SEL_ALL, 0);
+	int i;
 
-	case 1:
-		value |= 0 << udphy->dp_lane_sel[0] * 2;
-		break;
+	for (i = 0; i < udphy->dp_lanes; i++)
+		value |= field_prep(DP_LANE_SEL_N(udphy->dp_lane_sel[i]), i);
 
-	default:
-		break;
-	}
+	value |= FIELD_PREP_WM16(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel);
+	value |= FIELD_PREP_WM16(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel);
 
-	regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg,
-		     ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) |
-		     FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) |
-		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
+	regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, value);
 }
 
 static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:47 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:47 +0200
Subject: [PATCH v5 09/18] phy: rockchip: usbdp: Use FIELD_PREP_WM16_CONST
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-9-efc83069869f@collabora.com>

Cleanup code by replacing open-coded version of FIELD_PREP_WM16_CONST
with the existing helper macro.

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 6d7ca11b308e..1bfc365e2b2c 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -12,6 +12,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/hw_bitfield.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
@@ -75,7 +76,6 @@
 #define TRSV_LN2_MON_RX_CDR_DONE_OFFSET		0x1b84	/* trsv_reg06E1 */
 #define TRSV_LN2_MON_RX_CDR_LOCK_DONE		BIT(0)
 
-#define BIT_WRITEABLE_SHIFT			16
 #define PHY_AUX_DP_DATA_POL_NORMAL		0
 #define PHY_AUX_DP_DATA_POL_INVERT		1
 #define PHY_LANE_MUX_USB			0
@@ -104,8 +104,8 @@ struct rk_udphy_grf_reg {
 #define _RK_UDPHY_GEN_GRF_REG(offset, mask, disable, enable) \
 {\
 	offset, \
-	FIELD_PREP_CONST(mask, disable) | (mask << BIT_WRITEABLE_SHIFT), \
-	FIELD_PREP_CONST(mask, enable) | (mask << BIT_WRITEABLE_SHIFT), \
+	FIELD_PREP_WM16_CONST(mask, disable), \
+	FIELD_PREP_WM16_CONST(mask, enable), \
 }
 
 #define RK_UDPHY_GEN_GRF_REG(offset, bitend, bitstart, disable, enable) \

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:49 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:49 +0200
Subject: [PATCH v5 11/18] phy: rockchip: usbdp: Register DP aux bridge
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-11-efc83069869f@collabora.com>

Add support to use USB-C connectors with the DP altmode helper code on
devicetree based platforms. To get this working there must be a DRM
bridge chain from the DisplayPort controller to the USB-C connector.
E.g. on Rockchip RK3576:

root at rk3576 # cat /sys/kernel/debug/dri/0/encoder-0/bridges
bridge[0]: dw_dp_bridge_funcs
        refcount: 7
        type: [10] DP
        OF: /soc/dp at 27e40000:rockchip,rk3576-dp
        ops: [0x47] detect edid hpd
bridge[1]: drm_aux_bridge_funcs
        refcount: 4
        type: [0] Unknown
        OF: /soc/phy at 2b010000:rockchip,rk3576-usbdp-phy
        ops: [0x0]
bridge[2]: drm_aux_hpd_bridge_funcs
        refcount: 5
        type: [10] DP
        OF: /soc/i2c at 2ac50000/typec-portc at 22/connector:usb-c-connector
        ops: [0x4] hpd

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/Kconfig              |  2 ++
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 14 ++++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index 14698571b607..39759bb2fa1d 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -136,8 +136,10 @@ config PHY_ROCKCHIP_USBDP
 	tristate "Rockchip USBDP COMBO PHY Driver"
 	depends on ARCH_ROCKCHIP && OF
 	depends on TYPEC
+	depends on DRM || DRM=n
 	select GENERIC_PHY
 	select USB_COMMON
+	select DRM_AUX_BRIDGE if DRM_BRIDGE
 	help
 	  Enable this to support the Rockchip USB3.0/DP combo PHY with
 	  Samsung IP block. This is required for USB3 support on RK3588.
diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index beab20e4c512..77ad2a89d4f2 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2024 Collabora Ltd
  */
 
+#include <drm/bridge/aux-bridge.h>
 #include <dt-bindings/phy/phy.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
@@ -1434,6 +1435,7 @@ static int rk_udphy_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct phy_provider *phy_provider;
+	struct fwnode_handle *dp_aux_ep;
 	struct resource *res;
 	struct rk_udphy *udphy;
 	void __iomem *base;
@@ -1492,6 +1494,18 @@ static int rk_udphy_probe(struct platform_device *pdev)
 			return ret;
 	}
 
+	/*
+	 * Only register the DRM bridge, if the DP aux channel is connected.
+	 * Some boards use the USBDP PHY only for its USB3 capabilities.
+	 */
+	dp_aux_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 3, 0, 0);
+	if (dp_aux_ep) {
+		ret = drm_aux_bridge_register(dev);
+		fwnode_handle_put(dp_aux_ep);
+		if (ret)
+			return ret;
+	}
+
 	udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops);
 	if (IS_ERR(udphy->phy_u3)) {
 		ret = PTR_ERR(udphy->phy_u3);

-- 
2.53.0



From robh at kernel.org  Fri Jun 12 09:22:02 2026
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Jun 2026 11:22:02 -0500
Subject: [PATCH v3 1/3] dt-bindings: mfd: syscon: Disallow simple-bus
 with syscon
In-Reply-To: <20260608-n-dt-bindings-simple-bus-syscon-v3-1-4eba9ec1212a@oss.qualcomm.com>
References: <20260608-n-dt-bindings-simple-bus-syscon-v3-0-4eba9ec1212a@oss.qualcomm.com>
 <20260608-n-dt-bindings-simple-bus-syscon-v3-1-4eba9ec1212a@oss.qualcomm.com>
Message-ID: <178128132175.1153833.2573734544472661843.robh@kernel.org>


On Mon, 08 Jun 2026 22:44:24 +0200, Krzysztof Kozlowski wrote:
> "syscon" is a system controller with registers having their own
> functions, thus not really a trivial MMIO simple bus.  "simple-bus" on
> the other hand is just a bus on which multiple devices sit and the
> "simple" means no functions are allowed here.
> 
> Combination of both "syscon" and "simple-bus" is abuse of DT for easier
> instantiating of Linux device drivers so add a schema to disallow that.
> 
> Unfortunately there are a few old cases of that patterns, so add
> exceptions:
> 
> 1. "cznic,turris1x-cpld" and "img,pistachio-cr-periph" are already used
>    in upstream DTS.
> 
> 2. TI has several DTSI with a child of SCM device (e.g. "ti,am3-scm")
>    using "syscon" and "simple-bus" but without a dedicated compatible
>    documented anywhere.  Add new compatibles for such cases.
> 
> Additionally, add comments around code enforcing two or three
> compatibles: it is similar safeguard detecting incorrect bindings.
> 
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> 
> ---
> 
> Changes in v3:
> 1. s/ti,omap5-scm-conf/ti,omap5-sysc-padconf-global/ because it is more
>    appropriate (specific)
> 2. Add comments, why simple-mfd+syscon has dedicated if:then:
> 
> Changes in v2:
> 1. Complete patch. I accidentally sent only part of it, built on top of
>    internal WIP which I forgot to squash.
>    I received Ack from Rob, but change is significant, so please kindly
>    re-review.
> ---
>  .../devicetree/bindings/mfd/syscon-common.yaml     | 34 ++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
> 

Acked-by: Rob Herring (Arm) <robh at kernel.org>



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:52 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:52 +0200
Subject: [PATCH v5 14/18] phy: rockchip: usbdp: Re-init the PHY on
 orientation change
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-14-efc83069869f@collabora.com>

Changing the cable orientation reconfigures the lane muxing, which
requires re-initializing the PHY. Without this DP functionality
breaks, if the cable is re-plugged with swapped orientation.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index a3b4e2e0f578..89a08267611c 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -622,6 +622,7 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 				 enum typec_orientation orien)
 {
 	struct rk_udphy *udphy = typec_switch_get_drvdata(sw);
+	bool flipped = orien == TYPEC_ORIENTATION_REVERSE;
 
 	mutex_lock(&udphy->mutex);
 
@@ -633,7 +634,10 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 		goto unlock_ret;
 	}
 
-	udphy->flip = orien == TYPEC_ORIENTATION_REVERSE;
+	if (udphy->flip != flipped)
+		udphy->phy_needs_reinit = true;
+
+	udphy->flip = flipped;
 	rk_udphy_set_typec_default_mapping(udphy);
 	rk_udphy_usb_bvalid_enable(udphy, true);
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:44 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:44 +0200
Subject: [PATCH v5 06/18] phy: rockchip: usbdp: Add missing mode_change
 update
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-6-efc83069869f@collabora.com>

rk_udphy_set_typec_default_mapping() updates the available modes,
but does not set the mode_change as required. This results in
missing re-initialization and thus non-working DisplayPort.

Fix this issue by introducing a new helper to update the available
modes.

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 97e53b933225..febc148a754e 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -619,6 +619,15 @@ static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd)
 	rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd);
 }
 
+static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
+{
+	if (udphy->mode == mode)
+		return;
+
+	udphy->mode_change = true;
+	udphy->mode = mode;
+}
+
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 {
 	if (udphy->flip) {
@@ -649,7 +658,7 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1);
 	}
 
-	udphy->mode = UDPHY_MODE_DP_USB;
+	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -1385,10 +1394,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 			usleep_range(750, 800);
 			rk_udphy_dp_hpd_event_trigger(udphy, true);
 		} else if (data->status & DP_STATUS_HPD_STATE) {
-			if (udphy->mode != mode) {
-				udphy->mode = mode;
-				udphy->mode_change = true;
-			}
+			rk_udphy_mode_set(udphy, mode);
 			rk_udphy_dp_hpd_event_trigger(udphy, true);
 		} else {
 			rk_udphy_dp_hpd_event_trigger(udphy, false);

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:51 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:51 +0200
Subject: [PATCH v5 13/18] phy: rockchip: usbdp: Rename mode_change to
 phy_needs_reinit
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-13-efc83069869f@collabora.com>

Right now the mode_change property is set whenever the mode changes
between USB-only, DP-only and USB-DP. It is needed, because on any
mode change the PHY needs to be re-initialized. Apparently at least
DP also requires a re-init when the cable orientation is changed,
which is currently not being done (except when the orientation switch
also involves a mode change). Prepare for this by renaming mode_change
to phy_needs_reinit.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 7255c80e0fe2..a3b4e2e0f578 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -171,7 +171,7 @@ struct rk_udphy {
 
 	/* PHY status management */
 	bool flip;
-	bool mode_change;
+	bool phy_needs_reinit;
 	u8 mode;
 	u8 status;
 
@@ -580,7 +580,7 @@ static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 	if (udphy->mode == mode)
 		return;
 
-	udphy->mode_change = true;
+	udphy->phy_needs_reinit = true;
 	udphy->mode = mode;
 }
 
@@ -968,15 +968,15 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 	}
 
 	if (udphy->status == UDPHY_MODE_NONE) {
-		udphy->mode_change = false;
+		udphy->phy_needs_reinit = false;
 		ret = rk_udphy_setup(udphy);
 		if (ret)
 			return ret;
 
 		if (udphy->mode & UDPHY_MODE_USB)
 			rk_udphy_u3_port_disable(udphy, false);
-	} else if (udphy->mode_change) {
-		udphy->mode_change = false;
+	} else if (udphy->phy_needs_reinit) {
+		udphy->phy_needs_reinit = false;
 		if (udphy->mode == UDPHY_MODE_DP)
 			rk_udphy_u3_port_disable(udphy, true);
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:45 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:45 +0200
Subject: [PATCH v5 07/18] phy: rockchip: usbdp: Support single-lane DP
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-7-efc83069869f@collabora.com>

From: Zhang Yubing <yubing.zhang at rock-chips.com>

Implement support for using just a single DisplayPort line.

Signed-off-by: Zhang Yubing <yubing.zhang at rock-chips.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 61 +++++++++++++------------------
 1 file changed, 25 insertions(+), 36 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index febc148a754e..bf8394174294 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -193,6 +193,7 @@ struct rk_udphy {
 	int id;
 
 	bool dp_in_use;
+	int dp_lanes;
 
 	/* PHY const config */
 	const struct rk_udphy_cfg *cfgs;
@@ -537,6 +538,13 @@ static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable)
  * <0 1>                  dpln0         dpln1       usbrx         usbtx
  * <2 3>                  usbrx         usbtx       dpln0         dpln1
  * ---------------------------------------------------------------------------
+ * if 1 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x>;
+ * sample as follow:
+ * ---------------------------------------------------------------------------
+ *                        B11-B10       A2-A3       A11-A10       B2-B3
+ * rockchip,dp-lane-mux   ln0(tx/rx)    ln1(tx)     ln2(tx/rx)    ln3(tx)
+ * <0>                    dpln0         \           usbrx         usbtx
+ * ---------------------------------------------------------------------------
  */
 
 static void rk_udphy_dplane_select(struct rk_udphy *udphy)
@@ -544,18 +552,18 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	u32 value = 0;
 
-	switch (udphy->mode) {
-	case UDPHY_MODE_DP:
-		value |= 2 << udphy->dp_lane_sel[2] * 2;
+	switch (udphy->dp_lanes) {
+	case 4:
 		value |= 3 << udphy->dp_lane_sel[3] * 2;
+		value |= 2 << udphy->dp_lane_sel[2] * 2;
 		fallthrough;
 
-	case UDPHY_MODE_DP_USB:
-		value |= 0 << udphy->dp_lane_sel[0] * 2;
+	case 2:
 		value |= 1 << udphy->dp_lane_sel[1] * 2;
-		break;
+		fallthrough;
 
-	case UDPHY_MODE_USB:
+	case 1:
+		value |= 0 << udphy->dp_lane_sel[0] * 2;
 		break;
 
 	default:
@@ -568,28 +576,6 @@ static void rk_udphy_dplane_select(struct rk_udphy *udphy)
 		     FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value);
 }
 
-static int rk_udphy_dplane_get(struct rk_udphy *udphy)
-{
-	int dp_lanes;
-
-	switch (udphy->mode) {
-	case UDPHY_MODE_DP:
-		dp_lanes = 4;
-		break;
-
-	case UDPHY_MODE_DP_USB:
-		dp_lanes = 2;
-		break;
-
-	case UDPHY_MODE_USB:
-	default:
-		dp_lanes = 0;
-		break;
-	}
-
-	return dp_lanes;
-}
-
 static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes)
 {
 	u32 val = 0;
@@ -659,6 +645,7 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 	}
 
 	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
+	udphy->dp_lanes = 2;
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -897,7 +884,7 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 		return 0;
 	}
 
-	if (num_lanes != 2 && num_lanes != 4)
+	if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4)
 		return dev_err_probe(udphy->dev, -EINVAL,
 				     "invalid number of lane mux\n");
 
@@ -923,7 +910,8 @@ static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy)
 	}
 
 	udphy->mode = UDPHY_MODE_DP;
-	if (num_lanes == 2) {
+	udphy->dp_lanes = num_lanes;
+	if (num_lanes == 1 || num_lanes == 2) {
 		udphy->mode |= UDPHY_MODE_USB;
 		udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP);
 	}
@@ -1074,18 +1062,17 @@ static int rk_udphy_dp_phy_exit(struct phy *phy)
 static int rk_udphy_dp_phy_power_on(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
-	int ret, dp_lanes;
+	int ret;
 
 	mutex_lock(&udphy->mutex);
 
-	dp_lanes = rk_udphy_dplane_get(udphy);
-	phy_set_bus_width(phy, dp_lanes);
+	phy_set_bus_width(phy, udphy->dp_lanes);
 
 	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
 	if (ret)
 		goto unlock;
 
-	rk_udphy_dplane_enable(udphy, dp_lanes);
+	rk_udphy_dplane_enable(udphy, udphy->dp_lanes);
 
 	rk_udphy_dplane_select(udphy);
 
@@ -1365,6 +1352,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
 		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		mode = UDPHY_MODE_DP;
+		udphy->dp_lanes = 4;
 		break;
 
 	case TYPEC_DP_STATE_D:
@@ -1381,6 +1369,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		}
 		mode = UDPHY_MODE_DP_USB;
+		udphy->dp_lanes = 2;
 		break;
 	}
 
@@ -1529,7 +1518,7 @@ static int rk_udphy_probe(struct platform_device *pdev)
 		ret = PTR_ERR(udphy->phy_dp);
 		return dev_err_probe(dev, ret, "failed to create DP phy\n");
 	}
-	phy_set_bus_width(udphy->phy_dp, rk_udphy_dplane_get(udphy));
+	phy_set_bus_width(udphy->phy_dp, udphy->dp_lanes);
 	udphy->phy_dp->attrs.max_link_rate = 8100;
 	phy_set_drvdata(udphy->phy_dp, udphy);
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:50 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:50 +0200
Subject: [PATCH v5 12/18] phy: rockchip: usbdp: Drop DP HPD handling
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-12-efc83069869f@collabora.com>

Drop the HPD handling logic from the USBDP PHY. The registers involved
require the display controller power domain being enabled and thus the
HPD signal should be handled by the displayport controller itself.
Apart from that the HPD handling as it is done here is incorrect and
misses hotplug events happening after the USB-C connector (e.g. when
a USB-C to HDMI adapter is involved and the HDMI cable is replugged).

Proper USB-C DP HPD support requires some restructuring of the DP
controller driver, which will happen independent of this patch. The
mainline kernel does not yet support USB-C DP AltMode on RK3588 and
RK3576, so it is fine to drop this code without adding the counterpart
in the DRM in an atomic change.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 85 ++++---------------------------
 1 file changed, 9 insertions(+), 76 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 77ad2a89d4f2..7255c80e0fe2 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -128,7 +128,6 @@ struct rk_udphy_grf_cfg {
 
 struct rk_udphy_vogrf_cfg {
 	/* vo-grf */
-	struct rk_udphy_grf_reg hpd_trigger;
 	u32 dp_lane_reg;
 };
 
@@ -186,14 +185,11 @@ struct rk_udphy {
 	u32 dp_lane_sel[4];
 	u32 dp_aux_dout_sel;
 	u32 dp_aux_din_sel;
-	bool dp_sink_hpd_sel;
-	bool dp_sink_hpd_cfg;
 	unsigned int link_rate;
 	unsigned int lanes;
 	u8 bw;
 	int id;
 
-	bool dp_in_use;
 	int dp_lanes;
 
 	/* PHY const config */
@@ -579,19 +575,6 @@ static void rk_udphy_dp_lane_enable(struct rk_udphy *udphy, int dp_lanes)
 				   CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0));
 }
 
-static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd)
-{
-	const struct rk_udphy_cfg *cfg = udphy->cfgs;
-
-	udphy->dp_sink_hpd_sel = true;
-	udphy->dp_sink_hpd_cfg = hpd;
-
-	if (!udphy->dp_in_use)
-		return;
-
-	rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd);
-}
-
 static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 {
 	if (udphy->mode == mode)
@@ -1023,29 +1006,6 @@ static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode)
 		rk_udphy_disable(udphy);
 }
 
-static int rk_udphy_dp_phy_init(struct phy *phy)
-{
-	struct rk_udphy *udphy = phy_get_drvdata(phy);
-
-	mutex_lock(&udphy->mutex);
-
-	udphy->dp_in_use = true;
-
-	mutex_unlock(&udphy->mutex);
-
-	return 0;
-}
-
-static int rk_udphy_dp_phy_exit(struct phy *phy)
-{
-	struct rk_udphy *udphy = phy_get_drvdata(phy);
-
-	mutex_lock(&udphy->mutex);
-	udphy->dp_in_use = false;
-	mutex_unlock(&udphy->mutex);
-	return 0;
-}
-
 static int rk_udphy_dp_phy_power_on(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
@@ -1274,8 +1234,6 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
 }
 
 static const struct phy_ops rk_udphy_dp_phy_ops = {
-	.init		= rk_udphy_dp_phy_init,
-	.exit		= rk_udphy_dp_phy_exit,
 	.power_on	= rk_udphy_dp_phy_power_on,
 	.power_off	= rk_udphy_dp_phy_power_off,
 	.configure	= rk_udphy_dp_phy_configure,
@@ -1329,6 +1287,14 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
 	u8 mode;
 
+	/*
+	 * Ignore mux events not involving DP AltMode, because
+	 * the mode field is being reused, e.g. state->mode == 4
+	 * could be either TYPEC_MODE_USB4 or TYPEC_DP_STATE_C.
+	 */
+	if (!state->alt || state->alt->svid != USB_TYPEC_DP_SID)
+		return 0;
+
 	mutex_lock(&udphy->mutex);
 
 	switch (state->mode) {
@@ -1360,22 +1326,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 		break;
 	}
 
-	if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) {
-		struct typec_displayport_data *data = state->data;
-
-		if (!data) {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-		} else if (data->status & DP_STATUS_IRQ_HPD) {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-			usleep_range(750, 800);
-			rk_udphy_dp_hpd_event_trigger(udphy, true);
-		} else if (data->status & DP_STATUS_HPD_STATE) {
-			rk_udphy_mode_set(udphy, mode);
-			rk_udphy_dp_hpd_event_trigger(udphy, true);
-		} else {
-			rk_udphy_dp_hpd_event_trigger(udphy, false);
-		}
-	}
+	rk_udphy_mode_set(udphy, mode);
 
 	mutex_unlock(&udphy->mutex);
 	return 0;
@@ -1531,20 +1482,6 @@ static int rk_udphy_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __maybe_unused rk_udphy_resume(struct device *dev)
-{
-	struct rk_udphy *udphy = dev_get_drvdata(dev);
-
-	if (udphy->dp_sink_hpd_sel)
-		rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg);
-
-	return 0;
-}
-
-static const struct dev_pm_ops rk_udphy_pm_ops = {
-	SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, rk_udphy_resume)
-};
-
 static const char * const rk_udphy_rst_list[] = {
 	"init", "cmn", "lane", "pcs_apb", "pma_apb"
 };
@@ -1568,7 +1505,6 @@ static const struct rk_udphy_cfg rk3576_udphy_cfgs = {
 	},
 	.vogrfcfg = {
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3),
 			.dp_lane_reg    = 0x0000,
 		},
 	},
@@ -1609,11 +1545,9 @@ static const struct rk_udphy_cfg rk3588_udphy_cfgs = {
 	},
 	.vogrfcfg = {
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3),
 			.dp_lane_reg	= 0x0000,
 		},
 		{
-			.hpd_trigger	= RK_UDPHY_GEN_GRF_REG(0x0008, 11, 10, 1, 3),
 			.dp_lane_reg	= 0x0008,
 		},
 	},
@@ -1649,7 +1583,6 @@ static struct platform_driver rk_udphy_driver = {
 	.driver		= {
 		.name	= "rockchip-usbdp-phy",
 		.of_match_table = rk_udphy_dt_match,
-		.pm = &rk_udphy_pm_ops,
 	},
 };
 module_platform_driver(rk_udphy_driver);

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:55 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:55 +0200
Subject: [PATCH v5 17/18] phy: rockchip: usbdp: Support going from DP-only
 mode to USB mode
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-17-efc83069869f@collabora.com>

When a USB-C adapter, which maps all Superspeed lanes to DP is plugged
in, the USB support is disabled in the PHY. When the adapter is
unplugged and a different adapter with USB functionality is plugged in
afterwards, USB functionality is not restored as the USB controller
keeps the PHY enabled for the entire time.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index f673c5481d24..236331cc0d13 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -178,6 +178,7 @@ struct rk_udphy {
 
 	/* utilized for USB */
 	bool hs; /* flag for high-speed */
+	bool usb_in_use;
 
 	/* utilized for DP */
 	struct gpio_desc *sbu1_dc_gpio;
@@ -1015,6 +1016,9 @@ static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode)
 		ret = rk_udphy_init(udphy);
 		if (ret)
 			return ret;
+
+		if (udphy->mode & UDPHY_MODE_USB)
+			rk_udphy_u3_port_disable(udphy, false);
 	}
 
 	udphy->status |= mode;
@@ -1278,6 +1282,8 @@ static int rk_udphy_usb3_phy_init(struct phy *phy)
 
 	guard(mutex)(&udphy->mutex);
 
+	udphy->usb_in_use = true;
+
 	/* DP only or high-speed, disable U3 port */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
 		rk_udphy_u3_port_disable(udphy, true);
@@ -1295,6 +1301,8 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
 
 	guard(mutex)(&udphy->mutex);
 
+	udphy->usb_in_use = false;
+
 	/* DP only or high-speed */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
 		return 0;
@@ -1314,6 +1322,7 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 				  struct typec_mux_state *state)
 {
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
+	u8 old_mode;
 
 	/*
 	 * Ignore mux events not involving DP AltMode, because
@@ -1325,8 +1334,20 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 
 	guard(mutex)(&udphy->mutex);
 
+	old_mode = udphy->mode;
+
 	rk_udphy_set_typec_state(udphy, state->mode);
 
+	/*
+	 * If the new mode includes USB but the old one didn't (e.g. leaving
+	 * DP-only), and the USB PHY was already initialized by the USB
+	 * controller, we need to power on the USB side now since no
+	 * subsequent phy_init call will come from the controller.
+	 */
+	if ((udphy->mode & UDPHY_MODE_USB) && !(old_mode & UDPHY_MODE_USB) &&
+	    udphy->usb_in_use && !udphy->hs)
+		rk_udphy_power_on(udphy, UDPHY_MODE_USB);
+
 	return 0;
 }
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:53 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:53 +0200
Subject: [PATCH v5 15/18] phy: rockchip: usbdp: Factor out lane_mux_sel
 setup
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-15-efc83069869f@collabora.com>

Avoid describing the USB+DP lane_mux_sel logic twice by introducing
a helper function to reduce code duplication.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 81 +++++++++++++++----------------
 1 file changed, 40 insertions(+), 41 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 89a08267611c..4ba8b6f0a954 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -584,6 +584,42 @@ static void rk_udphy_mode_set(struct rk_udphy *udphy, u8 mode)
 	udphy->mode = mode;
 }
 
+static void rk_udphy_set_typec_state(struct rk_udphy *udphy, unsigned long state)
+{
+	u8 mode;
+
+	switch (state) {
+	case TYPEC_DP_STATE_C:
+	case TYPEC_DP_STATE_E:
+		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
+		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
+		mode = UDPHY_MODE_DP;
+		udphy->dp_lanes = 4;
+		break;
+
+	case TYPEC_DP_STATE_D:
+	default:
+		if (udphy->flip) {
+			udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
+		} else {
+			udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
+			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
+			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
+		}
+		mode = UDPHY_MODE_DP_USB;
+		udphy->dp_lanes = 2;
+		break;
+	}
+
+	rk_udphy_mode_set(udphy, mode);
+}
+
 static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 {
 	if (udphy->flip) {
@@ -591,10 +627,6 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		udphy->dp_lane_sel[1] = 1;
 		udphy->dp_lane_sel[2] = 3;
 		udphy->dp_lane_sel[3] = 2;
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
 		udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT;
 		udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT;
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1);
@@ -604,18 +636,14 @@ static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy)
 		udphy->dp_lane_sel[1] = 3;
 		udphy->dp_lane_sel[2] = 1;
 		udphy->dp_lane_sel[3] = 0;
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
 		udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL;
 		udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL;
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0);
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1);
 	}
 
-	rk_udphy_mode_set(udphy, UDPHY_MODE_DP_USB);
-	udphy->dp_lanes = 2;
+	/* default to USB3 + DP as 4 lane USB is not supported */
+	rk_udphy_set_typec_state(udphy, TYPEC_DP_STATE_D);
 }
 
 static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
@@ -1289,7 +1317,6 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 				  struct typec_mux_state *state)
 {
 	struct rk_udphy *udphy = typec_mux_get_drvdata(mux);
-	u8 mode;
 
 	/*
 	 * Ignore mux events not involving DP AltMode, because
@@ -1301,38 +1328,10 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 
 	mutex_lock(&udphy->mutex);
 
-	switch (state->mode) {
-	case TYPEC_DP_STATE_C:
-	case TYPEC_DP_STATE_E:
-		udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-		udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		mode = UDPHY_MODE_DP;
-		udphy->dp_lanes = 4;
-		break;
-
-	case TYPEC_DP_STATE_D:
-	default:
-		if (udphy->flip) {
-			udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB;
-		} else {
-			udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB;
-			udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP;
-			udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP;
-		}
-		mode = UDPHY_MODE_DP_USB;
-		udphy->dp_lanes = 2;
-		break;
-	}
-
-	rk_udphy_mode_set(udphy, mode);
+	rk_udphy_set_typec_state(udphy, state->mode);
 
 	mutex_unlock(&udphy->mutex);
+
 	return 0;
 }
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:54 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:54 +0200
Subject: [PATCH v5 16/18] phy: rockchip: usbdp: Use guard functions for
 mutex
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-16-efc83069869f@collabora.com>

Convert the driver to use guard functions for mutex handling as
a small cleanup. There is a small functional change in the DP PHY
power up function, which no longer sleeps if the internal powerup
code returns an error. This is not a problem as the sleep is only
relevant for successful power-up.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 51 ++++++++++++++-----------------
 1 file changed, 23 insertions(+), 28 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 4ba8b6f0a954..f673c5481d24 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -10,6 +10,7 @@
 #include <dt-bindings/phy/phy.h>
 #include <linux/bitfield.h>
 #include <linux/bits.h>
+#include <linux/cleanup.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
@@ -652,14 +653,15 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 	struct rk_udphy *udphy = typec_switch_get_drvdata(sw);
 	bool flipped = orien == TYPEC_ORIENTATION_REVERSE;
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
 
 	if (orien == TYPEC_ORIENTATION_NONE) {
 		gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0);
 		gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0);
 		/* unattached */
 		rk_udphy_usb_bvalid_enable(udphy, false);
-		goto unlock_ret;
+
+		return 0;
 	}
 
 	if (udphy->flip != flipped)
@@ -669,8 +671,6 @@ static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw,
 	rk_udphy_set_typec_default_mapping(udphy);
 	rk_udphy_usb_bvalid_enable(udphy, true);
 
-unlock_ret:
-	mutex_unlock(&udphy->mutex);
 	return 0;
 }
 
@@ -1043,26 +1043,25 @@ static int rk_udphy_dp_phy_power_on(struct phy *phy)
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 	int ret;
 
-	mutex_lock(&udphy->mutex);
+	scoped_guard(mutex, &udphy->mutex) {
+		phy_set_bus_width(phy, udphy->dp_lanes);
 
-	phy_set_bus_width(phy, udphy->dp_lanes);
-
-	ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
-	if (ret)
-		goto unlock;
+		ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP);
+		if (ret)
+			return ret;
 
-	rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
+		rk_udphy_dp_lane_enable(udphy, udphy->dp_lanes);
 
-	rk_udphy_dp_lane_select(udphy);
+		rk_udphy_dp_lane_select(udphy);
+	}
 
-unlock:
-	mutex_unlock(&udphy->mutex);
 	/*
 	 * If data send by aux channel too fast after phy power on,
 	 * the aux may be not ready which will cause aux error. Adding
 	 * delay to avoid this issue.
 	 */
 	usleep_range(10000, 11000);
+
 	return ret;
 }
 
@@ -1070,10 +1069,10 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
+
 	rk_udphy_dp_lane_enable(udphy, 0);
 	rk_udphy_power_off(udphy, UDPHY_MODE_DP);
-	mutex_unlock(&udphy->mutex);
 
 	return 0;
 }
@@ -1275,19 +1274,18 @@ static const struct phy_ops rk_udphy_dp_phy_ops = {
 static int rk_udphy_usb3_phy_init(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
-	int ret = 0;
+	int ret;
+
+	guard(mutex)(&udphy->mutex);
 
-	mutex_lock(&udphy->mutex);
 	/* DP only or high-speed, disable U3 port */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) {
 		rk_udphy_u3_port_disable(udphy, true);
-		goto unlock;
+		return 0;
 	}
 
 	ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB);
 
-unlock:
-	mutex_unlock(&udphy->mutex);
 	return ret;
 }
 
@@ -1295,15 +1293,14 @@ static int rk_udphy_usb3_phy_exit(struct phy *phy)
 {
 	struct rk_udphy *udphy = phy_get_drvdata(phy);
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
+
 	/* DP only or high-speed */
 	if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs)
-		goto unlock;
+		return 0;
 
 	rk_udphy_power_off(udphy, UDPHY_MODE_USB);
 
-unlock:
-	mutex_unlock(&udphy->mutex);
 	return 0;
 }
 
@@ -1326,12 +1323,10 @@ static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux,
 	if (!state->alt || state->alt->svid != USB_TYPEC_DP_SID)
 		return 0;
 
-	mutex_lock(&udphy->mutex);
+	guard(mutex)(&udphy->mutex);
 
 	rk_udphy_set_typec_state(udphy, state->mode);
 
-	mutex_unlock(&udphy->mutex);
-
 	return 0;
 }
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 09:21:56 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:21:56 +0200
Subject: [PATCH v5 18/18] phy: rockchip: usbdp: Add some extra debug
 messages
In-Reply-To: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
References: <20260612-rockchip-usbdp-cleanup-v5-0-efc83069869f@collabora.com>
Message-ID: <20260612-rockchip-usbdp-cleanup-v5-18-efc83069869f@collabora.com>

It's useful to log PHY reinit to ease debugging issues around
USB-C hotplugging.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/phy/rockchip/phy-rockchip-usbdp.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 236331cc0d13..4042e2dd8121 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -491,6 +491,8 @@ static void rk_udphy_u3_port_disable(struct rk_udphy *udphy, u8 disable)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	const struct rk_udphy_grf_reg *preg;
 
+	dev_dbg(udphy->dev, "USB3 port %s\n", str_on_off(!disable));
+
 	preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg;
 	rk_udphy_grfreg_write(udphy->usbgrf, preg, disable);
 }
@@ -784,6 +786,10 @@ static int rk_udphy_init(struct rk_udphy *udphy)
 	const struct rk_udphy_cfg *cfg = udphy->cfgs;
 	int ret;
 
+	dev_dbg(udphy->dev, "(re-)init PHY with USB=%s and DP=%s\n",
+		str_enabled_disabled(udphy->mode & UDPHY_MODE_USB),
+		str_enabled_disabled(udphy->mode & UDPHY_MODE_DP));
+
 	rk_udphy_reset_assert_all(udphy);
 	usleep_range(10000, 11000);
 
@@ -854,6 +860,8 @@ static int rk_udphy_setup(struct rk_udphy *udphy)
 {
 	int ret;
 
+	dev_dbg(udphy->dev, "enable PHY\n");
+
 	ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks);
 	if (ret) {
 		dev_err(udphy->dev, "failed to enable clk\n");
@@ -872,6 +880,7 @@ static int rk_udphy_setup(struct rk_udphy *udphy)
 
 static void rk_udphy_disable(struct rk_udphy *udphy)
 {
+	dev_dbg(udphy->dev, "disable PHY\n");
 	clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks);
 	rk_udphy_reset_assert_all(udphy);
 }

-- 
2.53.0



From broonie at kernel.org  Fri Jun 12 09:30:57 2026
From: broonie at kernel.org (Mark Brown)
Date: Fri, 12 Jun 2026 17:30:57 +0100
Subject: [PATCH 4/4] regulator: Add support for UGREEN NASync DH2300 MCU
 SATA power gate
In-Reply-To: <20260612-dh2300-mcu-v1-4-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
 <20260612-dh2300-mcu-v1-4-ab8db1617bc0@flipper.net>
Message-ID: <aiw0QYnaYHQpIwiq@sirena.co.uk>

On Fri, Jun 12, 2026 at 07:34:17PM +0400, Alexey Charkov wrote:

> +static int ugreen_dh2300_mcu_regulator_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct regulator_config config = { };
> +	struct regulator_dev *rdev;
> +	struct device_node *np;
> +
> +	np = of_get_child_by_name(dev->parent->of_node, "regulator");
> +	if (!np)
> +		return dev_err_probe(dev, -ENODEV,
> +				     "missing regulator child node\n");

You should just be able to configured this in the regulator_desc rather
than describe it.

> +	config.init_data = of_get_regulator_init_data(dev, np,
> +						      &ugreen_dh2300_sata_desc);
> +

Similarly here, there should be no need for this open coding.
-------------- 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-rockchip/attachments/20260612/9f720122/attachment.sig>

From sebastian.reichel at collabora.com  Fri Jun 12 09:37:42 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 18:37:42 +0200
Subject: [PATCH v2 07/12] drm/rockchip: dw_dp: Implement out-of-band HPD
 handling
In-Reply-To: <4f4ff085-80ae-4144-b040-be9b136574ee@rock-chips.com>
References: <20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f@collabora.com>
 <20260501-synopsys-dw-dp-improvements-v2-7-d7e7f6bac77f@collabora.com>
 <4f4ff085-80ae-4144-b040-be9b136574ee@rock-chips.com>
Message-ID: <aiw0VKuj6Y6tpr9f@venus>

Hello Chaoyi,

On Tue, Jun 02, 2026 at 04:30:59PM +0800, Chaoyi Chen wrote:
> On 5/1/2026 6:20 AM, Sebastian Reichel wrote:
> > Implement out-of-band hotplug handling, which will be used to receive
> > external hotplug information from the USB-C state machine. This is
> > currently handled by the USBDP PHY, which brings quite some trouble
> > as the register being accessed requires the power-domain from the DP
> > controller and also requires custom TypeC HPD info parsing in the
> > USBDP PHY driver.
> > 
> > In contrast to the USBDP PHY this does not just enable the hotplug
> > signal when a DP AltMode capable adapter is plugged in, but instead
> > properly detects if a cable is plugged in for things like USB-C to
> > HDMI adapters.
> > 
> > Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> 
> [...]
> 
> > +static void dw_dp_rockchip_hpd_sw_cfg(void *data, bool hpd)
> > +{
> > +	struct rockchip_dw_dp *dp = data;
> > +	u32 hpd_reg = dp->pdata->hpd_reg[dp->id];
> > +
> > +	dev_dbg(dp->dev, "Force HPD connected=%s\n", str_yes_no(hpd));
> > +
> > +	dp->hpd_cfg = hpd;
> > +
> > +	regmap_write(dp->vo_grf, hpd_reg,
> > +		     FIELD_PREP_WM16_CONST(ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG, dp->hpd_cfg));
> 
> FIELD_PREP_WM16() should be used here because "dp->hpd_cfg" is not
> a constant expression.
> 
> Other patches in this series have similar issues. Doesn't your
> compiler warn you about this? Thanks.

The code builds warning free for me. Also FIELD_PREP_WM16_CONST
requies that the mask is constant, which is the first argument
(i.e. ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG in this case). The second
argument should be fine as a variable as far as I can tell.

But since FIELD_PREP_WM16 is shorter anyways, gives better error
handling and can be used for all occuances in the dw-dp rockchip
glue I will use that instead.

Thanks,

-- Sebastian
-------------- 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-rockchip/attachments/20260612/0bbbf846/attachment.sig>

From conor at kernel.org  Fri Jun 12 09:43:04 2026
From: conor at kernel.org (Conor Dooley)
Date: Fri, 12 Jun 2026 17:43:04 +0100
Subject: [PATCH 1/4] dt-bindings: vendor-prefixes: Add Ugreen Group
 Limited
In-Reply-To: <20260612-dh2300-mcu-v1-1-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
 <20260612-dh2300-mcu-v1-1-ab8db1617bc0@flipper.net>
Message-ID: <20260612-chirping-catacomb-acb53680c4c4@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-rockchip/attachments/20260612/b678da07/attachment.sig>

From foss+kernel at 0leil.net  Fri Jun 12 09:47:34 2026
From: foss+kernel at 0leil.net (Quentin Schulz)
Date: Fri, 12 Jun 2026 18:47:34 +0200
Subject: [PATCH] arm64: dts: rockchip: fix eMMC reset polarity on PP-1516
Message-ID: <20260612-pp1516-emmc-polarity-v1-1-4816c1c909f7@cherry.de>

From: Quentin Schulz <quentin.schulz at cherry.de>

According to the Jedec 5.1 specification, the device is held in reset
when RST_n is low, therefore the polarity of the line must be that, as
specified in the Device Tree binding (mmc/mmc-pwrseq-emmc.yaml).

Due to the wrong polarity, eMMC devices with RST_n_FUNCTION[162]
bitfield [1:0] set to 0x1 (the default is 0x0) will be held in reset
forever.

Cc: stable at vger.kernel.org
Fixes: 56198acdbf0d ("arm64: dts: rockchip: add px30-pp1516 base dtsi and board variants")
Signed-off-by: Quentin Schulz <quentin.schulz at cherry.de>
---
PP-1516 is affected by the same issue that Cobra has and for which a
patch[1] has already been sent.

[1] https://lore.kernel.org/linux-rockchip/20260609081728.30616-2-jakobunt at gmail.com/
---
 arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi b/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi
index 192791993f059..02200de695d31 100644
--- a/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi
+++ b/arch/arm64/boot/dts/rockchip/px30-pp1516.dtsi
@@ -33,7 +33,7 @@ emmc_pwrseq: emmc-pwrseq {
 		compatible = "mmc-pwrseq-emmc";
 		pinctrl-0 = <&emmc_reset>;
 		pinctrl-names = "default";
-		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
+		reset-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_LOW>;
 	};
 
 	gpio-leds {

---
base-commit: 2b414a95b8f7307d42173ba9e580d6d3e2bcbfce
change-id: 20260612-pp1516-emmc-polarity-5a7fb54db917

Best regards,
--  
Quentin Schulz <quentin.schulz at cherry.de>



From detlev.casanova at collabora.com  Fri Jun 12 10:25:02 2026
From: detlev.casanova at collabora.com (Detlev Casanova)
Date: Fri, 12 Jun 2026 13:25:02 -0400
Subject: [PATCH 3/3] media: hantro: add per-context fdinfo usage stats
In-Reply-To: <a83b7ce30ffc423128e3a3b7d5a03baa8cba6216.camel@collabora.com>
References: <20260612-v4l2-add-fdinfo-v1-0-723211abc861@collabora.com>
 <20260612-v4l2-add-fdinfo-v1-3-723211abc861@collabora.com>
 <a83b7ce30ffc423128e3a3b7d5a03baa8cba6216.camel@collabora.com>
Message-ID: <cece4025-950f-4081-af3a-a1548f9df0a1@collabora.com>

Hi Nicolas,

On 6/12/26 11:18, Nicolas Dufresne wrote:
> Hi,
>
> Le vendredi 12 juin 2026 ? 10:26 -0400, Detlev Casanova a ?crit?:
>> From: Christopher Healy <healych at amazon.com>
>>
>> Add per-file-descriptor hardware utilization tracking to the Hantro
>> VPU stateless codec driver, exposed via /proc/<pid>/fdinfo/<fd>.
>>
>> Record a ktime timestamp when each job is submitted to hardware in
>> device_run(), and accumulate the elapsed nanoseconds when the job
>> completes in hantro_job_finish(). Report the accumulated time along
>> with the current clock frequency through the new V4L2 show_fdinfo
>> callback.
>>
>> The output uses a media- key prefix with the following keys:
>>  ? media-driver:?????????? driver name
>>  ? media-engine-<eng>:???? accumulated busy time in nanoseconds
>>  ? media-maxfreq-<eng>:??? maximum engine frequency in Hz
>>  ? media-curfreq-<eng>:??? current engine frequency in Hz
>>
>> Where <eng> is "decoder" or "encoder" depending on the context.
>>
>> This enables userspace monitoring tools to compute per-process decoder
>> and encoder utilization. The current and max frequency keys report the
>> same value today since the driver lacks devfreq support, but will
>> diverge once DVFS is added, allowing userspace to approximate true
>> capacity utilization without any fdinfo code changes. A future series
>> can add hardware cycle counter support (via media-cycles-<eng>) for
>> exact utilization under DVFS, with no changes to the existing uAPI.
>>
>> Signed-off-by: Christopher Healy <healych at amazon.com>
>> Signed-off-by: Detlev Casanova <detlev.casanova at collabora.com>
>> ---
>>  ?drivers/media/platform/verisilicon/hantro.h???? |? 5 +++++
>>  ?drivers/media/platform/verisilicon/hantro_drv.c | 22 ++++++++++++++++++++++
>>  ?2 files changed, 27 insertions(+)
>>
>> diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
>> index 0353de154a1e..10287e5cebac 100644
>> --- a/drivers/media/platform/verisilicon/hantro.h
>> +++ b/drivers/media/platform/verisilicon/hantro.h
>> @@ -16,6 +16,7 @@
>>  ?#include <linux/videodev2.h>
>>  ?#include <linux/wait.h>
>>  ?#include <linux/clk.h>
>> +#include <linux/ktime.h>
>>  ?#include <linux/reset.h>
>>   
>>  ?#include <media/v4l2-ctrls.h>
>> @@ -268,6 +269,10 @@ struct hantro_ctx {
>>  ?	struct hantro_postproc_ctx postproc;
>>  ?	bool need_postproc;
>>   
>> +	/* Statistics for debugging and performance measurements. */
>> +	ktime_t start_time;
>> +	u64 total_ns;
>> +
>>  ?	/* Specific for particular codec modes. */
>>  ?	union {
>>  ?		struct hantro_h264_dec_hw_ctx h264_dec;
>> diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
>> index 2e81877f640f..139c2e6a83aa 100644
>> --- a/drivers/media/platform/verisilicon/hantro_drv.c
>> +++ b/drivers/media/platform/verisilicon/hantro_drv.c
>> @@ -90,6 +90,8 @@ static void hantro_job_finish(struct hantro_dev *vpu,
>>  ?			????? struct hantro_ctx *ctx,
>>  ?			????? enum vb2_buffer_state result)
>>  ?{
>> +	ctx->total_ns += ktime_to_ns(ktime_sub(ktime_get(), ctx->start_time));
>> +
>>  ?	pm_runtime_put_autosuspend(vpu->dev);
>>   
>>  ?	clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks);
>> @@ -186,6 +188,8 @@ static void device_run(void *priv)
>>   
>>  ?	v4l2_m2m_buf_copy_metadata(src, dst);
>>   
>> +	ctx->start_time = ktime_get();
>> +
>>  ?	if (ctx->codec_ops->run(ctx))
>>  ?		goto err_cancel_job;
>>   
>> @@ -701,10 +705,28 @@ static int hantro_release(struct file *filp)
>>  ?	return 0;
>>  ?}
>>   
>> +static void hantro_show_fdinfo(struct seq_file *m, struct file *f)
>> +{
>> +	struct hantro_ctx *ctx = file_to_ctx(f);
>> +	struct hantro_dev *vpu = ctx->dev;
>> +
>> +	seq_printf(m, "media-driver:\t%s\n", DRIVER_NAME);
>> +	seq_printf(m, "media-engine-%s:\t%llu ns\n",
>> +		?? ctx->is_encoder ? "encoder" : "decoder",
>> +		?? ctx->total_ns);
>> +	seq_printf(m, "media-maxfreq-%s:\t%lu Hz\n",
>> +		?? ctx->is_encoder ? "encoder" : "decoder",
>> +		?? clk_get_rate(vpu->clocks[0].clk));
>> +	seq_printf(m, "media-curfreq-%s:\t%lu Hz\n",
>> +		?? ctx->is_encoder ? "encoder" : "decoder",
>> +		?? clk_get_rate(vpu->clocks[0].clk));
> Similar to what was done in DRM helpers, I would create a common structure,
> maybe in a v4l2-stats library (or some better name). The driver would fill that
> structure directly, or through helpers (such as software timer helper, cycle
> count translation helper), and finally, this show_fd_info() would be a one
> liners, just like DRM do.
>
> This will ensure full consistency in the trace, and avoid possible future
> unresolvable compatibility issue due to past mistakes. If we ever let a bug
> through (of course we won't :-D) all driver will have the same bug, and it will
> be easier to not break userspace.
Yes, that makes a lot of sense actually, And will also help with the 
ftrace HW info if we have stats and debug info centralized in v4l2
> Nicolas
>
>> +}
>> +
>>  ?static const struct v4l2_file_operations hantro_fops = {
>>  ?	.owner = THIS_MODULE,
>>  ?	.open = hantro_open,
>>  ?	.release = hantro_release,
>> +	.show_fdinfo = hantro_show_fdinfo,
>>  ?	.poll = v4l2_m2m_fop_poll,
>>  ?	.unlocked_ioctl = video_ioctl2,
>>  ?	.mmap = v4l2_m2m_fop_mmap,



From cristian.ciocaltea at collabora.com  Fri Jun 12 10:40:01 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 20:40:01 +0300
Subject: [PATCH v7 01/30] drm/fb-helper: Remove unused local variable in
 hotplug_event()
In-Reply-To: <c7866bc4-bf37-4f8c-ae64-2d1d3a23f1ef@suse.de>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-1-445eb54ee1ed@collabora.com>
 <c7866bc4-bf37-4f8c-ae64-2d1d3a23f1ef@suse.de>
Message-ID: <be231e53-3c4c-424d-bc62-4d3a0007af64@collabora.com>

Hi Thomas,

On 6/12/26 4:46 PM, Thomas Zimmermann wrote:
> 
> 
> Am 02.06.26 um 00:44 schrieb Cristian Ciocaltea:
>> Remove the 'err' local variable in drm_fb_helper_hotplug_event() which
>> only stores a return value that is never used beyond the immediate
>> return statement.  This simplifies the code without behavior changes.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> Reviewed-by: Thomas Zimmermann <tzimmermann at suse.de>
> 
> But why is this patch hidden in this series? It has nothing to do with HDMI support.

I came across this while investigating some issues with the HPD-related changes
in the series (was part of the call path). 

Should I send the patch separately, or can it be picked up directly?

Thanks for reviewing,
Cristian


From sebastian.reichel at collabora.com  Fri Jun 12 11:00:49 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:49 +0200
Subject: [PATCH v3 03/10] drm/bridge: synopsys: dw-dp: Add follow-up bridge
 support
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-3-dc61e6352508@collabora.com>

Add support to use USB-C connectors with the DP altmode helper code on
devicetree based platforms. To get this working there must be a DRM
bridge chain from the DisplayPort controller to the USB-C connector.
E.g. on Rockchip RK3576:

root at rk3576 # cat /sys/kernel/debug/dri/0/encoder-0/bridges
bridge[0]: dw_dp_bridge_funcs
        refcount: 7
        type: [10] DP
        OF: /soc/dp at 27e40000:rockchip,rk3576-dp
        ops: [0x47] detect edid hpd
bridge[1]: drm_aux_bridge_funcs
        refcount: 4
        type: [0] Unknown
        OF: /soc/phy at 2b010000:rockchip,rk3576-usbdp-phy
        ops: [0x0]
bridge[2]: drm_aux_hpd_bridge_funcs
        refcount: 5
        type: [10] DP
        OF: /soc/i2c at 2ac50000/typec-portc at 22/connector:usb-c-connector
        ops: [0x4] hpd

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index ac7779e42bb2..98cff435dfb8 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -1970,7 +1970,7 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct dw_dp *dp;
-	struct drm_bridge *bridge;
+	struct drm_bridge *bridge, *next_bridge;
 	void __iomem *res;
 	int ret;
 
@@ -2064,6 +2064,20 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 		goto unregister_aux;
 	}
 
+	next_bridge = of_drm_get_bridge_by_endpoint(dev->of_node, 1, 0);
+	if (IS_ERR(next_bridge)) {
+		ret = PTR_ERR(next_bridge);
+		dev_err_probe(dev, ret, "failed to get follow-up bridge.\n");
+		goto unregister_aux;
+	}
+
+	ret = drm_bridge_attach(encoder, next_bridge, bridge,
+				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to attach next bridge\n");
+		goto unregister_aux;
+	}
+
 	dw_dp_init_hw(dp);
 
 	ret = phy_init(dp->phy);

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:46 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:46 +0200
Subject: [PATCH v3 00/10] Synopsys DisplayPort Controller improvements for
 Rockchip platforms
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>

This patch series updates the Synopsys Designware DisplayPort bridge
together with the only existing user: The Rockchip RK3576/RK3588:

 1. follow-up bridges (PHY, USB-C connector)
    this is needed to get USB-C DP AltMode working; I've followed the
    Qualcomm driver as reference

 2. runtime PM
    the initial driver has been upstreamed without RPM; add it to
    avoid wasting power when nothing is plugged

 3. audio
    the initial driver has been upstreamed without audio support;
    this adds all missing bits for audio with single stream transport

To properly make use of the bridge code the following USBDP PHY series
is also needed:

https://lore.kernel.org/linux-phy/20260428-rockchip-usbdp-cleanup-v4-0-7775671ece22 at collabora.com/

There are two parts, which possibly need some discussion:

 1. I added a dedicated bridge callback for out-of-band hotplug events,
    which is separate from the hotplug_notify. I have a feeling, that
    there might be a better solution, but haven't found it.

 2. The DT binding for audio support - explicitly marked as RFC - works
    perfectly fine, but is not ready for MST. I don't intend to
    implement that right now, but the binding should obviously take it
    into consideration to avoid breaking it in the future. I've put
    some points for discussion into the relevant patch.

Changes in PATCHv3:
- Link to v2: https://lore.kernel.org/r/20260501-synopsys-dw-dp-improvements-v2-0-d7e7f6bac77f at collabora.com
- Collect Reviewed-by on "Simplify driver data setting" patch (Andy Yan)
- Use of_drm_get_bridge_by_endpoint instead of devm_drm_of_get_bridge (Luca Ceresoli)
- Use FIELD_PREP_WM16 instead of FIELD_PREP_WM16_CONST (Chaoyi Chen)
- Rebase to latest drm-misc-next (Dropped Cristian's patches)

Changes in PATCHv2:
 * Link to v1: https://lore.kernel.org/r/20260326-synopsys-dw-dp-improvements-v1-0-501849162290 at collabora.com
 * rebased to latest drm-misc-next
 * prepended the Patches from Cristian's cleanup series, as they also
   needed a rebase and should be merged first
   https://lore.kernel.org/dri-devel/20260327-drm-rk-fixes-v3-0-fd2e6900c08c at collabora.com/
 * fix issue with the audio stream (un)prepare handling in last patch

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
Sebastian Reichel (10):
      drm/bridge: synopsys: dw-dp: Simplify driver data setting
      drm/bridge: synopsys: dw-dp: Support MEDIA_BUS_FMT_FIXED
      drm/bridge: synopsys: dw-dp: Add follow-up bridge support
      drm/bridge: Add out-of-band HPD notify handler
      drm/bridge: synopsys: dw-dp: Support software triggered OOB HPD
      drm/rockchip: dw_dp: Implement out-of-band HPD handling
      drm/bridge: synopsys: dw-dp: Add Runtime PM support
      drm/rockchip: dw_dp: Add runtime PM support
      [RFC] dt-bindings: display: rockchip: dw-dp: fix sound DAI cells
      drm/bridge: synopsys: dw-dp: Add audio support

 .../bindings/display/rockchip/rockchip,dw-dp.yaml  |   5 +-
 drivers/gpu/drm/bridge/synopsys/dw-dp.c            | 308 ++++++++++++++++++++-
 drivers/gpu/drm/display/drm_bridge_connector.c     |   6 +
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c          | 167 ++++++++++-
 include/drm/bridge/dw_dp.h                         |   6 +
 include/drm/drm_bridge.h                           |  14 +
 6 files changed, 493 insertions(+), 13 deletions(-)
---
base-commit: 2afdfc658f7a7e9ee2a67ec6663922da9c799c53
change-id: 20260325-synopsys-dw-dp-improvements-7da2e98df1dd

Best regards,
-- 
Sebastian Reichel <sebastian.reichel at collabora.com>



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:48 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:48 +0200
Subject: [PATCH v3 02/10] drm/bridge: synopsys: dw-dp: Support
 MEDIA_BUS_FMT_FIXED
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-2-dc61e6352508@collabora.com>

Add support for MEDIA_BUS_FMT_FIXED, which is e.g. requested for USB-C
DP chains as the last bridge in the chain (aux-hpd-bridge) does not
implement atomic_get_output_bus_fmts(), which results in the generic
drm_atomic_bridge_chain_select_bus_fmts() code using MEDIA_BUS_FMT_FIXED
instead.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index 36ee6e027af5..ac7779e42bb2 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -1528,6 +1528,7 @@ static int dw_dp_bridge_atomic_check(struct drm_bridge *bridge,
 				     struct drm_connector_state *conn_state)
 {
 	struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+	unsigned int out_bus_format = bridge_state->output_bus_cfg.format;
 	struct dw_dp *dp = bridge_to_dp(bridge);
 	struct dw_dp_bridge_state *state;
 	const struct dw_dp_output_format *fmt;
@@ -1538,7 +1539,10 @@ static int dw_dp_bridge_atomic_check(struct drm_bridge *bridge,
 	state = to_dw_dp_bridge_state(bridge_state);
 	mode = &state->mode;
 
-	fmt = dw_dp_get_output_format(bridge_state->output_bus_cfg.format);
+	if (out_bus_format == MEDIA_BUS_FMT_FIXED)
+		out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+	fmt = dw_dp_get_output_format(out_bus_format);
 	if (!fmt)
 		return -EINVAL;
 

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:47 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:47 +0200
Subject: [PATCH v3 01/10] drm/bridge: synopsys: dw-dp: Simplify driver data
 setting
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-1-dc61e6352508@collabora.com>

There is no need to get the platform device just for setting up
the driver data. Simplify the logic.

Reviewed-by: Andy Yan <andy.yan at rock-chips.com>
Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 0de822360c8d..35598ab9fe84 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -74,7 +74,6 @@ static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = {
 
 static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *data)
 {
-	struct platform_device *pdev = to_platform_device(dev);
 	const struct dw_dp_plat_data *plat_data;
 	struct drm_device *drm_dev = data;
 	struct rockchip_dw_dp *dp;
@@ -87,7 +86,7 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
 		return -ENOMEM;
 
 	dp->dev = dev;
-	platform_set_drvdata(pdev, dp);
+	dev_set_drvdata(dev, dp);
 
 	plat_data = of_device_get_match_data(dev);
 	if (!plat_data)

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:50 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:50 +0200
Subject: [PATCH v3 04/10] drm/bridge: Add out-of-band HPD notify handler
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-4-dc61e6352508@collabora.com>

For DP bridges, that can be used for DP AltMode, it might be necessary
to enforce HPD status. There is an existing ->oob_hotplug_event() on
the DRM connector, but it currently just calls into hpd_notify().

As DP bridge drivers usually also implement .detect and that also
generates calls into hpd_notify, this is a bad place to force the
HPD status as the follow-up detect call might force it off again
resulting in all follow-up calls to the detection routine also
failing.

Avoid this by having a dedicated function for OOB events.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/display/drm_bridge_connector.c |  6 ++++++
 include/drm/drm_bridge.h                       | 14 ++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
index 92f8a2d7aab4..802b5677194b 100644
--- a/drivers/gpu/drm/display/drm_bridge_connector.c
+++ b/drivers/gpu/drm/display/drm_bridge_connector.c
@@ -180,6 +180,12 @@ static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connect
 	struct drm_bridge_connector *bridge_connector =
 		to_drm_bridge_connector(connector);
 
+	/* Notify all bridges in the pipeline of hotplug events. */
+	drm_for_each_bridge_in_chain_scoped(bridge_connector->encoder, bridge) {
+		if (bridge->funcs->oob_notify)
+			bridge->funcs->oob_notify(bridge, connector, status);
+	}
+
 	drm_bridge_connector_handle_hpd(bridge_connector, status);
 }
 
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 00a95f927e34..11802e39d1f1 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -646,6 +646,20 @@ struct drm_bridge_funcs {
 	 */
 	void (*hpd_disable)(struct drm_bridge *bridge);
 
+	/**
+	 * @oob_notify:
+	 *
+	 * Notify the bridge of out of band hot plug detection.
+	 *
+	 * This callback is optional, it may be implemented by bridges that
+	 * need to be notified of display connection or disconnection for
+	 * internal reasons. One use case is to force the DP controllers HPD
+	 * signal for USB-C DP AltMode.
+	 */
+	void (*oob_notify)(struct drm_bridge *bridge,
+			   struct drm_connector *connector,
+			   enum drm_connector_status status);
+
 	/**
 	 * @hdmi_tmds_char_rate_valid:
 	 *

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:56 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:56 +0200
Subject: [PATCH v3 10/10] drm/bridge: synopsys: dw-dp: Add audio support
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-10-dc61e6352508@collabora.com>

Implement audio support for the Synopsys DesignWare DisplayPort
controller.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 221 +++++++++++++++++++++++++++++++-
 1 file changed, 220 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index 7f4f36c61484..f1946f2c945d 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -23,17 +23,21 @@
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge_connector.h>
 #include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_hdmi_audio_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_of.h>
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_simple_kms_helper.h>
 
+#include <sound/hdmi-codec.h>
+
 #define DW_DP_VERSION_NUMBER			0x0000
 #define DW_DP_VERSION_TYPE			0x0004
 #define DW_DP_ID				0x0008
 
 #define DW_DP_CONFIG_REG1			0x0100
+#define AUDIO_SELECT				GENMASK(2, 1)
 #define DW_DP_CONFIG_REG2			0x0104
 #define DW_DP_CONFIG_REG3			0x0108
 
@@ -110,6 +114,10 @@
 #define HBR_MODE_ENABLE				BIT(10)
 #define AUDIO_DATA_WIDTH			GENMASK(9, 5)
 #define AUDIO_DATA_IN_EN			GENMASK(4, 1)
+#define AUDIO_DATA_IN_EN_CHANNEL12		BIT(0)
+#define AUDIO_DATA_IN_EN_CHANNEL34		BIT(1)
+#define AUDIO_DATA_IN_EN_CHANNEL56		BIT(2)
+#define AUDIO_DATA_IN_EN_CHANNEL78		BIT(3)
 #define AUDIO_INF_SELECT			BIT(0)
 
 #define DW_DP_SDP_VERTICAL_CTRL			0x0500
@@ -253,6 +261,8 @@
 
 #define SDP_REG_BANK_SIZE			16
 
+#define DW_DP_SDP_VERSION			0x12
+
 struct dw_dp_link_caps {
 	bool enhanced_framing;
 	bool tps3_supported;
@@ -305,6 +315,19 @@ struct dw_dp_hotplug {
 	bool long_hpd;
 };
 
+enum dw_dp_audio_interface_support {
+	DW_DP_AUDIO_I2S_ONLY = 0,
+	DW_DP_AUDIO_SPDIF_ONLY = 1,
+	DW_DP_AUDIO_I2S_AND_SPDIF = 2,
+	DW_DP_AUDIO_NONE = 3,
+};
+
+enum dw_dp_audio_interface {
+	DW_DP_AUDIO_I2S = 0,
+	DW_DP_AUDIO_SPDIF = 1,
+	DW_DP_AUDIO_UNUSED,
+};
+
 struct dw_dp {
 	struct drm_bridge bridge;
 	struct device *dev;
@@ -320,6 +343,8 @@ struct dw_dp {
 	int irq;
 	struct work_struct hpd_work;
 	struct dw_dp_hotplug hotplug;
+	enum dw_dp_audio_interface audio_interface;
+	int audio_channels;
 	/* Serialize hpd status access */
 	struct mutex irq_lock;
 
@@ -1837,6 +1862,186 @@ static void dw_dp_bridge_oob_notify(struct drm_bridge *bridge,
 		dev_err_once(dp->dev, "Missing platform handler for OOB HPD handling\n");
 }
 
+static int dw_dp_audio_infoframe_send(struct dw_dp *dp)
+{
+	struct hdmi_audio_infoframe frame;
+	struct dw_dp_sdp sdp;
+	int ret;
+
+	ret = hdmi_audio_infoframe_init(&frame);
+	if (ret < 0)
+		return ret;
+
+	frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM;
+	frame.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
+	frame.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
+	frame.channels = dp->audio_channels;
+
+	ret = hdmi_audio_infoframe_pack_for_dp(&frame, &sdp.base, DW_DP_SDP_VERSION);
+	if (ret < 0)
+		return ret;
+
+	sdp.flags = DW_DP_SDP_VERTICAL_INTERVAL;
+
+	return dw_dp_send_sdp(dp, &sdp);
+}
+
+static int dw_dp_audio_startup(struct drm_bridge *bridge,
+			       struct drm_connector *connector)
+{
+	struct dw_dp *dp = bridge_to_dp(bridge);
+
+	dev_dbg(dp->dev, "audio startup\n");
+	pm_runtime_get_sync(dp->dev);
+
+	return 0;
+}
+
+static void dw_dp_audio_unprepare(struct drm_bridge *bridge,
+				  struct drm_connector *connector)
+{
+	struct dw_dp *dp = bridge_to_dp(bridge);
+
+	/* Disable all audio streams */
+	regmap_update_bits(dp->regmap, DW_DP_AUD_CONFIG1, AUDIO_DATA_IN_EN,
+			   FIELD_PREP(AUDIO_DATA_IN_EN, 0));
+
+	if (dp->audio_interface == DW_DP_AUDIO_SPDIF)
+		clk_disable_unprepare(dp->spdif_clk);
+	else if (dp->audio_interface == DW_DP_AUDIO_I2S)
+		clk_disable_unprepare(dp->i2s_clk);
+
+	dp->audio_interface = DW_DP_AUDIO_UNUSED;
+}
+
+static int dw_dp_audio_prepare(struct drm_bridge *bridge,
+			       struct drm_connector *connector,
+			       struct hdmi_codec_daifmt *daifmt,
+			       struct hdmi_codec_params *params)
+{
+	struct dw_dp *dp = bridge_to_dp(bridge);
+	u8 audio_data_in_en, supported_audio_interfaces;
+	u32 cfg1;
+	int ret;
+
+	/*
+	 * prepare might be called multiple times, so release the clocks
+	 * from previous calls to keep the calls in balance.
+	 */
+	if (dp->audio_interface != DW_DP_AUDIO_UNUSED)
+		dw_dp_audio_unprepare(bridge, connector);
+
+	dp->audio_channels = params->cea.channels;
+	switch (params->cea.channels) {
+	case 1:
+	case 2:
+		audio_data_in_en = AUDIO_DATA_IN_EN_CHANNEL12;
+		break;
+	case 8:
+		audio_data_in_en = AUDIO_DATA_IN_EN_CHANNEL12 |
+				   AUDIO_DATA_IN_EN_CHANNEL34 |
+				   AUDIO_DATA_IN_EN_CHANNEL56 |
+				   AUDIO_DATA_IN_EN_CHANNEL78;
+		break;
+	default:
+		dev_err(dp->dev, "invalid audio channels %d\n", dp->audio_channels);
+		return -EINVAL;
+	}
+
+	switch (daifmt->fmt) {
+	case HDMI_SPDIF:
+		dp->audio_interface = DW_DP_AUDIO_SPDIF;
+		break;
+	case HDMI_I2S:
+		/*
+		 * It is recommended to use SPDIF instead of I2S, since I2S mode requires
+		 * manually inserting PCUV control bits from userspace and this is done
+		 * automatically in hardware for SPDIF mode.
+		 */
+		dp->audio_interface = DW_DP_AUDIO_I2S;
+		break;
+	default:
+		dev_err(dp->dev, "invalid DAI format %d\n", daifmt->fmt);
+		return -EINVAL;
+	}
+
+	regmap_read(dp->regmap, DW_DP_CONFIG_REG1, &cfg1);
+	supported_audio_interfaces = FIELD_GET(AUDIO_SELECT, cfg1);
+
+	if (supported_audio_interfaces != DW_DP_AUDIO_I2S_AND_SPDIF &&
+	    supported_audio_interfaces != dp->audio_interface) {
+		dev_err(dp->dev, "unsupported DAI %d\n", daifmt->fmt);
+		return -EINVAL;
+	}
+
+	clk_prepare_enable(dp->spdif_clk);
+	clk_prepare_enable(dp->i2s_clk);
+
+	regmap_update_bits(dp->regmap, DW_DP_AUD_CONFIG1,
+			   AUDIO_DATA_IN_EN | NUM_CHANNELS | AUDIO_DATA_WIDTH |
+			   AUDIO_INF_SELECT | HBR_MODE_ENABLE,
+			   FIELD_PREP(AUDIO_DATA_IN_EN, audio_data_in_en) |
+			   FIELD_PREP(NUM_CHANNELS, dp->audio_channels - 1) |
+			   FIELD_PREP(AUDIO_DATA_WIDTH, params->sample_width) |
+			   FIELD_PREP(AUDIO_INF_SELECT, dp->audio_interface) |
+			   FIELD_PREP(HBR_MODE_ENABLE, 0));
+
+	/* Wait for inf switch */
+	usleep_range(20, 40);
+
+	if (dp->audio_interface == DW_DP_AUDIO_I2S)
+		clk_disable_unprepare(dp->spdif_clk);
+	else if (dp->audio_interface == DW_DP_AUDIO_SPDIF)
+		clk_disable_unprepare(dp->i2s_clk);
+
+	/*
+	 * Send audio stream during vertical and horizontal blanking periods.
+	 * Send out audio timestamp SDP once per video frame during the vertical
+	 * blanking period
+	 */
+	regmap_update_bits(dp->regmap, DW_DP_SDP_VERTICAL_CTRL,
+			   EN_AUDIO_STREAM_SDP | EN_AUDIO_TIMESTAMP_SDP,
+			   FIELD_PREP(EN_AUDIO_STREAM_SDP, 1) |
+			   FIELD_PREP(EN_AUDIO_TIMESTAMP_SDP, 1));
+	regmap_update_bits(dp->regmap, DW_DP_SDP_HORIZONTAL_CTRL,
+			   EN_AUDIO_STREAM_SDP,
+			   FIELD_PREP(EN_AUDIO_STREAM_SDP, 1));
+
+	ret = dw_dp_audio_infoframe_send(dp);
+	if (ret < 0)
+		dev_err(dp->dev, "failed to send audio infoframe\n");
+
+	dev_dbg(dp->dev, "audio prepare with %d channels using DAI=%d\n",
+		dp->audio_channels, dp->audio_interface);
+
+	return 0;
+}
+
+static void dw_dp_audio_shutdown(struct drm_bridge *bridge,
+				 struct drm_connector *connector)
+{
+	struct dw_dp *dp = bridge_to_dp(bridge);
+
+	dev_dbg(dp->dev, "audio shutdown\n");
+
+	dw_dp_audio_unprepare(bridge, connector);
+	pm_runtime_put_autosuspend(dp->dev);
+}
+
+static int dw_dp_audio_mute_stream(struct drm_bridge *bridge,
+				   struct drm_connector *connector,
+				   bool enable, int direction)
+{
+	struct dw_dp *dp = bridge_to_dp(bridge);
+
+	dev_dbg(dp->dev, "audio %smute\n", enable ? "" : "un");
+
+	regmap_update_bits(dp->regmap, DW_DP_AUD_CONFIG1, AUDIO_MUTE,
+			   FIELD_PREP(AUDIO_MUTE, enable));
+
+	return 0;
+}
+
 static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
 	.atomic_duplicate_state = dw_dp_bridge_atomic_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1850,6 +2055,11 @@ static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
 	.detect = dw_dp_bridge_detect,
 	.edid_read = dw_dp_bridge_edid_read,
 	.oob_notify = dw_dp_bridge_oob_notify,
+
+	.dp_audio_startup = dw_dp_audio_startup,
+	.dp_audio_prepare = dw_dp_audio_prepare,
+	.dp_audio_shutdown = dw_dp_audio_shutdown,
+	.dp_audio_mute_stream = dw_dp_audio_mute_stream,
 };
 
 static int dw_dp_link_retrain(struct dw_dp *dp)
@@ -2076,10 +2286,19 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 	}
 
 	bridge->of_node = dev->of_node;
-	bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
+	bridge->ops = DRM_BRIDGE_OP_DP_AUDIO |
+		      DRM_BRIDGE_OP_DETECT |
+		      DRM_BRIDGE_OP_EDID |
+		      DRM_BRIDGE_OP_HPD;
 	bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
 	bridge->ycbcr_420_allowed = true;
 
+	dp->audio_interface = DW_DP_AUDIO_UNUSED;
+	bridge->hdmi_audio_dev = dev;
+	bridge->hdmi_audio_max_i2s_playback_channels = 8;
+	bridge->hdmi_audio_dai_port = 1;
+	bridge->hdmi_audio_spdif_playback = true;
+
 	ret = devm_drm_bridge_add(dev, bridge);
 	if (ret)
 		return ERR_PTR(ret);

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:54 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:54 +0200
Subject: [PATCH v3 08/10] drm/rockchip: dw_dp: Add runtime PM support
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-8-dc61e6352508@collabora.com>

Add support for runtime PM to the Rockchip RK3576/3588 Synopsys
DesignWare DisplayPort driver.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 40 +++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 9c53f1d2c29a..1f53228e56d9 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -12,6 +12,7 @@
 #include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
 
@@ -58,6 +59,8 @@ static void dw_dp_rockchip_hpd_sw_sel(void *data, bool force_hpd_from_sw)
 
 	dp->hpd_sel = force_hpd_from_sw;
 
+	ACQUIRE(pm_runtime_active_auto, pm)(dp->dev);
+
 	regmap_write(dp->vo_grf, hpd_reg,
 		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_SEL, dp->hpd_sel));
 }
@@ -71,6 +74,8 @@ static void dw_dp_rockchip_hpd_sw_cfg(void *data, bool hpd)
 
 	dp->hpd_cfg = hpd;
 
+	ACQUIRE(pm_runtime_active_auto, pm)(dp->dev);
+
 	regmap_write(dp->vo_grf, hpd_reg,
 		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG, dp->hpd_cfg));
 }
@@ -213,6 +218,12 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
 	if (IS_ERR(dp->base))
 		return PTR_ERR(dp->base);
 
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_set_autosuspend_delay(dev, 500);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable runtime PM\n");
+
 	connector = drm_bridge_connector_init(drm_dev, encoder);
 	if (IS_ERR(connector)) {
 		dw_dp_unbind(dp->base);
@@ -246,6 +257,34 @@ static void dw_dp_remove(struct platform_device *pdev)
 	component_del(&pdev->dev, &dw_dp_rockchip_component_ops);
 }
 
+static int dw_dp_rockchip_runtime_suspend(struct device *dev)
+{
+	struct rockchip_dw_dp *dp = dev_get_drvdata(dev);
+
+	return dw_dp_runtime_suspend(dp->base);
+}
+
+static int dw_dp_rockchip_runtime_resume(struct device *dev)
+{
+	struct rockchip_dw_dp *dp = dev_get_drvdata(dev);
+	u32 hpd_reg = dp->pdata->hpd_reg[dp->id];
+	int ret;
+
+	ret = dw_dp_runtime_resume(dp->base);
+	if (ret)
+		return ret;
+
+	regmap_write(dp->vo_grf, hpd_reg,
+		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_SEL, dp->hpd_sel) |
+		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG, dp->hpd_cfg));
+
+	return 0;
+}
+
+static const struct dev_pm_ops dw_dp_pm_ops = {
+	RUNTIME_PM_OPS(dw_dp_rockchip_runtime_suspend, dw_dp_rockchip_runtime_resume, NULL)
+};
+
 static const struct rockchip_dw_dp_plat_data rk3588_dp_plat_data = {
 	.num_ctrls = 2,
 	.ctrl_ids = {0xfde50000, 0xfde60000},
@@ -280,5 +319,6 @@ struct platform_driver dw_dp_driver = {
 	.driver = {
 		.name = "dw-dp",
 		.of_match_table = dw_dp_of_match,
+		.pm = pm_ptr(&dw_dp_pm_ops),
 	},
 };

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:55 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:55 +0200
Subject: [PATCH RFC v3 09/10] dt-bindings: display: rockchip: dw-dp: fix
 sound DAI cells
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-9-dc61e6352508@collabora.com>

The RK3588 and RK3576 DesignWare DisplayPort controllers both have two
possible DAI interfaces: I2S and S/PDIF. Thus it is needed to have an
argument to select the right interface.

In case of RK3576 this is not enough though. The RK3576 has the same IP
as RK3588, but configured with Multi Stream Transport (MST) enabled for
up to 3 displays and thus has a total of 6 DAI interfaces (I2S and
S/PDIF for each possible stream. Meanwhile the RK3588 does not support
MST and thus has only 2 DAI interfaces.

The binding update right now only supports the simple single stream
transport (SST) setup. To avoid further DT ABI breakage (or complicated
bindings supporting different number of arguments), it's probably a good
idea to take MST into account now even though the upstream Linux driver
does not yet support it.

I see two options:

1. Adding yet another cell, so that we have the following:
   <&dp_ctrl [display_stream] [i2s_or_spdif]>; potentially append
   extra input ports for MST video data to existing ports node
   (e.g. port at 2). I would only handle the sound DAI part in my
   patch and basically use '0' for the display stream and just
   leave the option of using '1' or '2' once MST support is added.

2. The vendor kernel creates a sub-node for each supported display
   stream and puts the ports mapping as well as the DAI reference
   into that. This bundles all information for one display stream
   together, which creates a clean look but the subnode does not
   really describe any real thing in the hardware.

As upstream MST support seems to be quite limited, I wish for some
feedback about the preferred way to handle this.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 .../devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml         | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml
index 2b0d9e23e943..1303d0e2145a 100644
--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-dp.yaml
@@ -83,7 +83,8 @@ properties:
     maxItems: 1
 
   "#sound-dai-cells":
-    const: 0
+    const: 1
+    description: 0 for I2S, 1 for SPDIF
 
 required:
   - compatible
@@ -144,7 +145,7 @@ examples:
         resets = <&cru SRST_DP0>;
         phys = <&usbdp_phy0 PHY_TYPE_DP>;
         power-domains = <&power RK3588_PD_VO0>;
-        #sound-dai-cells = <0>;
+        #sound-dai-cells = <1>;
 
         ports {
           #address-cells = <1>;

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:52 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:52 +0200
Subject: [PATCH v3 06/10] drm/rockchip: dw_dp: Implement out-of-band HPD
 handling
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-6-dc61e6352508@collabora.com>

Implement out-of-band hotplug handling, which will be used to receive
external hotplug information from the USB-C state machine. This is
currently handled by the USBDP PHY, which brings quite some trouble
as the register being accessed requires the power-domain from the DP
controller and also requires custom TypeC HPD info parsing in the
USBDP PHY driver.

In contrast to the USBDP PHY this does not just enable the hotplug
signal when a DP AltMode capable adapter is plugged in, but instead
properly detects if a cable is plugged in for things like USB-C to
HDMI adapters.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/rockchip/dw_dp-rockchip.c | 126 ++++++++++++++++++++++++++++--
 1 file changed, 120 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
index 35598ab9fe84..9c53f1d2c29a 100644
--- a/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_dp-rockchip.c
@@ -7,9 +7,12 @@
  */
 
 #include <linux/component.h>
+#include <linux/hw_bitfield.h>
 #include <linux/media-bus-format.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/videodev2.h>
 
 #include <drm/bridge/dw_dp.h>
@@ -24,12 +27,54 @@
 
 #include "rockchip_drm_drv.h"
 
+#define ROCKCHIP_MAX_CTRLS 2
+
+#define ROCKCHIP_VO_GRF_DP_SINK_HPD_SEL BIT(10)
+#define ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG BIT(11)
+
+struct rockchip_dw_dp_plat_data {
+	u8 num_ctrls;
+	u32 ctrl_ids[ROCKCHIP_MAX_CTRLS];
+	u32 max_link_rate;
+	u8 pixel_mode;
+	u32 hpd_reg[ROCKCHIP_MAX_CTRLS];
+};
+
 struct rockchip_dw_dp {
 	struct dw_dp *base;
 	struct device *dev;
+	const struct rockchip_dw_dp_plat_data *pdata;
+	struct regmap *vo_grf;
 	struct rockchip_encoder encoder;
+	int id;
+	bool hpd_sel;
+	bool hpd_cfg;
 };
 
+static void dw_dp_rockchip_hpd_sw_sel(void *data, bool force_hpd_from_sw)
+{
+	struct rockchip_dw_dp *dp = data;
+	u32 hpd_reg = dp->pdata->hpd_reg[dp->id];
+
+	dp->hpd_sel = force_hpd_from_sw;
+
+	regmap_write(dp->vo_grf, hpd_reg,
+		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_SEL, dp->hpd_sel));
+}
+
+static void dw_dp_rockchip_hpd_sw_cfg(void *data, bool hpd)
+{
+	struct rockchip_dw_dp *dp = data;
+	u32 hpd_reg = dp->pdata->hpd_reg[dp->id];
+
+	dev_dbg(dp->dev, "Force HPD connected=%s\n", str_yes_no(hpd));
+
+	dp->hpd_cfg = hpd;
+
+	regmap_write(dp->vo_grf, hpd_reg,
+		     FIELD_PREP_WM16(ROCKCHIP_VO_GRF_DP_SINK_HPD_CFG, dp->hpd_cfg));
+}
+
 static int dw_dp_encoder_atomic_check(struct drm_encoder *encoder,
 				      struct drm_crtc_state *crtc_state,
 				      struct drm_connector_state *conn_state)
@@ -72,14 +117,49 @@ static const struct drm_encoder_helper_funcs dw_dp_encoder_helper_funcs = {
 	.atomic_check		= dw_dp_encoder_atomic_check,
 };
 
+static struct regmap *dp_dp_rockchip_get_vo_grf(struct rockchip_dw_dp *dp)
+{
+	struct device_node *np = dev_of_node(dp->dev);
+	struct of_phandle_args args;
+	struct regmap *regmap;
+	int ret;
+
+	ret = of_parse_phandle_with_args(np, "phys", "#phy-cells", 0, &args);
+	if (ret)
+		return ERR_PTR(-ENODEV);
+
+	/*
+	 * Limit this workaround to RK3576 and RK3588, new platforms should
+	 * add a VO GRF phandle in the DisplayPort DT node.
+	 */
+	if (!of_device_is_compatible(args.np, "rockchip,rk3576-usbdp-phy") &&
+	    !of_device_is_compatible(args.np, "rockchip,rk3588-usbdp-phy")) {
+		regmap = ERR_PTR(-ENODEV);
+		goto out_put_node;
+	}
+
+	regmap = syscon_regmap_lookup_by_phandle(args.np, "rockchip,vo-grf");
+
+out_put_node:
+	of_node_put(args.np);
+	return regmap;
+}
+
 static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *data)
 {
-	const struct dw_dp_plat_data *plat_data;
+	const struct rockchip_dw_dp_plat_data *plat_data_const;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct dw_dp_plat_data *plat_data;
 	struct drm_device *drm_dev = data;
 	struct rockchip_dw_dp *dp;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-	int ret;
+	struct resource *res;
+	int ret, id;
+
+	plat_data = drmm_kzalloc(drm_dev, sizeof(*plat_data), GFP_KERNEL);
+	if (!plat_data)
+		return -ENOMEM;
 
 	dp = drmm_kzalloc(drm_dev, sizeof(*dp), GFP_KERNEL);
 	if (!dp)
@@ -88,10 +168,38 @@ static int dw_dp_rockchip_bind(struct device *dev, struct device *master, void *
 	dp->dev = dev;
 	dev_set_drvdata(dev, dp);
 
-	plat_data = of_device_get_match_data(dev);
-	if (!plat_data)
+	plat_data_const = device_get_match_data(dev);
+	if (!plat_data_const)
 		return -ENODEV;
 
+	dp->pdata = plat_data_const;
+
+	res = platform_get_mem_or_io(pdev, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	/* find the DisplayPort ID from the io address */
+	dp->id = -ENODEV;
+	for (id = 0; id < plat_data_const->num_ctrls; id++) {
+		if (res->start == plat_data_const->ctrl_ids[id]) {
+			dp->id = id;
+			break;
+		}
+	}
+
+	if (dp->id < 0)
+		return dp->id;
+
+	dp->vo_grf = dp_dp_rockchip_get_vo_grf(dp);
+	if (IS_ERR(dp->vo_grf))
+		return PTR_ERR(dp->vo_grf);
+
+	plat_data->max_link_rate = plat_data_const->max_link_rate;
+	plat_data->pixel_mode = plat_data_const->pixel_mode;
+	plat_data->hpd_sw_sel = dw_dp_rockchip_hpd_sw_sel;
+	plat_data->hpd_sw_cfg = dw_dp_rockchip_hpd_sw_cfg;
+	plat_data->data = dp;
+
 	encoder = &dp->encoder.encoder;
 	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
 	rockchip_drm_encoder_set_crtc_endpoint_id(&dp->encoder, dev->of_node, 0, 0);
@@ -138,14 +246,20 @@ static void dw_dp_remove(struct platform_device *pdev)
 	component_del(&pdev->dev, &dw_dp_rockchip_component_ops);
 }
 
-static const struct dw_dp_plat_data rk3588_dp_plat_data = {
+static const struct rockchip_dw_dp_plat_data rk3588_dp_plat_data = {
+	.num_ctrls = 2,
+	.ctrl_ids = {0xfde50000, 0xfde60000},
 	.max_link_rate = 810000,
 	.pixel_mode = DW_DP_MP_QUAD_PIXEL,
+	.hpd_reg = {0x0000, 0x0008},
 };
 
-static const struct dw_dp_plat_data rk3576_dp_plat_data = {
+static const struct rockchip_dw_dp_plat_data rk3576_dp_plat_data = {
+	.num_ctrls = 1,
+	.ctrl_ids = {0x27e40000},
 	.max_link_rate = 810000,
 	.pixel_mode = DW_DP_MP_DUAL_PIXEL,
+	.hpd_reg = {0x0000},
 };
 
 static const struct of_device_id dw_dp_of_match[] = {

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:53 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:53 +0200
Subject: [PATCH v3 07/10] drm/bridge: synopsys: dw-dp: Add Runtime PM
 support
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-7-dc61e6352508@collabora.com>

Add runtime PM stubs to the Synopsys DesignWare DisplayPort bridge
driver. Support is not enabled automatically and must be hooked up
in the vendor specific glue code.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 27 +++++++++++++++++++++++++++
 include/drm/bridge/dw_dp.h              |  3 +++
 2 files changed, 30 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index 7fa38145e35c..7f4f36c61484 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -1465,6 +1465,8 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux,
 	if (WARN_ON(msg->size > 16))
 		return -E2BIG;
 
+	ACQUIRE(pm_runtime_active_auto, pm)(dp->dev);
+
 	switch (msg->request & ~DP_AUX_I2C_MOT) {
 	case DP_AUX_NATIVE_WRITE:
 	case DP_AUX_I2C_WRITE:
@@ -1655,6 +1657,8 @@ static void dw_dp_bridge_atomic_enable(struct drm_bridge *bridge,
 	struct drm_connector_state *conn_state;
 	int ret;
 
+	pm_runtime_get_sync(dp->dev);
+
 	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
 	if (!connector) {
 		dev_err(dp->dev, "failed to get connector\n");
@@ -1709,6 +1713,7 @@ static void dw_dp_bridge_atomic_disable(struct drm_bridge *bridge,
 	dw_dp_link_disable(dp);
 	bitmap_zero(dp->sdp_reg_bank, SDP_REG_BANK_SIZE);
 	dw_dp_reset(dp);
+	pm_runtime_put_autosuspend(dp->dev);
 }
 
 static bool dw_dp_hpd_detect_link(struct dw_dp *dp, struct drm_connector *connector)
@@ -1729,6 +1734,8 @@ static enum drm_connector_status dw_dp_bridge_detect(struct drm_bridge *bridge,
 {
 	struct dw_dp *dp = bridge_to_dp(bridge);
 
+	ACQUIRE(pm_runtime_active_auto, pm)(dp->dev);
+
 	if (!dw_dp_hpd_detect(dp))
 		return connector_status_disconnected;
 
@@ -2153,6 +2160,26 @@ void dw_dp_unbind(struct dw_dp *dp)
 }
 EXPORT_SYMBOL_GPL(dw_dp_unbind);
 
+int dw_dp_runtime_suspend(struct dw_dp *dp)
+{
+	clk_disable_unprepare(dp->aux_clk);
+	clk_disable_unprepare(dp->apb_clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_dp_runtime_suspend);
+
+int dw_dp_runtime_resume(struct dw_dp *dp)
+{
+	clk_prepare_enable(dp->apb_clk);
+	clk_prepare_enable(dp->aux_clk);
+
+	dw_dp_init_hw(dp);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_dp_runtime_resume);
+
 MODULE_AUTHOR("Andy Yan <andyshrk at 163.com>");
 MODULE_DESCRIPTION("DW DP Core Library");
 MODULE_LICENSE("GPL");
diff --git a/include/drm/bridge/dw_dp.h b/include/drm/bridge/dw_dp.h
index 2127afa26b2c..3037e0290861 100644
--- a/include/drm/bridge/dw_dp.h
+++ b/include/drm/bridge/dw_dp.h
@@ -28,4 +28,7 @@ struct dw_dp_plat_data {
 struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 			 const struct dw_dp_plat_data *plat_data);
 void dw_dp_unbind(struct dw_dp *dp);
+
+int dw_dp_runtime_suspend(struct dw_dp *dp);
+int dw_dp_runtime_resume(struct dw_dp *dp);
 #endif /* __DW_DP__ */

-- 
2.53.0



From sebastian.reichel at collabora.com  Fri Jun 12 11:00:51 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 20:00:51 +0200
Subject: [PATCH v3 05/10] drm/bridge: synopsys: dw-dp: Support software
 triggered OOB HPD
In-Reply-To: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
References: <20260612-synopsys-dw-dp-improvements-v3-0-dc61e6352508@collabora.com>
Message-ID: <20260612-synopsys-dw-dp-improvements-v3-5-dc61e6352508@collabora.com>

Add support for USB-C DP AltMode out-of-band hotplug handling. The
handling itself is implemented in the platform specific driver as the
registers to force HPD state are not part of the Designware DisplayPort
IP itself. Instead the platform integration might provide the necessary
functionality to mux the HPD signal.

Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
---
 drivers/gpu/drm/bridge/synopsys/dw-dp.c | 38 ++++++++++++++++++++++++++++++++-
 include/drm/bridge/dw_dp.h              |  3 +++
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-dp.c b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
index 98cff435dfb8..7fa38145e35c 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-dp.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-dp.c
@@ -1817,6 +1817,19 @@ static struct drm_bridge_state *dw_dp_bridge_atomic_duplicate_state(struct drm_b
 	return &state->base;
 }
 
+static void dw_dp_bridge_oob_notify(struct drm_bridge *bridge,
+				    struct drm_connector *connector,
+				    enum drm_connector_status status)
+{
+	bool hpd_high = status != connector_status_disconnected;
+	struct dw_dp *dp = bridge_to_dp(bridge);
+
+	if (dp->plat_data.hpd_sw_cfg)
+		dp->plat_data.hpd_sw_cfg(dp->plat_data.data, hpd_high);
+	else
+		dev_err_once(dp->dev, "Missing platform handler for OOB HPD handling\n");
+}
+
 static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
 	.atomic_duplicate_state = dw_dp_bridge_atomic_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
@@ -1829,6 +1842,7 @@ static const struct drm_bridge_funcs dw_dp_bridge_funcs = {
 	.atomic_disable = dw_dp_bridge_atomic_disable,
 	.detect = dw_dp_bridge_detect,
 	.edid_read = dw_dp_bridge_edid_read,
+	.oob_notify = dw_dp_bridge_oob_notify,
 };
 
 static int dw_dp_link_retrain(struct dw_dp *dp)
@@ -1965,6 +1979,19 @@ static void dw_dp_phy_exit(void *data)
 	phy_exit(dp->phy);
 }
 
+static bool dw_dp_is_routed_to_usb_c(struct drm_encoder *encoder)
+{
+	struct drm_bridge *last_bridge __free(drm_bridge_put) = NULL;
+	struct fwnode_handle *fwnode;
+
+	last_bridge = drm_bridge_chain_get_last_bridge(encoder);
+	if (!last_bridge)
+		return false;
+
+	fwnode = of_fwnode_handle(last_bridge->of_node);
+	return fwnode_device_is_compatible(fwnode, "usb-c-connector");
+}
+
 struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 			 const struct dw_dp_plat_data *plat_data)
 {
@@ -1980,7 +2007,9 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 
 	dp->dev = dev;
 	dp->pixel_mode = plat_data->pixel_mode;
-
+	dp->plat_data.hpd_sw_sel = plat_data->hpd_sw_sel;
+	dp->plat_data.hpd_sw_cfg = plat_data->hpd_sw_cfg;
+	dp->plat_data.data = plat_data->data;
 	dp->plat_data.max_link_rate = plat_data->max_link_rate;
 	bridge = &dp->bridge;
 	mutex_init(&dp->irq_lock);
@@ -2078,6 +2107,13 @@ struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,
 		goto unregister_aux;
 	}
 
+	if (dw_dp_is_routed_to_usb_c(encoder)) {
+		dev_dbg(dev, "USB-C mode\n");
+
+		if (dp->plat_data.hpd_sw_sel)
+			dp->plat_data.hpd_sw_sel(dp->plat_data.data, 1);
+	}
+
 	dw_dp_init_hw(dp);
 
 	ret = phy_init(dp->phy);
diff --git a/include/drm/bridge/dw_dp.h b/include/drm/bridge/dw_dp.h
index 22105c3e8e4d..2127afa26b2c 100644
--- a/include/drm/bridge/dw_dp.h
+++ b/include/drm/bridge/dw_dp.h
@@ -20,6 +20,9 @@ enum {
 struct dw_dp_plat_data {
 	u32 max_link_rate;
 	u8 pixel_mode;
+	void *data;
+	void (*hpd_sw_sel)(void *data, bool hpd);
+	void (*hpd_sw_cfg)(void *data, bool hpd);
 };
 
 struct dw_dp *dw_dp_bind(struct device *dev, struct drm_encoder *encoder,

-- 
2.53.0



From cristian.ciocaltea at collabora.com  Fri Jun 12 11:11:54 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 21:11:54 +0300
Subject: [PATCH v7 02/30] drm/connector: Add HDMI 2.0 scrambler
 infrastructure
In-Reply-To: <20260612-subtle-shapeless-rattlesnake-4b6af8@houat>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-2-445eb54ee1ed@collabora.com>
 <20260612-subtle-shapeless-rattlesnake-4b6af8@houat>
Message-ID: <7b19b243-ad6a-4d1f-b34e-684e8bfe500c@collabora.com>

Hi Maxime,

Thanks for taking the time to review this!

On 6/12/26 3:06 PM, Maxime Ripard wrote:
> On Tue, Jun 02, 2026 at 01:44:02AM +0300, Cristian Ciocaltea wrote:
>> Add the connector-level infrastructure to support HDMI 2.0 scrambling:
>>
>> - A scrambler_supported flag to indicate whether the source supports the
>>   scrambling capability, in which case the newly introduced
>>   .scrambler_{enable|disable}() callbacks in drm_connector_hdmi_funcs
>>   are mandatory
>> - A scrambler_needed flag to be managed by the hdmi state helpers based
>>   on the negotiated TMDS character rate and the source/sink scrambling
>>   capabilities
>> - A scrambler_enabled flag to track whether scrambling is currently
>>   active
>> - A delayed work item (scdc_work) with an associated callback (scdc_cb)
>>   to monitor sink-side scrambling status and retry the setup if the sink
>>   resets it
>>
>> These are intended to be used by SCDC scrambling helpers to coordinate
>> scrambling setup and teardown between the source driver and the DRM
>> core.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>> ---
>>  drivers/gpu/drm/drm_connector.c | 18 +++++++++
>>  include/drm/drm_connector.h     | 81 +++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 99 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
>> index a5d13b92b665..526dc2931b8a 100644
>> --- a/drivers/gpu/drm/drm_connector.c
>> +++ b/drivers/gpu/drm/drm_connector.c
>> @@ -220,6 +220,19 @@ void drm_connector_free_work_fn(struct work_struct *work)
>>  	}
>>  }
>>  
>> +static void drm_connector_hdmi_scdc_work(struct work_struct *work)
>> +{
>> +	struct drm_connector *connector;
>> +	struct drm_connector_hdmi *hdmi;
>> +
>> +	hdmi = container_of(to_delayed_work(work), struct drm_connector_hdmi,
>> +			    scdc_work);
>> +	connector = container_of(hdmi, struct drm_connector, hdmi);
>> +
>> +	if (hdmi->scdc_cb)
>> +		hdmi->scdc_cb(connector);
>> +}
>> +
>>  static int drm_connector_init_only(struct drm_device *dev,
>>  				   struct drm_connector *connector,
>>  				   const struct drm_connector_funcs *funcs,
>> @@ -285,6 +298,7 @@ static int drm_connector_init_only(struct drm_device *dev,
>>  	mutex_init(&connector->edid_override_mutex);
>>  	mutex_init(&connector->hdmi.infoframes.lock);
>>  	mutex_init(&connector->hdmi_audio.lock);
>> +	INIT_DELAYED_WORK(&connector->hdmi.scdc_work, drm_connector_hdmi_scdc_work);
>>  	connector->edid_blob_ptr = NULL;
>>  	connector->epoch_counter = 0;
>>  	connector->tile_blob_ptr = NULL;
>> @@ -606,6 +620,10 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>>  	    !hdmi_funcs->hdmi.write_infoframe)
>>  		return -EINVAL;
>>  
>> +	if (connector->hdmi.scrambler_supported &&
>> +	    (!hdmi_funcs->scrambler_enable || !hdmi_funcs->scrambler_disable))
>> +		return -EINVAL;
>> +
>>  	ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
>>  	if (ret)
>>  		return ret;
>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> index 529755c2e862..f1c5c15a6cce 100644
>> --- a/include/drm/drm_connector.h
>> +++ b/include/drm/drm_connector.h
>> @@ -28,6 +28,7 @@
>>  #include <linux/ctype.h>
>>  #include <linux/hdmi.h>
>>  #include <linux/notifier.h>
>> +#include <linux/workqueue.h>
>>  #include <drm/drm_mode_object.h>
>>  #include <drm/drm_util.h>
>>  #include <drm/drm_property.h>
>> @@ -1057,6 +1058,19 @@ struct drm_connector_hdmi_state {
>>  	 * @tmds_char_rate: TMDS Character Rate, in Hz.
>>  	 */
>>  	unsigned long long tmds_char_rate;
>> +
>> +	/**
>> +	 * @scrambler_needed: Whether HDMI 2.0 SCDC scrambling is required
>> +	 * for the negotiated mode/bpc/format.
>> +	 *
>> +	 * Computed by drm_atomic_helper_connector_hdmi_check() from
>> +	 * @tmds_char_rate and the source/sink scrambling capabilities.
>> +	 *
>> +	 * Per HDMI 2.0, scrambling is mandatory above 340 MHz TMDS
>> +	 * character rate. Optional scrambling at lower rates is
>> +	 * deliberately not requested by the helper.
>> +	 */
>> +	bool scrambler_needed;
>>  };
>>  
>>  /**
>> @@ -1358,6 +1372,36 @@ struct drm_connector_hdmi_funcs {
>>  	 */
>>  	const struct drm_edid *(*read_edid)(struct drm_connector *connector);
>>  
>> +	/**
>> +	 * @scrambler_enable:
>> +	 *
>> +	 * This callback is invoked through @drm_scdc_start_scrambling during
>> +	 * a commit to setup SCDC scrambling and high TMDS clock ratio on
>> +	 * source side.
>> +	 *
>> +	 * The @scrambler_enable callback is mandatory if HDMI 2.0 is to be
>> +	 * supported.
>> +	 *
>> +	 * Returns:
>> +	 * 0 on success, a negative error code otherwise
>> +	 */
>> +	int (*scrambler_enable)(struct drm_connector *connector);
>> +
>> +	/**
>> +	 * @scrambler_disable:
>> +	 *
>> +	 * This callback is invoked through @drm_scdc_stop_scrambling during
>> +	 * a commit to disable SCDC scrambling and high TMDS clock ratio on
>> +	 * source side.
>> +	 *
>> +	 * The @scrambler_disable callback is mandatory if HDMI 2.0 is to be
>> +	 * supported.
>> +	 *
>> +	 * Returns:
>> +	 * 0 on success, a negative error code otherwise
>> +	 */
>> +	int (*scrambler_disable)(struct drm_connector *connector);
>> +
>>  	/**
>>  	 * @avi:
>>  	 *
>> @@ -1960,6 +2004,43 @@ struct drm_connector_hdmi {
>>  	 */
>>  	unsigned long supported_formats;
>>  
>> +	/**
>> +	 * @scrambler_supported: Indicates whether the HDMI controller
>> +	 * (source) supports HDMI 2.0 SCDC scrambling.
>> +	 *
>> +	 * When true, @drm_connector_hdmi_funcs.scrambler_enable and
>> +	 * @drm_connector_hdmi_funcs.scrambler_disable are mandatory.
>> +	 * This is enforced by drmm_connector_hdmi_init().
>> +	 *
>> +	 * For HDMI bridge based drivers using drm_bridge_connector_init(),
>> +	 * this is propagated automatically from bridges that set the
>> +	 * DRM_BRIDGE_OP_HDMI_SCRAMBLER flag in their &drm_bridge->ops.
>> +	 * Other drivers must set this field on @connector->hdmi before calling
>> +	 * drmm_connector_hdmi_init().
>> +	 */
>> +	bool scrambler_supported;
>> +
>> +	/**
>> +	 * @scrambler_enabled: Tracks whether HDMI 2.0 scrambler is currently enabled.
>> +	 */
>> +	bool scrambler_enabled;
> 
> This is already in the state. Why do you need to copy it over here, and

This was supposed to be used exclusively by drm_scdc_{start,stop}_scrambling()
and drm_scdc_sync_status() helpers to control the work item and conditionally
trigger CRTC resets.  However, it's now also set by vc4_hdmi_connector_init() to
force disable the scrambler in the vc4_crtc_disable_at_boot() execution path.

For this purpose, I think we should add a "force" argument to
drm_scdc_stop_scrambling(), or maybe a dedicated helper?!

> if you do, you'll need a lock.

Currently it's managed via READ_ONCE()/WRITE_ONCE(). Do you think locking is
really necessary?

Regards,
Cristian


From cristian.ciocaltea at collabora.com  Fri Jun 12 12:23:20 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 22:23:20 +0300
Subject: [PATCH v7 05/30] drm/display: hdmi_state_helper: Add ctx-aware
 hotplug helper for SCDC sync
In-Reply-To: <20260611-refined-idealistic-sunfish-3df3a4@houat>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-5-445eb54ee1ed@collabora.com>
 <20260611-refined-idealistic-sunfish-3df3a4@houat>
Message-ID: <e81b477a-ff61-4fdf-9622-b980f8ac453c@collabora.com>

On 6/11/26 6:25 PM, Maxime Ripard wrote:
> On Tue, Jun 02, 2026 at 01:44:05AM +0300, Cristian Ciocaltea wrote:
>> Introduce drm_atomic_helper_connector_hdmi_hotplug_ctx(), a variant of
>> drm_atomic_helper_connector_hdmi_hotplug() that accepts a
>> drm_modeset_acquire_ctx.
>>
>> This enables SCDC status synchronization on hotplug events, which
>> requires lock acquisition context for performing the CRTC reset
>> triggered by drm_scdc_sync_status().

[...]

>> diff --git a/include/drm/display/drm_hdmi_state_helper.h b/include/drm/display/drm_hdmi_state_helper.h
>> index 13375bd0f4ae..75fedd4a3ba8 100644
>> --- a/include/drm/display/drm_hdmi_state_helper.h
>> +++ b/include/drm/display/drm_hdmi_state_helper.h
>> @@ -7,6 +7,7 @@ struct drm_atomic_commit;
>>  struct drm_connector;
>>  struct drm_connector_state;
>>  struct drm_display_mode;
>> +struct drm_modeset_acquire_ctx;
>>  struct hdmi_audio_infoframe;
>>  
>>  enum drm_connector_status;
>> @@ -24,6 +25,9 @@ int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *con
>>  						       struct drm_atomic_commit *state);
>>  void drm_atomic_helper_connector_hdmi_hotplug(struct drm_connector *connector,
>>  					      enum drm_connector_status status);
>> +int drm_atomic_helper_connector_hdmi_hotplug_ctx(struct drm_connector *connector,
>> +						 enum drm_connector_status status,
>> +						 struct drm_modeset_acquire_ctx *ctx);
> 
> There's not a lot of users, so I'd prefer if we were just changing the
> prototype of drm_atomic_helper_connector_hdmi_hotplug()

Ack - that was actually my first attempt, but I later thought it would be more
desirable to handle it incrementally.

Cristian


From cristian.ciocaltea at collabora.com  Fri Jun 12 13:42:06 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Fri, 12 Jun 2026 23:42:06 +0300
Subject: [PATCH v7 11/30] drm/display: bridge_connector: Wire up HDMI 2.0
 scrambler callbacks
In-Reply-To: <20260612-attractive-dashing-mule-309598@houat>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-11-445eb54ee1ed@collabora.com>
 <20260612-attractive-dashing-mule-309598@houat>
Message-ID: <b14af457-0799-43cc-80b5-7ffff5901f24@collabora.com>

On 6/12/26 11:52 AM, Maxime Ripard wrote:
> On Tue, Jun 02, 2026 at 01:44:11AM +0300, Cristian Ciocaltea wrote:
>> Connect the bridge connector's .scrambler_{enable|disable} callbacks to
>> the underlying bridge's .hdmi_scrambler_{enable|disable} funcs when
>> DRM_BRIDGE_OP_HDMI_SCRAMBLER is advertised.
>>
>> This completes the bridge connector plumbing so that the SCDC
>> scrambling helpers can control source-side scrambling through the
>> bridge chain.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
>> ---
>>  drivers/gpu/drm/display/drm_bridge_connector.c | 41 +++++++++++++++++++++++++-
>>  1 file changed, 40 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/display/drm_bridge_connector.c b/drivers/gpu/drm/display/drm_bridge_connector.c
>> index 9d21b1b57b0d..d048ab49eade 100644
>> --- a/drivers/gpu/drm/display/drm_bridge_connector.c
>> +++ b/drivers/gpu/drm/display/drm_bridge_connector.c
>> @@ -555,6 +555,32 @@ static int drm_bridge_connector_write_spd_infoframe(struct drm_connector *connec
>>  	return bridge->funcs->hdmi_write_spd_infoframe(bridge, buffer, len);
>>  }
>>  
>> +static int drm_bridge_connector_scrambler_enable(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_scrambler_enable(bridge);
>> +}
>> +
>> +static int drm_bridge_connector_scrambler_disable(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_scrambler_disable(bridge);
>> +}
>> +
>>  static const struct drm_edid *
>>  drm_bridge_connector_read_edid(struct drm_connector *connector)
>>  {
>> @@ -580,7 +606,7 @@ 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, hdr_drm and spd are set dynamically during init */
>> +	/* scrambler, audio, hdr_drm and spd are set dynamically during init */
>>  };
>>  
>>  static const struct drm_connector_infoframe_funcs drm_bridge_connector_hdmi_audio_infoframe = {
>> @@ -886,6 +912,11 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>>  			     !bridge->funcs->hdmi_clear_spd_infoframe))
>>  				return ERR_PTR(-EINVAL);
>>  
>> +			if (bridge->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER &&
>> +			    (!bridge->funcs->hdmi_scrambler_enable ||
>> +			     !bridge->funcs->hdmi_scrambler_disable))
>> +				return ERR_PTR(-EINVAL);
>> +
>>  			bridge_connector->bridge_hdmi = drm_bridge_get(bridge);
>>  
>>  			if (bridge->supported_formats)
>> @@ -990,6 +1021,14 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>>  			bridge_connector->hdmi_funcs.spd =
>>  				drm_bridge_connector_hdmi_spd_infoframe;
>>  
>> +		if (bridge_connector->bridge_hdmi->ops & DRM_BRIDGE_OP_HDMI_SCRAMBLER) {
>> +			bridge_connector->hdmi_funcs.scrambler_enable =
>> +				drm_bridge_connector_scrambler_enable;
>> +			bridge_connector->hdmi_funcs.scrambler_disable =
>> +				drm_bridge_connector_scrambler_disable;
>> +			connector->hdmi.scrambler_supported = true;
>> +		}
>> +
> 
> I think we're taking this backwards. The scrambler support isn't
> optional: either the controller supports HDMI < 2.0, and then it doesn't
> exist, or it supports >= 2.0 and then it's mandatory.
> 
> You're considering it optional here, when it's never actually optional
> (unlike YUV420 for example)
> 
> I still think we should list, somehow, the capabilities of the
> controller to the helpers, like max tmds rate supported, formats, etc.
> We've so far put everything as an argument to drmm_connector_hdmi_init
> but it becomes a bit overloaded, and I wonder if introducing a callback
> wouldn't solve this, kind of like what we have for planes and formats.


What about introducing something like:

struct drm_connector_hdmi_caps {
    ...
    unsigned int supported_formats;
    enum hdmi_version supported_hdmi_ver;
};

struct drm_connector_hdmi_funcs {
    ...
    int (*get_caps)(struct drm_connector *connector,
                    struct drm_connector_hdmi_caps *caps);
    ...
};

int drmm_connector_hdmi_init(struct drm_device *dev, ...)
{
    ...
    if (hdmi_funcs->get_caps) {
        struct drm_connector_hdmi_caps caps = { };

        ret = hdmi_funcs->get_caps(connector, &caps);
        if (ret)
            return ret;

        connector->hdmi.supported_formats  = caps.supported_formats;
        ...
        if (caps.supported_hdmi_ver > HDMI_2_0)
            connector->hdmi.frl_supported = true;
        else if (caps.supported_hdmi_ver == HDMI_2_0)
            connector->hdmi.scrambler_supported = true;
    }
    ...
}

Not sure if max_tmds_char_rate should be listed as a capability, as we already
have the .tmds_char_rate_valid() callback.

Cristian


From sebastian.reichel at collabora.com  Fri Jun 12 14:15:34 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Fri, 12 Jun 2026 23:15:34 +0200
Subject: [RFC PATCH v3 0/9] accel: rocket: Add RK3568 NPU support
In-Reply-To: <DJ5FUW50YM2N.6ZTY4WK27ZP5@cknow-tech.com>
References: <CA+GS1Y1s78PwN63X2YJoS8VEGp7CpTERo_K65yKs00U4VRAw4Q@mail.gmail.com>
 <e5058919-9485-4de5-8eea-331ebfc2987c@rock-chips.com>
 <CA+GS1Y3ysdWZ3qCq3ip_Pbw+v4LxHZd95aBo=jwB+orYaMBBNw@mail.gmail.com>
 <CA+GS1Y0kAM_XGLQuKPTphif2HcQg18ZXhd8RHHr2xPOEMCDvXA@mail.gmail.com>
 <bcedaff0-abf8-4585-a0ea-057062cd0411@rock-chips.com>
 <CA+GS1Y2-hRqpGgsknh+oOX+-uZ3DZtdekdP9viTP6a40zhhUhg@mail.gmail.com>
 <b05f7154-e85f-4207-80ae-f080282ba780@rock-chips.com>
 <DJ5A9XL183RZ.20J3ASQ3EWUZ6@cknow-tech.com>
 <CA+GS1Y1xAq-9eMyMmoVE6NG9KLG7XRxgPoSr5RkW=6fT5D820g@mail.gmail.com>
 <DJ5FUW50YM2N.6ZTY4WK27ZP5@cknow-tech.com>
Message-ID: <aixze8zFboY3huSf@venus>

Hi,

On Wed, Jun 10, 2026 at 04:28:17PM +0200, Diederik de Haas wrote:
> On Wed Jun 10, 2026 at 3:36 PM CEST, Midgy Balon wrote:
> [    2.110935] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management at fd8d8000/power-controller/power-domain at 8
> [    2.557459] sdhci-dwcmshc fe2e0000.mmc: Can't reduce the clock below 52MHz in HS200/HS400 mode
> [    2.647174] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier 2-0042 for /power-management at fd8d8000/power-controller/power-domain at 8
> [    2.945089] rockchip-pm-domain fd8d8000.power-management:power-controller: Failed to create device link (0x180) with supplier spi2.0 for /power-management at fd8d8000/power-controller/power-domain at 12
> 
> 8 = NPU; 12 = GPU
> 
> on both nanopc-t6-lts and nanopc-t6-plus (both RK3588).
> And on a 6.18 dmesg output I have for Rock 5B, I see the ~ same, but then
> it's 1-0042 instead of 2-0042. 
> 
> I don't know if it's bad or harmless, but it is consistent.

The fw_devlink framework tries to figure out a sensible probe order
by analyzing links between devices. The warning is because there is
a cyclic dependency. This happens because all power domains are
provided by one device (power-controller).

Now if you want to probe the I2C regulator 2-0042, you need the
I2C controller and to probe the I2C controller you need the I2C
power domain and for that you need the power-controller. But for
the power-controller you need 2-0042 (for the NPU power-domain).
At this point fw_devlink gives up and prints the warning.

Apart from the warning this results in the kernel missing dependency
information, so there might be some extra probe calls ending in
-EPROBE_DEFER (which wastes CPU power and delays the boot process).

So it's neither super bad, nor completely harmless. Fixing this
properly requires some heavy restructuring of the Rockchip
power-controller driver.

Greetings,

-- Sebastian
-------------- 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-rockchip/attachments/20260612/10c5522d/attachment.sig>

From robh at kernel.org  Fri Jun 12 14:49:02 2026
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Jun 2026 16:49:02 -0500
Subject: [PATCH] ASoC: Match DT helper types
Message-ID: <20260612214904.1882991-1-robh@kernel.org>

The affected ASoC drivers read properties whose bindings use boolean
flags, normal uint32 cells, or phandle-style arrays. Using helpers for
a different encoding makes those accesses disagree with the binding.

Use helpers that match the documented encoding and keep the existing
driver storage by copying through temporary values where needed.

Assisted-by: Codex:gpt-5-5
Signed-off-by: Rob Herring (Arm) <robh at kernel.org>
---
 sound/soc/codecs/ak4642.c         | 2 +-
 sound/soc/codecs/sta32x.c         | 6 +++---
 sound/soc/codecs/sta350.c         | 6 +++---
 sound/soc/codecs/twl4030.c        | 6 ++----
 sound/soc/rockchip/rockchip_pdm.c | 3 +--
 5 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index fe035d2fc913..b68555c8fbaf 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -613,7 +613,7 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev)
 	if (of_property_read_u32(np, "clock-frequency", &rate))
 		return NULL;
 
-	if (of_property_read_bool(np, "clocks"))
+	if (of_property_present(np, "clocks"))
 		parent_clk_name = of_clk_get_parent_name(np, 0);
 
 	of_property_read_string(np, "clock-output-names", &clk_name);
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index b9f9784f5164..857b729e6978 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -1038,7 +1038,7 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
 {
 	struct device_node *np = dev->of_node;
 	struct sta32x_platform_data *pdata;
-	u16 tmp;
+	u32 tmp;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -1063,8 +1063,8 @@ static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
 		of_property_read_bool(np, "st,needs_esd_watchdog");
 
 	tmp = 140;
-	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
-	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+	of_property_read_u32(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u32, tmp, 0, 300) / 20;
 
 	/* CONFE */
 	pdata->max_power_use_mpcc =
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 71af82b099c0..367d60577906 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1091,7 +1091,7 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
 	struct device_node *np = dev->of_node;
 	struct sta350_platform_data *pdata;
 	const char *ffx_power_mode;
-	u16 tmp;
+	u32 tmp;
 	u8 tmp8;
 
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -1131,8 +1131,8 @@ static int sta350_probe_dt(struct device *dev, struct sta350_priv *sta350)
 	}
 
 	tmp = 140;
-	of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
-	pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+	of_property_read_u32(np, "st,drop-compensation-ns", &tmp);
+	pdata->drop_compensation_ns = clamp_t(u32, tmp, 0, 300) / 20;
 
 	pdata->oc_warning_adjustment =
 		of_property_read_bool(np, "st,overcurrent-warning-adjustment");
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 9476cdfd4dde..91f5f907951a 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -202,13 +202,11 @@ static void
 twl4030_get_board_param_values(struct twl4030_board_params *board_params,
 			       struct device_node *node)
 {
-	int value;
-
 	of_property_read_u32(node, "ti,digimic_delay", &board_params->digimic_delay);
 	of_property_read_u32(node, "ti,ramp_delay_value", &board_params->ramp_delay_value);
 	of_property_read_u32(node, "ti,offset_cncl_path", &board_params->offset_cncl_path);
-	if (!of_property_read_u32(node, "ti,hs_extmute", &value))
-		board_params->hs_extmute = value;
+	if (of_property_read_bool(node, "ti,hs_extmute"))
+		board_params->hs_extmute = 1;
 
 	if (of_property_present(node, "ti,hs_extmute_gpio"))
 		board_params->hs_extmute = 1;
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index c69cdd6f2499..966105a544f5 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -546,8 +546,7 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n
 	unsigned int path[PDM_PATH_MAX];
 	int cnt = 0, ret = 0, i = 0, val = 0, msk = 0;
 
-	cnt = of_count_phandle_with_args(node, "rockchip,path-map",
-					 NULL);
+	cnt = of_property_count_u32_elems(node, "rockchip,path-map");
 	if (cnt != PDM_PATH_MAX)
 		return cnt;
 
-- 
2.53.0



From broonie at kernel.org  Thu Jun 11 12:49:46 2026
From: broonie at kernel.org (Mark Brown)
Date: Thu, 11 Jun 2026 20:49:46 +0100
Subject: [PATCH v2 0/5] ASoC: rockchip: Reorder clock enable sequence
In-Reply-To: <20260602101608.45137-1-phucduc.bui@gmail.com>
References: <20260602101608.45137-1-phucduc.bui@gmail.com>
Message-ID: <178120738665.484538.15946340325623351219.b4-ty@b4>

On Tue, 02 Jun 2026 17:16:03 +0700, phucduc.bui at gmail.com wrote:
> ASoC: rockchip: Reorder clock enable sequence
> 
> From: bui duc phuc <phucduc.bui at gmail.com>
> 
> Hi all,
> 
> This series reorders the runtime resume clock enable sequence in the
> Rockchip SPDIF and PDM drivers to enable the bus clock before the
> functional controller clock.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/5] ASoC: dt-bindings: rockchip-spdif: Correct SPDIF clock descriptions
      https://git.kernel.org/broonie/sound/c/d057cbc218ac
[2/5] ASoC: rockchip: spdif: Reorder clock enable sequence
      https://git.kernel.org/broonie/sound/c/74d3f01a90ca
[3/5] ASoC: rockchip: rockchip_pdm: Reorder clock enable sequence
      https://git.kernel.org/broonie/sound/c/3168721d6ec3
[4/5] ASoC: rockchip: spdif: Restore regcache cache-only mode on sync failure
      https://git.kernel.org/broonie/sound/c/3546e9aa691a
[5/5] ASoC: rockchip: rockchip_pdm: Handle runtime PM resume failures in set_fmt
      https://git.kernel.org/broonie/sound/c/ee7b5f7b3933

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 Jun 11 12:53:26 2026
From: broonie at kernel.org (Mark Brown)
Date: Thu, 11 Jun 2026 20:53:26 +0100
Subject: [PATCH v2 0/3] ASoC: rockchip: Use guard() for spin locks
In-Reply-To: <20260604033554.96996-1-phucduc.bui@gmail.com>
References: <20260604033554.96996-1-phucduc.bui@gmail.com>
Message-ID: <178120760640.484538.12942087225448845771.b4-ty@b4>

On Thu, 04 Jun 2026 10:35:50 +0700, phucduc.bui at gmail.com wrote:
> ASoC: rockchip: Use guard() for spin locks
> 
> From: bui duc phuc <phucduc.bui at gmail.com>
> 
> Hi all,
> 
> This series converts spinlock handling in the Rockchip sound drivers
> to use guard() helpers.
> The changes are code cleanup only and should have no functional impact.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/3] ASoC: rockchip: rockchip_i2s: Use guard() for spin locks
      https://git.kernel.org/broonie/sound/c/4bda5af16920
[2/3] ASoC: rockchip: i2s-tdm: Use guard() for spin locks
      https://git.kernel.org/broonie/sound/c/ec22437fc41a
[3/3] ASoC: rockchip: rockchip_sai: Use guard() for spin locks
      https://git.kernel.org/broonie/sound/c/f7fe9f707360

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 cristian.ciocaltea at collabora.com  Fri Jun 12 17:41:20 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sat, 13 Jun 2026 03:41:20 +0300
Subject: [PATCH v7 25/30] drm/vc4: hdmi: Convert to common HDMI 2.0 SCDC
 scrambling helpers
In-Reply-To: <20260612-primitive-chital-of-tempering-18bc7c@houat>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-25-445eb54ee1ed@collabora.com>
 <20260612-primitive-chital-of-tempering-18bc7c@houat>
Message-ID: <8937d785-4daa-4246-9553-24aed7d279b5@collabora.com>

Hi Maxime,

On 6/12/26 3:04 PM, Maxime Ripard wrote:
> Hi,
> 
> On Tue, Jun 02, 2026 at 01:44:25AM +0300, Cristian Ciocaltea wrote:
>> Replace the vc4-local scrambling implementation with the newly
>> introduced DRM common SCDC scrambling infrastructure:
>>
>> - Advertise source-side scrambling support by setting
>>   connector->hdmi.scrambling_supported based on the variant's
>>   max_pixel_clock before drmm_connector_hdmi_init().
>>
>> - Provide minimal .scrambler_{enable|disable} connector callbacks that
>>   only toggle the VC5 HDMI_SCRAMBLER_CTL register.  Sink-side SCDC
>>   programming and periodic status monitoring are now delegated to
>>   drm_scdc_{start|stop}_scrambling().
>>
>> - Replace vc4_hdmi_enable_scrambling() with a conditional call to
>>   drm_scdc_start_scrambling() in post_crtc_enable, gated on
>>   conn_state->hdmi.scrambler_needed (computed by the HDMI state helper).
>>
>> - Replace vc4_hdmi_disable_scrambling() with drm_scdc_stop_scrambling()
>>   in post_crtc_disable.
>>
>> - Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
>>   the .detect_ctx() path to
>>   drm_atomic_helper_connector_hdmi_hotplug_ctx() which internally calls
>>   drm_scdc_sync_status() to trigger a CRTC reset on reconnection.
>>
>> - Drop the local scrambling_work delayed workqueue and scdc_enabled
>>   flag, now tracked by the common drm_connector_hdmi layer.
>>
>> - Drop vc4_hdmi_supports_scrambling() and
>>   vc4_hdmi_mode_needs_scrambling() helpers, inlining the remaining 4KP60
>>   warning with an explicit drm_hdmi_compute_mode_clock() check.
>>
>> - Seed connector->hdmi.scrambler_enabled = true in connector_init() to
>>   ensure drm_scdc_stop_scrambling() runs at boot and disables any stale
>>   scrambling state left by the bootloader.
>>
>> No functional change is expected for the supported modes.
>>
>> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea at collabora.com>
> 
> I'd really like it to be broken down into several patches:
> 
>> ---
>>  drivers/gpu/drm/vc4/vc4_hdmi.c | 265 ++++++-----------------------------------
>>  drivers/gpu/drm/vc4/vc4_hdmi.h |   8 --
>>  2 files changed, 35 insertions(+), 238 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
>> index 046ac4f43ba8..02f6ca6ab52b 100644
>> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
>> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
>> @@ -114,31 +114,6 @@
>>  #define HSM_MIN_CLOCK_FREQ	120000000
>>  #define CEC_CLOCK_FREQ 40000
>>  
>> -static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
>> -{
>> -	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
>> -
>> -	lockdep_assert_held(&vc4_hdmi->mutex);
>> -
>> -	if (!display->is_hdmi)
>> -		return false;
>> -
>> -	if (!display->hdmi.scdc.supported ||
>> -	    !display->hdmi.scdc.scrambling.supported)
>> -		return false;
>> -
>> -	return true;
>> -}
>> -
>> -static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
>> -					   unsigned int bpc,
>> -					   enum drm_output_color_format fmt)
>> -{
>> -	unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
>> -
>> -	return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
>> -}
>> -
>>  static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
>>  {
>>  	struct drm_debugfs_entry *entry = m->private;
>> @@ -272,124 +247,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
>>  static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
>>  #endif
>>  
>> -static int vc4_hdmi_reset_link(struct drm_connector *connector,
>> -			       struct drm_modeset_acquire_ctx *ctx)
>> -{
>> -	struct drm_device *drm;
>> -	struct vc4_hdmi *vc4_hdmi;
>> -	struct drm_connector_state *conn_state;
>> -	struct drm_crtc_state *crtc_state;
>> -	struct drm_crtc *crtc;
>> -	bool scrambling_needed;
>> -	u8 config;
>> -	int ret;
>> -
>> -	if (!connector)
>> -		return 0;
>> -
>> -	drm = connector->dev;
>> -	ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
>> -	if (ret)
>> -		return ret;
>> -
>> -	conn_state = connector->state;
>> -	crtc = conn_state->crtc;
>> -	if (!crtc)
>> -		return 0;
>> -
>> -	ret = drm_modeset_lock(&crtc->mutex, ctx);
>> -	if (ret)
>> -		return ret;
>> -
>> -	crtc_state = crtc->state;
>> -	if (!crtc_state->active)
>> -		return 0;
>> -
>> -	vc4_hdmi = connector_to_vc4_hdmi(connector);
>> -	mutex_lock(&vc4_hdmi->mutex);
>> -
>> -	if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
>> -		mutex_unlock(&vc4_hdmi->mutex);
>> -		return 0;
>> -	}
>> -
>> -	scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
>> -							   vc4_hdmi->output_bpc,
>> -							   vc4_hdmi->output_format);
>> -	if (!scrambling_needed) {
>> -		mutex_unlock(&vc4_hdmi->mutex);
>> -		return 0;
>> -	}
>> -
>> -	if (conn_state->commit &&
>> -	    !try_wait_for_completion(&conn_state->commit->hw_done)) {
>> -		mutex_unlock(&vc4_hdmi->mutex);
>> -		return 0;
>> -	}
>> -
>> -	ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
>> -	if (ret < 0) {
>> -		drm_err(drm, "Failed to read TMDS config: %d\n", ret);
>> -		mutex_unlock(&vc4_hdmi->mutex);
>> -		return 0;
>> -	}
>> -
>> -	if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
>> -		mutex_unlock(&vc4_hdmi->mutex);
>> -		return 0;
>> -	}
>> -
>> -	mutex_unlock(&vc4_hdmi->mutex);
>> -
>> -	/*
>> -	 * HDMI 2.0 says that one should not send scrambled data
>> -	 * prior to configuring the sink scrambling, and that
>> -	 * TMDS clock/data transmission should be suspended when
>> -	 * changing the TMDS clock rate in the sink. So let's
>> -	 * just do a full modeset here, even though some sinks
>> -	 * would be perfectly happy if were to just reconfigure
>> -	 * the SCDC settings on the fly.
>> -	 */
>> -	return drm_atomic_helper_reset_crtc(crtc, ctx);
>> -}
> 
> This one doesn't look functionally equivalent to me to
> drm_scdc_reset_crtc: this part was, in part, making sure we would only
> reset the scrambler if it was enabled in the first place.
> drm_scdc_reset_crtc() doesn't and will always trigger a modeset on
> hotplug. That's unnecessary and a significant functional different.

drm_scdc_reset_crtc() alone was not meant to be an equivalent of
vc4_hdmi_reset_link(), as it only checks the sink side and it serves as an
internal helper used exclusively by drm_scdc_sync_status().  

As a matter of fact, the latter is the one responsible for verifying if the
scrambler was enabled on the controller side before attempting to invoke the
reset logic, hence we should get the same behavior.  But we don't invoke it
directly either, it's part of the drm_atomic_helper_connector_hdmi_hotplug_ctx()
call path.

> I'd argue that it's drm_scdc_reset_crtc() that needs to align to what
> vc4 was doing, not the opposite.

The only difference consists in dropping the crtc state check:

    ret = drm_modeset_lock(&crtc->mutex, ctx);
    if (ret)
            return ret;

    crtc_state = crtc->state;
    if (!crtc_state->active)
            return 0;

The rationale was that when CRTC is inactive, drm_atomic_helper_reset_crtc()
should result in a no-op commit anyway.

And the one for the in-flight commit:

    if (conn_state->commit &&
        !try_wait_for_completion(&conn_state->commit->hw_done)) {
            mutex_unlock(&vc4_hdmi->mutex);
            return 0;
    }

Both checks are also missing in drm_bridge_helper_reset_crtc(), taken as an
initial reference. Should we still keep any/both and sync the bridge helper
accordingly?

>> -static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
>> -				    struct drm_modeset_acquire_ctx *ctx,
>> -				    enum drm_connector_status status)
>> -{
>> -	struct drm_connector *connector = &vc4_hdmi->connector;
>> -	int ret;
>> -
>> -	/*
>> -	 * NOTE: This function should really be called with vc4_hdmi->mutex
>> -	 * held, but doing so results in reentrancy issues since
>> -	 * cec_s_phys_addr() might call .adap_enable, which leads to that
>> -	 * funtion being called with our mutex held.
>> -	 *
>> -	 * A similar situation occurs with vc4_hdmi_reset_link() that
>> -	 * will call into our KMS hooks if the scrambling was enabled.
>> -	 *
>> -	 * Concurrency isn't an issue at the moment since we don't share
>> -	 * any state with any of the other frameworks so we can ignore
>> -	 * the lock for now.
>> -	 */
>> -
>> -	drm_atomic_helper_connector_hdmi_hotplug(connector, status);
>> -
>> -	if (status != connector_status_connected)
>> -		return;
>> -
>> -	for (;;) {
>> -		ret = vc4_hdmi_reset_link(connector, ctx);
>> -		if (ret == -EDEADLK) {
>> -			drm_modeset_backoff(ctx);
>> -			continue;
>> -		}
>> -
>> -		break;
>> -	}
>> -}
>> -
>>  static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>>  					 struct drm_modeset_acquire_ctx *ctx,
>>  					 bool force)
>> @@ -401,8 +258,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>>  	/*
>>  	 * NOTE: This function should really take vc4_hdmi->mutex, but
>>  	 * doing so results in reentrancy issues since
>> -	 * vc4_hdmi_handle_hotplug() can call into other functions that
>> -	 * would take the mutex while it's held here.
>> +	 * drm_atomic_helper_connector_hdmi_hotplug_ctx() can call into other
>> +	 * functions that would take the mutex while it's held here.
>>  	 *
>>  	 * Concurrency isn't an issue at the moment since we don't share
>>  	 * any state with any of the other frameworks so we can ignore
>> @@ -425,10 +282,11 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
>>  			status = connector_status_connected;
>>  	}
>>  
>> -	vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
>> +	ret = drm_atomic_helper_connector_hdmi_hotplug_ctx(connector, status, ctx);
>> +
>>  	pm_runtime_put(&vc4_hdmi->pdev->dev);
>>  
>> -	return status;
>> +	return ret == -EDEADLK ? ret : status;
>>  }
>>  
>>  static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
>> @@ -441,9 +299,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
>>  	if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
>>  		struct drm_device *drm = connector->dev;
>>  		const struct drm_display_mode *mode;
>> +		unsigned long long clock;
>>  
>>  		list_for_each_entry(mode, &connector->probed_modes, head) {
>> -			if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
>> +			clock = drm_hdmi_compute_mode_clock(mode, 8,
>> +							    DRM_OUTPUT_COLOR_FORMAT_RGB444);
>> +			if (clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ) {
> 
> This should be a patch of its own, but I think we should turn
> vc4_hdmi_mode_needs_scrambling() into a helper, instead of checking the
> clock rate in every driver that might need it. From a logical standpoint
> it's equivalent, but not from a semantic one.

Ack.

> 
>>  				drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz.");
>>  				drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60.");
>>  			}
>> @@ -540,6 +401,9 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
>>  	if (vc4_hdmi->variant->supports_hdr)
>>  		max_bpc = 12;
>>  
>> +	connector->hdmi.scrambler_supported =
>> +		vc4_hdmi->variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
>> +
>>  	ret = drmm_connector_hdmi_init(dev, connector,
>>  				       "Broadcom", "Videocore",
>>  				       &vc4_hdmi_connector_funcs,
>> @@ -561,6 +425,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
>>  
>>  	drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
>>  
>> +	/*
>> +	 * Since we don't know the state of the controller and its
>> +	 * display (if any), let's assume it's always enabled.
>> +	 * drm_scdc_stop_scrambling() will thus run at boot, make
>> +	 * sure it's disabled, and avoid any inconsistency.
>> +	 */
>> +	connector->hdmi.scrambler_enabled = connector->hdmi.scrambler_supported;
>> +
>>  	/*
>>  	 * Some of the properties below require access to state, like bpc.
>>  	 * Allocate some default initial connector state with our reset helper.
>> @@ -786,93 +658,30 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
>>  					buffer, len);
>>  }
>>  
>> -#define SCRAMBLING_POLLING_DELAY_MS	1000
>> -
>> -static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
>> +static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
>>  {
>> -	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
>> -	struct drm_connector *connector = &vc4_hdmi->connector;
>> -	struct drm_device *drm = connector->dev;
>> -	const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
>> +	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
>>  	unsigned long flags;
>> -	int idx;
>> -
>> -	lockdep_assert_held(&vc4_hdmi->mutex);
>> -
>> -	if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
>> -		return;
>> -
>> -	if (!vc4_hdmi_mode_needs_scrambling(mode,
>> -					    vc4_hdmi->output_bpc,
>> -					    vc4_hdmi->output_format))
>> -		return;
>> -
>> -	if (!drm_dev_enter(drm, &idx))
>> -		return;
> 
> drm_dev_enter should be kept here

Sorry, somehow I missed to realize when I prepared the patches that I
accidentally dropped these during my initial driver rework.

> 
>> -	drm_scdc_set_high_tmds_clock_ratio(connector, true);
>> -	drm_scdc_set_scrambling(connector, true);
>>  
>>  	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
>>  	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
>>  		   VC5_HDMI_SCRAMBLER_CTL_ENABLE);
>>  	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>>  
>> -	drm_dev_exit(idx);
> 
> And exit here.
> 
>> -static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
>> +static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
>>  {
>> -	struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
>> -	struct drm_connector *connector = &vc4_hdmi->connector;
>> -	struct drm_device *drm = connector->dev;
>> +	struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
>>  	unsigned long flags;
>> -	int idx;
>> -
>> -	lockdep_assert_held(&vc4_hdmi->mutex);
>> -
>> -	if (!vc4_hdmi->scdc_enabled)
>> -		return;
>> -
>> -	vc4_hdmi->scdc_enabled = false;
>> -
>> -	if (delayed_work_pending(&vc4_hdmi->scrambling_work))
>> -		cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
>> -
>> -	if (!drm_dev_enter(drm, &idx))
>> -		return;
> 
> Ditto
> 
>>  	spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
>>  	HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
>>  		   ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
>>  	spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>>  
>> -	drm_scdc_set_scrambling(connector, false);
>> -	drm_scdc_set_high_tmds_clock_ratio(connector, false);
>> -
>> -	drm_dev_exit(idx);
>> -}
>> -
>> -static void vc4_hdmi_scrambling_wq(struct work_struct *work)
>> -{
>> -	struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
>> -						 struct vc4_hdmi,
>> -						 scrambling_work);
>> -	struct drm_connector *connector = &vc4_hdmi->connector;
>> -
>> -	if (drm_scdc_get_scrambling_status(connector))
>> -		return;
>> -
>> -	drm_scdc_set_high_tmds_clock_ratio(connector, true);
>> -	drm_scdc_set_scrambling(connector, true);
>> -
>> -	queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
>> -			   msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
>> +	return 0;
>>  }
>>  
>>  static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
>> @@ -917,7 +726,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
>>  		spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
>>  	}
>>  
>> -	vc4_hdmi_disable_scrambling(encoder);
>> +	drm_scdc_stop_scrambling(&vc4_hdmi->connector);
> 
> I don't think the names here are right. It's not *only* related to scdc
> but also to the HDMI controller. I'm fine with using a scdc prefix but
> only for the things related to scdc. This is related (in part) to the
> HDMI controller, so it should use a drm_connector_hdmi prefix.

Ack. I guess we should also move these helpers out of drm_scdc_helper.c, but
unsure where.  FWIW I'm currently working on adding HDMI 2.1 FRL support, and
implemented the link training in a dedicated drm_hdmi_frl_helper.c.  

Should we create drm_hdmi_scrambler_helper.c?  Or maybe have a common one to
hold both - any suggestion for the naming?

> 
>>  	drm_dev_exit(idx);
>>  
>> @@ -1625,6 +1434,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
>>  	struct drm_display_info *display = &vc4_hdmi->connector.display_info;
>>  	bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
>>  	bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
>> +	struct drm_connector_state *conn_state;
>>  	unsigned long flags;
>>  	int ret;
>>  	int idx;
>> @@ -1693,7 +1503,10 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
>>  	}
>>  
>>  	vc4_hdmi_recenter_fifo(vc4_hdmi);
>> -	vc4_hdmi_enable_scrambling(encoder);
>> +
>> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
>> +	if (conn_state && conn_state->hdmi.scrambler_needed)
>> +		drm_scdc_start_scrambling(connector);
> 
> And the nice thing with a drm_connector_hdmi_* prefix is that you don't
> have to shoehorn it into SCDC support anymore, so you can take a state
> as an argument, and do the check in the helper instead of doing it in
> every driver and hoping they get it right.

I was about to consider a similar approach before deciding to let drivers manage
the logic, i.e. to prevent loosing flexibility later when dealing with HDMI 2.1.
That was mostly in the context of supporting drivers to define if/when a display
mode that fits in TMDS should be sent over FRL. 

Thinking again, that's not really a valid concern right now, e.g. will use TMDS
by default for all supported modes, and switch to FRL only when absolutely
required.  Later we might consider extending the infrastructure to support
dynamic control if required.

Thanks,
Cristian


From cristian.ciocaltea at collabora.com  Fri Jun 12 18:30:02 2026
From: cristian.ciocaltea at collabora.com (Cristian Ciocaltea)
Date: Sat, 13 Jun 2026 04:30:02 +0300
Subject: [PATCH v7 04/30] drm/display: scdc_helper: Add HDMI 2.0
 scrambling management helpers
In-Reply-To: <20260612-cordial-steadfast-cow-fcaf01@houat>
References: <20260602-dw-hdmi-qp-scramb-v7-0-445eb54ee1ed@collabora.com>
 <20260602-dw-hdmi-qp-scramb-v7-4-445eb54ee1ed@collabora.com>
 <20260612-cordial-steadfast-cow-fcaf01@houat>
Message-ID: <2f5ce8eb-ef47-4238-ad68-ce62981a1845@collabora.com>

On 6/12/26 4:43 PM, Maxime Ripard wrote:
> On Tue, Jun 02, 2026 at 01:44:04AM +0300, Cristian Ciocaltea wrote:
>> +/**
>> + * drm_scdc_start_scrambling - activate scrambling and monitor SCDC status
>> + * @connector: connector
>> + *
>> + * Enables scrambling and high TMDS clock ratio on both source and sink sides.
>> + * Additionally, use a delayed work item to monitor the scrambling status on
>> + * the sink side and retry the operation, as some displays refuse to set the
>> + * scrambling bit right away.
>> + *
>> + * Returns:
>> + * Zero if scrambling is set successfully, an error code otherwise.
>> + */
>> +int drm_scdc_start_scrambling(struct drm_connector *connector)
>> +{
>> +	struct drm_display_info *info = &connector->display_info;
>> +	struct drm_connector_hdmi *hdmi = &connector->hdmi;
>> +	int ret;
>> +	u8 ver;
>> +
>> +	if (!hdmi->scrambler_supported) {
>> +		drm_scdc_dbg(connector, "Scrambler not supported, bailing.\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (!info->is_hdmi ||
>> +	    !info->hdmi.scdc.supported ||
>> +	    !info->hdmi.scdc.scrambling.supported) {
>> +		drm_scdc_dbg(connector, "Sink doesn't support scrambling.\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	drm_scdc_dbg(connector, "Enabling scrambling\n");
>> +
>> +	ret = drm_scdc_readb(connector->ddc, SCDC_SINK_VERSION, &ver);
>> +	if (ret) {
>> +		drm_scdc_dbg(connector, "Failed to read SCDC_SINK_VERSION: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = drm_scdc_writeb(connector->ddc, SCDC_SOURCE_VERSION,
>> +			      min_t(u8, ver, SCDC_MAX_SOURCE_VERSION));
>> +	if (ret) {
>> +		drm_scdc_dbg(connector, "Failed to write SCDC_SOURCE_VERSION: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	hdmi->scdc_cb = drm_scdc_monitor_scrambler;
>> +	WRITE_ONCE(hdmi->scrambler_enabled, true);
>> +
>> +	ret = drm_scdc_try_scrambling_setup(connector);
>> +	if (!ret)
>> +		ret = hdmi->funcs->scrambler_enable(connector);
>> +
>> +	if (ret) {
>> +		WRITE_ONCE(hdmi->scrambler_enabled, false);
>> +		cancel_delayed_work_sync(&hdmi->scdc_work);
>> +		hdmi->scdc_cb = NULL;
>> +
>> +		drm_scdc_set_scrambling(connector, false);
>> +		drm_scdc_set_high_tmds_clock_ratio(connector, false);
>> +	}
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL(drm_scdc_start_scrambling);
> 
> This is also pretty significantly different than what vc4 implemented. I
> don't necessarily mind, but claiming that it's functionally equivalent
> isn't true. I think it would be a much better strategy to turn the vc4
> code into helpers as is because it's been merged 4 years ago and we know
> it's solid.

As explained in patch 25, I think there's been a slight misunderstanding of how
the CRTC reset logic was actually implemented.

> Then, if you want to add additional checks and constraints (like the
> SCDC_SINK_VERSION) that's fine, but it should come on top, and with its
> own explanation.

I'll recheck if there's anything that I might have missed from the original
implementation, while moving the additional changes to separate patch(es).

Thanks,
Cristian


From midgy971 at gmail.com  Sat Jun 13 00:01:07 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:07 +0200
Subject: [RFC PATCH v4 0/9] accel: rocket: Add RK3568 NPU support
Message-ID: <20260613070116.438906-1-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

RFC, not for merge. End-to-end inference does not produce correct output
yet (see Status), so per the v2 discussion this is a request for design
feedback. It probes, attaches, and submits cleanly on a stock v7.1-rc6
tree; what remains is one hardware-internal issue.

The RK3568 has a single NVDLA-derived NPU core, the same IP family as the
RK3588 NPU the driver already supports; the register layout matches. The
RK3568 differences are a 32-bit NPU AXI/IOMMU (vs 40-bit) and explicit
PVTPLL/PMU bring-up to power and de-idle the NPU before it is reachable.

Patches:
  1-2  rocket: per-SoC data struct, then derive DMA width and core count
       from match data (refactors, no functional change); patch 2 also
       bounds-checks the per-SoC cores array.
  3    rocket: RK3568 SoC data; start the PVTPLL compute clock via SCMI.
       Powering on and de-idling the NPU NoC are left to the power domain.
  4    rocket: reset the NPU before detaching the IOMMU on a job timeout
       (the detach otherwise stalls a wedged AXI master and WARNs).
  5    rocket: keep the IOMMU domain attached across jobs instead of
       re-attaching per job (the per-job rk_iommu handshake on the idle
       NPU MMU is slow and noisy); also drop the domain on reset and stop
       the scheduler before IOMMU teardown.
  6    dt-bindings: add the RK3568 NPU compatible; require rockchip,pmu
       for RK3568.
  7-8  arm64 dts: add the NPU and its IOMMU, and enable them on ROCK 3B.
  9    pmdomain: give the RK3568 NPU power domain a regulator so genpd
       owns vdd_npu via domain-supply (Suggested-by Chaoyi Chen).

Dependencies. This series no longer touches the IOMMU driver; two
in-flight Rockchip IOMMU changes are relevant but not part of it:
  - Simon Xue's "iommu/rockchip: Drop global rk_ops in favor of
    per-device ops" [1]. On boards with more than 4 GiB of RAM the NPU
    MMU's DTE must stay below 4 GiB (its DTE address is 32-bit), so the
    NPU IOMMU is described with the "rockchip,iommu" compatible, whose ops
    allocate the page tables with GFP_DMA32; the SoC's other IOMMUs use
    the "rockchip,rk3568-iommu" (40-bit) ops. The driver keeps a single
    global ops pointer, so two ops on one SoC trip its coexistence check;
    this series therefore sits on top of Simon's per-device-ops change,
    which Rockchip (Chaoyi Chen) confirmed is the intended way to give the
    NPU MMU its 32-bit DTE.
  - "iommu/rockchip: disable fetch dte time limit" [2] (Simon Xue / Sven
    Pueschel, in the iommu tree), which sets AUTO_GATING bit 31. v3 carried
    a local AUTO_GATING patch; that unconditional fix has since been merged,
    so this series drops its IOMMU patch. The bit is a no-op on this
    hardware in any case (the page walk completes on its reset value).

Power bring-up. The NPU is brought up through the power-domain layer (no
driver hack): the NPU power-domain keeps its clocks but drops the pm_qos
phandle (qos_npu sits behind the gated NPU NoC, so genpd's power-off QoS
save faults reading it), and vdd_npu is wired as the domain's
domain-supply with the domain marked need_regulator (patch 9), so genpd
brings the rail up before it de-idles the NoC at power-on. The PMU de-idle
then ACKs without PVTPLL running; PVTPLL is only needed for compute.

Status. On v7.1-rc6 the driver probes, creates /dev/accel/accel0,
attaches an IOMMU domain, and submits jobs; the program controller
fetches and broadcasts the command list. Inference output is still
wrong. The kernel side (this series) appears complete; what remains is
mesa/Teflon userspace, which still emits RK3588-tuned config (to be
filed on mesa-dev), and the hardware: with corrected config the NPU
reads the full input and weight tensors (per its DMA counters) but the
MAC/output stage never completes and the job times out, leaving the
output at the buffer's zero-point. It is not in the command list (a
byte-exact replay of the vendor's command list behaves the same).
Pointers from anyone with RK3568 NPU experience welcome.

Known residual. On the first IOMMU attach the NPU MMU is idle with paging
already enabled; the rk_iommu stall/reset handshake does not complete in
that state and logs one burst of timeouts before the (kept) domain
settles. It is harmless here because the job times out regardless, but it
points at an idle-MMU reconfiguration corner the rk_iommu code does not
handle on this block.

[1] https://lore.kernel.org/linux-rockchip/20260310105303.128859-1-xxm at rock-chips.com/
[2] https://lore.kernel.org/all/20260428-spu-iommudtefix-v2-1-f592f579e508 at pengutronix.de/

Changes since v3:
  - Dropped the local AUTO_GATING patch: the correct fix (set AUTO_GATING
    bit 31, "disable fetch dte time limit") has since been merged upstream
    [2], so the series no longer touches the IOMMU driver.
  - vdd_npu: new pmdomain patch (9) gives the RK3568 NPU domain a regulator
    (need_regulator) and the board wires domain-supply, dropping the
    regulator-always-on workaround (Suggested-by Chaoyi Chen). It relies on
    the in-tree pmdomain default-off-if-need_regulator handling. The
    "Failed to create device link ... <pmic>" line at pmdomain probe is a
    pre-existing fw_devlink cyclic-dependency warning (the single
    power-controller provides every domain, including the one the I2C PMIC
    needs), seen the same way on RK3588; it is harmless here beyond a few
    wasted EPROBE_DEFER retries, and a proper fix belongs in the
    power-controller driver, not this series.
  - rk356x dts: also assign the CRU CLK_NPU so the NPU AXI bus clock comes
    up at 200 MHz instead of the 12 MHz boot default; order the NPU/IOMMU
    nodes by unit address.
  - rocket RK3568: fetch the SCMI/PVTPLL clock by name (the v3 bulk index
    resolved to the wrong clock); drop the redundant driver PMU de-idle
    writes (handled by the power domain).
  - rocket: clear the attached IOMMU domain on reset; unwind through
    rocket_core_fini() on noc_init failure; stop the scheduler before the
    IOMMU teardown.
  - rocket: bounds-check the cores array against the per-SoC core count.
  - Binding: require rockchip,pmu on RK3568.
  - Dependency framing: confirmed by Rockchip as v2 + 32-bit DTE via
    Simon's per-device-ops series (was framed as v1 in v3).

Midgy BALON (9):
  accel: rocket: Introduce per-SoC rocket_soc_data
  accel: rocket: Derive DMA width and core count from match data
  accel: rocket: Add RK3568 SoC support
  accel: rocket: Reset the NPU before detaching the IOMMU on timeout
  accel: rocket: Keep the IOMMU domain attached across jobs
  dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
  arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
  arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU
  pmdomain: rockchip: Add a regulator to the RK3568 NPU power domain

 .../npu/rockchip,rk3588-rknn-core.yaml        | 27 +++++++++-
 .../boot/dts/rockchip/rk3568-rock-3b.dts      | 18 ++++++-
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 ++++++++++++++
 drivers/accel/rocket/rocket_core.c            | 30 ++++++++++-
 drivers/accel/rocket/rocket_core.h            | 19 +++++++
 drivers/accel/rocket/rocket_device.c          | 15 ++----
 drivers/accel/rocket/rocket_device.h          |  3 +-
 drivers/accel/rocket/rocket_drv.c             | 50 ++++++++++++++++++-
 drivers/accel/rocket/rocket_job.c             | 45 ++++++++++++++---
 drivers/pmdomain/rockchip/pm-domains.c        | 36 +++++++++----
 10 files changed, 245 insertions(+), 36 deletions(-)


base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:08 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:08 +0200
Subject: [RFC PATCH v4 1/9] accel: rocket: Introduce per-SoC rocket_soc_data
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-2-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

Add a per-SoC data structure carried in the OF match table, currently
holding only the NPU AXI address width, and use it for the per-core DMA
mask instead of a hardcoded 40-bit value.  No functional change: the
RK3588 AXI master is 40-bit.  This prepares for SoCs with a narrower
address width.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c |  7 ++++++-
 drivers/accel/rocket/rocket_core.h | 11 +++++++++++
 drivers/accel/rocket/rocket_drv.c  |  6 +++++-
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index b3b2fa9ba645a..09c445af7de73 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -7,6 +7,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/iommu.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
@@ -21,6 +22,10 @@ int rocket_core_init(struct rocket_core *core)
 	u32 version;
 	int err = 0;
 
+	core->soc_data = of_device_get_match_data(dev);
+	if (!core->soc_data)
+		return dev_err_probe(dev, -EINVAL, "missing SoC match data\n");
+
 	core->resets[0].id = "srst_a";
 	core->resets[1].id = "srst_h";
 	err = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(core->resets),
@@ -52,7 +57,7 @@ int rocket_core_init(struct rocket_core *core)
 
 	dma_set_max_seg_size(dev, UINT_MAX);
 
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(core->soc_data->dma_bits));
 	if (err)
 		return err;
 
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index f6d7382854ca9..8ee105a0be40e 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -12,6 +12,16 @@
 
 #include "rocket_registers.h"
 
+struct rocket_core;
+
+/**
+ * struct rocket_soc_data - per-SoC configuration data
+ * @dma_bits: Physical address width reachable by the NPU's AXI master.
+ */
+struct rocket_soc_data {
+	unsigned int dma_bits;
+};
+
 #define rocket_pc_readl(core, reg) \
 	readl((core)->pc_iomem + (REG_PC_##reg))
 #define rocket_pc_writel(core, reg, value) \
@@ -31,6 +41,7 @@ struct rocket_core {
 	struct device *dev;
 	struct rocket_device *rdev;
 	unsigned int index;
+	const struct rocket_soc_data *soc_data;
 
 	int irq;
 	void __iomem *pc_iomem;
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index 8bbbce594883e..384c38e13acce 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -213,8 +213,12 @@ static void rocket_remove(struct platform_device *pdev)
 	}
 }
 
+static const struct rocket_soc_data rk3588_soc_data = {
+	.dma_bits = 40,
+};
+
 static const struct of_device_id dt_match[] = {
-	{ .compatible = "rockchip,rk3588-rknn-core" },
+	{ .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, dt_match);
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:09 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:09 +0200
Subject: [RFC PATCH v4 2/9] accel: rocket: Derive DMA width and core count from match data
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-3-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

The probe already has the per-SoC match data, which now records the core
count and DMA width.  Use it for the cores array allocation and the
device DMA mask instead of re-scanning the device tree for available core
nodes.

While at it, reject a device tree that declares more NPU core nodes than
the SoC has, so the fixed-size cores array can never be overrun.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.h   |  2 ++
 drivers/accel/rocket/rocket_device.c | 15 +++++----------
 drivers/accel/rocket/rocket_device.h |  3 ++-
 drivers/accel/rocket/rocket_drv.c    | 13 ++++++++++++-
 4 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index 8ee105a0be40e..d6421251670dc 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -16,9 +16,11 @@ struct rocket_core;
 
 /**
  * struct rocket_soc_data - per-SoC configuration data
+ * @num_cores: Number of NPU cores in this SoC.
  * @dma_bits: Physical address width reachable by the NPU's AXI master.
  */
 struct rocket_soc_data {
+	unsigned int num_cores;
 	unsigned int dma_bits;
 };
 
diff --git a/drivers/accel/rocket/rocket_device.c b/drivers/accel/rocket/rocket_device.c
index 46e6ee1e72c5f..6186f4faa3a2a 100644
--- a/drivers/accel/rocket/rocket_device.c
+++ b/drivers/accel/rocket/rocket_device.c
@@ -6,18 +6,16 @@
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
-#include <linux/of.h>
 
 #include "rocket_device.h"
 
 struct rocket_device *rocket_device_init(struct platform_device *pdev,
-					 const struct drm_driver *rocket_drm_driver)
+					 const struct drm_driver *rocket_drm_driver,
+					 const struct rocket_soc_data *soc_data)
 {
 	struct device *dev = &pdev->dev;
-	struct device_node *core_node;
 	struct rocket_device *rdev;
 	struct drm_device *ddev;
-	unsigned int num_cores = 0;
 	int err;
 
 	rdev = devm_drm_dev_alloc(dev, rocket_drm_driver, struct rocket_device, ddev);
@@ -27,17 +25,14 @@ struct rocket_device *rocket_device_init(struct platform_device *pdev,
 	ddev = &rdev->ddev;
 	dev_set_drvdata(dev, rdev);
 
-	for_each_compatible_node(core_node, NULL, "rockchip,rk3588-rknn-core")
-		if (of_device_is_available(core_node))
-			num_cores++;
-
-	rdev->cores = devm_kcalloc(dev, num_cores, sizeof(*rdev->cores), GFP_KERNEL);
+	rdev->cores = devm_kcalloc(dev, soc_data->num_cores, sizeof(*rdev->cores),
+				   GFP_KERNEL);
 	if (!rdev->cores)
 		return ERR_PTR(-ENOMEM);
 
 	dma_set_max_seg_size(dev, UINT_MAX);
 
-	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(soc_data->dma_bits));
 	if (err)
 		return ERR_PTR(err);
 
diff --git a/drivers/accel/rocket/rocket_device.h b/drivers/accel/rocket/rocket_device.h
index ce662abc01d3d..2f74e078974e3 100644
--- a/drivers/accel/rocket/rocket_device.h
+++ b/drivers/accel/rocket/rocket_device.h
@@ -22,7 +22,8 @@ struct rocket_device {
 };
 
 struct rocket_device *rocket_device_init(struct platform_device *pdev,
-					 const struct drm_driver *rocket_drm_driver);
+					 const struct drm_driver *rocket_drm_driver,
+					 const struct rocket_soc_data *soc_data);
 void rocket_device_fini(struct rocket_device *rdev);
 #define to_rocket_device(drm_dev) \
 	((struct rocket_device *)(container_of((drm_dev), struct rocket_device, ddev)))
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index 384c38e13acce..f0beed2d522c7 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -159,11 +159,15 @@ static const struct drm_driver rocket_drm_driver = {
 
 static int rocket_probe(struct platform_device *pdev)
 {
+	const struct rocket_soc_data *soc_data = of_device_get_match_data(&pdev->dev);
 	int ret;
 
+	if (!soc_data)
+		return -EINVAL;
+
 	if (rdev == NULL) {
 		/* First core probing, initialize DRM device. */
-		rdev = rocket_device_init(drm_dev, &rocket_drm_driver);
+		rdev = rocket_device_init(drm_dev, &rocket_drm_driver, soc_data);
 		if (IS_ERR(rdev)) {
 			dev_err(&pdev->dev, "failed to initialize rocket device\n");
 			return PTR_ERR(rdev);
@@ -172,6 +176,12 @@ static int rocket_probe(struct platform_device *pdev)
 
 	unsigned int core = rdev->num_cores;
 
+	if (core >= soc_data->num_cores) {
+		dev_err(&pdev->dev, "too many NPU core nodes (max %u)\n",
+			soc_data->num_cores);
+		return -EINVAL;
+	}
+
 	dev_set_drvdata(&pdev->dev, rdev);
 
 	rdev->cores[core].rdev = rdev;
@@ -214,6 +224,7 @@ static void rocket_remove(struct platform_device *pdev)
 }
 
 static const struct rocket_soc_data rk3588_soc_data = {
+	.num_cores = 3,
 	.dma_bits = 40,
 };
 
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:10 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:10 +0200
Subject: [RFC PATCH v4 3/9] accel: rocket: Add RK3568 SoC support
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-4-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

The RK3568 has a single core of the same NVDLA-derived NPU IP as the
RK3588, with a 32-bit AXI master.  Add rk3568_soc_data and its
compatible.

Unlike the RK3588, the RK3568 NPU's compute clock is a PVTPLL managed by
TF-A via SCMI; start it from an noc_init callback with a real rate change
(an intermediate rate defeats the clock framework's unchanged-rate
shortcut).  Powering on and de-idling the NPU NoC are left to the power
domain (genpd), which performs them when the IOMMU supplier is resumed,
so the driver does not poke the PMU directly.

If noc_init fails, unwind through rocket_core_fini() so the core is torn
down completely rather than leaking the runtime-PM and IOMMU state.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c |  9 +++++++++
 drivers/accel/rocket/rocket_core.h |  3 +++
 drivers/accel/rocket/rocket_drv.c  | 31 ++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index 09c445af7de73..779e951596a15 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -88,6 +88,15 @@ int rocket_core_init(struct rocket_core *core)
 		return err;
 	}
 
+	if (core->soc_data->noc_init) {
+		err = core->soc_data->noc_init(core);
+		if (err) {
+			pm_runtime_put_sync(dev);
+			rocket_core_fini(core);
+			return err;
+		}
+	}
+
 	version = rocket_pc_readl(core, VERSION);
 	version += rocket_pc_readl(core, VERSION_NUM) & 0xffff;
 
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index d6421251670dc..5a145ba8c5a92 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -18,10 +18,13 @@ struct rocket_core;
  * struct rocket_soc_data - per-SoC configuration data
  * @num_cores: Number of NPU cores in this SoC.
  * @dma_bits: Physical address width reachable by the NPU's AXI master.
+ * @noc_init: Optional callback to bring up the NPU before it is reachable.
+ *            Used on RK3568 to start the PVTPLL compute clock via SCMI.
  */
 struct rocket_soc_data {
 	unsigned int num_cores;
 	unsigned int dma_bits;
+	int (*noc_init)(struct rocket_core *core);
 };
 
 #define rocket_pc_readl(core, reg) \
diff --git a/drivers/accel/rocket/rocket_drv.c b/drivers/accel/rocket/rocket_drv.c
index f0beed2d522c7..86484110ad6f0 100644
--- a/drivers/accel/rocket/rocket_drv.c
+++ b/drivers/accel/rocket/rocket_drv.c
@@ -10,6 +10,7 @@
 #include <linux/err.h>
 #include <linux/iommu.h>
 #include <linux/of.h>
+#include <linux/of_clk.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
@@ -223,12 +224,42 @@ static void rocket_remove(struct platform_device *pdev)
 	}
 }
 
+/*
+ * The NPU compute clock is a PVTPLL managed by TF-A via SCMI; spin it up
+ * with a real rate change (an intermediate rate defeats the clock
+ * framework's unchanged-rate shortcut).  Powering on and de-idling the NPU
+ * NoC are handled by the power domain (genpd) before the NPU is accessed.
+ */
+static int rk3568_noc_init(struct rocket_core *core)
+{
+	struct clk *npu_clk;
+
+	npu_clk = of_clk_get_by_name(core->dev->of_node, "npu");
+	if (IS_ERR(npu_clk))
+		return dev_err_probe(core->dev, PTR_ERR(npu_clk),
+				     "failed to get the NPU SCMI clock\n");
+
+	if (clk_set_rate(npu_clk, 600000000UL) ||
+	    clk_set_rate(npu_clk, 1000000000UL))
+		dev_warn(core->dev, "failed to set the NPU compute clock rate\n");
+	clk_put(npu_clk);
+
+	return 0;
+}
+
+static const struct rocket_soc_data rk3568_soc_data = {
+	.num_cores = 1,
+	.dma_bits = 32,
+	.noc_init = rk3568_noc_init,
+};
+
 static const struct rocket_soc_data rk3588_soc_data = {
 	.num_cores = 3,
 	.dma_bits = 40,
 };
 
 static const struct of_device_id dt_match[] = {
+	{ .compatible = "rockchip,rk3568-rknn-core", .data = &rk3568_soc_data },
 	{ .compatible = "rockchip,rk3588-rknn-core", .data = &rk3588_soc_data },
 	{}
 };
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:11 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:11 +0200
Subject: [RFC PATCH v4 4/9] accel: rocket: Reset the NPU before detaching the IOMMU on timeout
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-5-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

On a job timeout the NPU AXI master can be left wedged with
outstanding transactions. rocket_reset() detached the IOMMU group
before resetting the hardware, so iommu_detach_group() ->
__iommu_group_set_core_domain() asked the rk_iommu to stall and wait
for the in-flight transactions to drain. They never did, the stall
request timed out (-ETIMEDOUT) and the IOMMU core WARNed:

  WARNING: drivers/iommu/iommu.c:157 __iommu_group_set_core_domain
    iommu_detach_group
    rocket_reset
    rocket_job_timedout

Assert the core reset first: it quiesces the AXI master so the
following IOMMU detach completes cleanly. Move the detach after
rocket_core_reset() and out of the job_lock (it does not touch
in_flight_job).

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_job.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index ac51bff39833f..e25234261536b 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -364,14 +364,20 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
 		if (core->in_flight_job)
 			pm_runtime_put_noidle(core->dev);
 
-		iommu_detach_group(NULL, core->iommu_group);
-
 		core->in_flight_job = NULL;
 	}
 
-	/* Proceed with reset now. */
+	/*
+	 * Reset the NPU hardware before detaching the IOMMU. A timed-out job
+	 * leaves the NPU AXI master wedged; detaching the IOMMU then issues a
+	 * stall request that never drains and times out (warning in the IOMMU
+	 * core). Asserting the core reset first quiesces the master so the
+	 * detach completes cleanly.
+	 */
 	rocket_core_reset(core);
 
+	iommu_detach_group(NULL, core->iommu_group);
+
 	/* NPU has been reset, we can clear the reset pending bit. */
 	atomic_set(&core->reset.pending, 0);
 
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:12 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:12 +0200
Subject: [RFC PATCH v4 5/9] accel: rocket: Keep the IOMMU domain attached across jobs
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-6-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

rocket attached the job's IOMMU domain in rocket_job_run() and
detached it again on every completion and reset. Each attach/detach
toggles the rk_iommu stall/force-reset/paging handshake, and on
RK3568 the NPU MMU is idle between jobs, so that handshake times out
and logs a burst of "stall/paging request timed out" errors for
every job.

Attach the per-context domain once and keep it: track the attached
domain in the core, swap it only when a job from a different context
runs, and detach it at core teardown. A reference on the attached
domain is held so it outlives the job that first attached it and is
released on swap/teardown.

Because a hardware reset (on job timeout) wipes the IOMMU page-table
base register, drop the attached domain after rocket_core_reset() so
the next job re-attaches and reprograms it. Also tear down the
scheduler before detaching the IOMMU in rocket_core_fini(), so an
in-flight job can no longer reach the domain being detached.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/accel/rocket/rocket_core.c | 14 +++++++++++-
 drivers/accel/rocket/rocket_core.h |  3 +++
 drivers/accel/rocket/rocket_job.c  | 35 +++++++++++++++++++++++++-----
 3 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/drivers/accel/rocket/rocket_core.c b/drivers/accel/rocket/rocket_core.c
index 779e951596a15..6c128f585cff4 100644
--- a/drivers/accel/rocket/rocket_core.c
+++ b/drivers/accel/rocket/rocket_core.c
@@ -13,6 +13,7 @@
 #include <linux/reset.h>
 
 #include "rocket_core.h"
+#include "rocket_drv.h"
 #include "rocket_job.h"
 
 int rocket_core_init(struct rocket_core *core)
@@ -112,9 +113,20 @@ void rocket_core_fini(struct rocket_core *core)
 {
 	pm_runtime_dont_use_autosuspend(core->dev);
 	pm_runtime_disable(core->dev);
+
+	/*
+	 * Stop the scheduler before tearing down the IOMMU so an in-flight
+	 * job can no longer touch the (about to be detached) domain.
+	 */
+	rocket_job_fini(core);
+
+	if (core->attached_domain) {
+		iommu_detach_group(NULL, core->iommu_group);
+		rocket_iommu_domain_put(core->attached_domain);
+		core->attached_domain = NULL;
+	}
 	iommu_group_put(core->iommu_group);
 	core->iommu_group = NULL;
-	rocket_job_fini(core);
 }
 
 void rocket_core_reset(struct rocket_core *core)
diff --git a/drivers/accel/rocket/rocket_core.h b/drivers/accel/rocket/rocket_core.h
index 5a145ba8c5a92..78791ecb32e75 100644
--- a/drivers/accel/rocket/rocket_core.h
+++ b/drivers/accel/rocket/rocket_core.h
@@ -42,6 +42,8 @@ struct rocket_soc_data {
 #define rocket_core_writel(core, reg, value) \
 	writel(value, (core)->core_iomem + (REG_CORE_##reg) - REG_CORE_S_STATUS)
 
+struct rocket_iommu_domain;
+
 struct rocket_core {
 	struct device *dev;
 	struct rocket_device *rdev;
@@ -56,6 +58,7 @@ struct rocket_core {
 	struct reset_control_bulk_data resets[2];
 
 	struct iommu_group *iommu_group;
+	struct rocket_iommu_domain *attached_domain;
 
 	struct mutex job_lock;
 	struct rocket_job *in_flight_job;
diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c
index e25234261536b..368b2ebead1b3 100644
--- a/drivers/accel/rocket/rocket_job.c
+++ b/drivers/accel/rocket/rocket_job.c
@@ -9,6 +9,7 @@
 #include <drm/rocket_accel.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
+#include <linux/kref.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
@@ -314,9 +315,26 @@ static struct dma_fence *rocket_job_run(struct drm_sched_job *sched_job)
 	if (ret < 0)
 		return fence;
 
-	ret = iommu_attach_group(job->domain->domain, core->iommu_group);
-	if (ret < 0)
-		return fence;
+	/*
+	 * Attach the job's IOMMU domain only when it differs from the one
+	 * already attached. Re-attaching per job toggles the rk_iommu
+	 * stall/reset handshake on an idle NPU MMU, which is slow and
+	 * noisy; keep the domain attached across jobs instead.
+	 */
+	if (core->attached_domain != job->domain) {
+		if (core->attached_domain) {
+			iommu_detach_group(NULL, core->iommu_group);
+			rocket_iommu_domain_put(core->attached_domain);
+			core->attached_domain = NULL;
+		}
+
+		ret = iommu_attach_group(job->domain->domain, core->iommu_group);
+		if (ret < 0)
+			return fence;
+
+		kref_get(&job->domain->kref);
+		core->attached_domain = job->domain;
+	}
 
 	scoped_guard(mutex, &core->job_lock) {
 		core->in_flight_job = job;
@@ -340,7 +358,6 @@ static void rocket_job_handle_irq(struct rocket_core *core)
 				return;
 			}
 
-			iommu_detach_group(NULL, iommu_group_get(core->dev));
 			dma_fence_signal(core->in_flight_job->done_fence);
 			pm_runtime_put_autosuspend(core->dev);
 			core->in_flight_job = NULL;
@@ -376,7 +393,15 @@ rocket_reset(struct rocket_core *core, struct drm_sched_job *bad)
 	 */
 	rocket_core_reset(core);
 
-	iommu_detach_group(NULL, core->iommu_group);
+	/*
+	 * The reset wipes the IOMMU page-table base, so drop the attached
+	 * domain to force the next job to re-attach and reprogram it.
+	 */
+	if (core->attached_domain) {
+		iommu_detach_group(NULL, core->iommu_group);
+		rocket_iommu_domain_put(core->attached_domain);
+		core->attached_domain = NULL;
+	}
 
 	/* NPU has been reset, we can clear the reset pending bit. */
 	atomic_set(&core->reset.pending, 0);
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:13 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:13 +0200
Subject: [RFC PATCH v4 6/9] dt-bindings: npu: rockchip,rk3588-rknn-core: Add RK3568
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-7-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

The RK3568 carries a single core of the same NVDLA-derived NPU IP as the
RK3588.  Add its compatible.

On RK3568 the NPU NoC bus-idle and power gating are controlled through the
system PMU rather than a dedicated register block, so add a rockchip,pmu
phandle to that syscon.  The RK3568 NPU has no dedicated SRAM rail, so
sram-supply is required only on RK3588.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 .../npu/rockchip,rk3588-rknn-core.yaml        | 27 ++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
index caca2a4903cd1..e0b948ac47d45 100644
--- a/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
+++ b/Documentation/devicetree/bindings/npu/rockchip,rk3588-rknn-core.yaml
@@ -21,6 +21,7 @@ properties:
 
   compatible:
     enum:
+      - rockchip,rk3568-rknn-core
       - rockchip,rk3588-rknn-core
 
   reg:
@@ -50,6 +51,13 @@ properties:
 
   npu-supply: true
 
+  rockchip,pmu:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to the PMU syscon.  On RK3568 the NPU's NoC bus-idle and
+      power gating are controlled through the PMU; this points to that
+      syscon so those registers can be reached.
+
   power-domains:
     maxItems: 1
 
@@ -75,7 +83,24 @@ required:
   - resets
   - reset-names
   - npu-supply
-  - sram-supply
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: rockchip,rk3588-rknn-core
+    then:
+      required:
+        - sram-supply
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: rockchip,rk3568-rknn-core
+    then:
+      required:
+        - rockchip,pmu
 
 additionalProperties: false
 
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:15 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:15 +0200
Subject: [RFC PATCH v4 8/9] arm64: dts: rockchip: rk3568-rock-3b: Enable the NPU
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-9-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

Enable the NPU and its IOMMU on ROCK 3B and wire vdd_npu as the NPU
power domain's domain-supply, so genpd brings the rail up and down with
the domain (the domain is marked need_regulator). The PVTPLL compute
clock is brought up later by the driver.

The rail is no longer kept always-on, so pin it to 1000 mV (the NPU's
1 GHz operating voltage; the driver runs a fixed compute rate with no
devfreq voltage scaling) and mark it boot-on, so it is up before the
power domain de-idles the NPU NoC at power-on.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 .../arm64/boot/dts/rockchip/rk3568-rock-3b.dts | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
index 69001e453732e..d3f9776c2bdc3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
@@ -330,9 +330,10 @@ regulator-state-mem {
 
 			vdd_npu: DCDC_REG4 {
 				regulator-name = "vdd_npu";
+				regulator-boot-on;
 				regulator-initial-mode = <0x2>;
-				regulator-min-microvolt = <500000>;
-				regulator-max-microvolt = <1350000>;
+				regulator-min-microvolt = <1000000>;
+				regulator-max-microvolt = <1000000>;
 				regulator-ramp-delay = <6001>;
 
 				regulator-state-mem {
@@ -787,3 +788,16 @@ vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
 		remote-endpoint = <&hdmi_in_vp0>;
 	};
 };
+
+&pd_npu {
+	domain-supply = <&vdd_npu>;
+};
+
+&rknn_core_0 {
+	npu-supply = <&vdd_npu>;
+	status = "okay";
+};
+
+&rknn_mmu_0 {
+	status = "okay";
+};
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:14 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:14 +0200
Subject: [RFC PATCH v4 7/9] arm64: dts: rockchip: rk356x: Add the NPU and its IOMMU
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-8-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

The RK3568 has an NVDLA-derived NPU at fde40000 with its own IOMMU at
fde4b000. Add both nodes (disabled by default) and the NPU power-domain
child under the PMU power-controller, and point rockchip,pmu at the PMU
syscon that controls the NPU NoC bus-idle.

Besides the SCMI compute clock, assign the CRU CLK_NPU so the NPU AXI
bus clock comes up at 200 MHz rather than the 12 MHz boot default.

The power-domain deliberately carries no pm_qos: qos_npu sits behind the
NPU NoC, which is gated until the NPU is brought up, so a genpd power-off
QoS save would fault reading it.

Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
index 64bdd8b7754b5..313db59c1aed8 100644
--- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
@@ -512,6 +512,13 @@ power-domain at RK3568_PD_GPU {
 				#power-domain-cells = <0>;
 			};
 
+			pd_npu: power-domain at RK3568_PD_NPU {
+				reg = <RK3568_PD_NPU>;
+				clocks = <&cru ACLK_NPU_PRE>,
+					 <&cru HCLK_NPU_PRE>;
+				#power-domain-cells = <0>;
+			};
+
 			/* These power domains are grouped by VD_LOGIC */
 			power-domain at RK3568_PD_VI {
 				reg = <RK3568_PD_VI>;
@@ -572,6 +579,37 @@ power-domain at RK3568_PD_RKVENC {
 		};
 	};
 
+	rknn_core_0: npu at fde40000 {
+		compatible = "rockchip,rk3568-rknn-core";
+		reg = <0x0 0xfde40000 0x0 0x1000>,
+		      <0x0 0xfde41000 0x0 0x1000>,
+		      <0x0 0xfde43000 0x0 0x1000>;
+		reg-names = "pc", "cna", "core";
+		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>,
+			 <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_PRE>;
+		clock-names = "aclk", "hclk", "npu", "pclk";
+		assigned-clocks = <&scmi_clk SCMI_CLK_NPU>, <&cru CLK_NPU>;
+		assigned-clock-rates = <200000000>, <600000000>;
+		resets = <&cru SRST_A_NPU>, <&cru SRST_H_NPU>;
+		reset-names = "srst_a", "srst_h";
+		power-domains = <&power RK3568_PD_NPU>;
+		rockchip,pmu = <&pmu>;
+		iommus = <&rknn_mmu_0>;
+		status = "disabled";
+	};
+
+	rknn_mmu_0: iommu at fde4b000 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xfde4b000 0x0 0x40>;
+		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
+		clock-names = "aclk", "iface";
+		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>;
+		power-domains = <&power RK3568_PD_NPU>;
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
 	gpu: gpu at fde60000 {
 		compatible = "rockchip,rk3568-mali", "arm,mali-bifrost";
 		reg = <0x0 0xfde60000 0x0 0x4000>;
-- 
2.39.5



From midgy971 at gmail.com  Sat Jun 13 00:01:16 2026
From: midgy971 at gmail.com (MidG971)
Date: Sat, 13 Jun 2026 09:01:16 +0200
Subject: [RFC PATCH v4 9/9] pmdomain: rockchip: Add a regulator to the RK3568 NPU power domain
In-Reply-To: <20260613070116.438906-1-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
Message-ID: <20260613070116.438906-10-midgy971@gmail.com>

From: Midgy BALON <midgy971 at gmail.com>

The RK3568 NPU rail (vdd_npu) needs to be enabled before the domain is
powered on and disabled after it is powered off. Give DOMAIN_RK3568 a
regulator parameter (like DOMAIN_RK3588 already has) so the NPU domain
can set need_regulator, letting genpd manage the rail wired up as the
domain's domain-supply instead of marking it always-on in DT.

Suggested-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
Signed-off-by: Midgy BALON <midgy971 at gmail.com>
---
 drivers/pmdomain/rockchip/pm-domains.c | 36 ++++++++++++++++++--------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index 490bbb1d1d8e8..19db307e3811d 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -138,6 +138,20 @@ struct rockchip_pmu {
 	.active_wakeup = wakeup,			\
 }
 
+#define DOMAIN_M_R(_name, pwr, status, req, idle, ack, wakeup, regulator)	\
+{							\
+	.name = _name,				\
+	.pwr_w_mask = (pwr) << 16,			\
+	.pwr_mask = (pwr),				\
+	.status_mask = (status),			\
+	.req_w_mask = (req) << 16,			\
+	.req_mask = (req),				\
+	.idle_mask = (idle),				\
+	.ack_mask = (ack),				\
+	.active_wakeup = wakeup,			\
+	.need_regulator = regulator,			\
+}
+
 #define DOMAIN_M_G(_name, pwr, status, req, idle, ack, g_mask, wakeup, keepon)	\
 {							\
 	.name = _name,					\
@@ -241,8 +255,8 @@ struct rockchip_pmu {
 #define DOMAIN_RK3562(name, pwr, req, g_mask, mem, wakeup)		\
 	DOMAIN_M_G_SD(name, pwr, pwr, req, req, req, g_mask, mem, wakeup, false)
 
-#define DOMAIN_RK3568(name, pwr, req, wakeup)		\
-	DOMAIN_M(name, pwr, pwr, req, req, req, wakeup)
+#define DOMAIN_RK3568(name, pwr, req, wakeup, regulator)		\
+	DOMAIN_M_R(name, pwr, pwr, req, req, req, wakeup, regulator)
 
 #define DOMAIN_RK3576(name, p_offset, pwr, status, r_status, r_offset, req, idle, g_mask, wakeup)	\
 	DOMAIN_M_O_R_G(name, p_offset, pwr, status, 0, r_status, r_status, r_offset, req, idle, idle, g_mask, wakeup)
@@ -1274,15 +1288,15 @@ static const struct rockchip_domain_info rk3562_pm_domains[] = {
 };
 
 static const struct rockchip_domain_info rk3568_pm_domains[] = {
-	[RK3568_PD_NPU]		= DOMAIN_RK3568("npu",  BIT(1), BIT(2),  false),
-	[RK3568_PD_GPU]		= DOMAIN_RK3568("gpu",  BIT(0), BIT(1),  false),
-	[RK3568_PD_VI]		= DOMAIN_RK3568("vi",   BIT(6), BIT(3),  false),
-	[RK3568_PD_VO]		= DOMAIN_RK3568("vo",   BIT(7), BIT(4),  false),
-	[RK3568_PD_RGA]		= DOMAIN_RK3568("rga",  BIT(5), BIT(5),  false),
-	[RK3568_PD_VPU]		= DOMAIN_RK3568("vpu",  BIT(2), BIT(6),  false),
-	[RK3568_PD_RKVDEC]	= DOMAIN_RK3568("vdec", BIT(4), BIT(8),  false),
-	[RK3568_PD_RKVENC]	= DOMAIN_RK3568("venc", BIT(3), BIT(7),  false),
-	[RK3568_PD_PIPE]	= DOMAIN_RK3568("pipe", BIT(8), BIT(11), false),
+	[RK3568_PD_NPU]		= DOMAIN_RK3568("npu",  BIT(1), BIT(2),  false, true),
+	[RK3568_PD_GPU]		= DOMAIN_RK3568("gpu",  BIT(0), BIT(1),  false, false),
+	[RK3568_PD_VI]		= DOMAIN_RK3568("vi",   BIT(6), BIT(3),  false, false),
+	[RK3568_PD_VO]		= DOMAIN_RK3568("vo",   BIT(7), BIT(4),  false, false),
+	[RK3568_PD_RGA]		= DOMAIN_RK3568("rga",  BIT(5), BIT(5),  false, false),
+	[RK3568_PD_VPU]		= DOMAIN_RK3568("vpu",  BIT(2), BIT(6),  false, false),
+	[RK3568_PD_RKVDEC]	= DOMAIN_RK3568("vdec", BIT(4), BIT(8),  false, false),
+	[RK3568_PD_RKVENC]	= DOMAIN_RK3568("venc", BIT(3), BIT(7),  false, false),
+	[RK3568_PD_PIPE]	= DOMAIN_RK3568("pipe", BIT(8), BIT(11), false, false),
 };
 
 static const struct rockchip_domain_info rk3576_pm_domains[] = {
-- 
2.39.5



From jonas at kwiboo.se  Sat Jun 13 00:40:46 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Sat, 13 Jun 2026 09:40:46 +0200
Subject: [RFC PATCH v4 8/9] arm64: dts: rockchip: rk3568-rock-3b: Enable
 the NPU
In-Reply-To: <20260613070116.438906-9-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
 <20260613070116.438906-9-midgy971@gmail.com>
Message-ID: <e0f044df-9d34-4e6e-aa48-9e4227b4bdf7@kwiboo.se>

Hi Midgy,

On 6/13/2026 9:01 AM, MidG971 wrote:
> From: Midgy BALON <midgy971 at gmail.com>
> 
> Enable the NPU and its IOMMU on ROCK 3B and wire vdd_npu as the NPU
> power domain's domain-supply, so genpd brings the rail up and down with
> the domain (the domain is marked need_regulator). The PVTPLL compute
> clock is brought up later by the driver.
> 
> The rail is no longer kept always-on, so pin it to 1000 mV (the NPU's
> 1 GHz operating voltage; the driver runs a fixed compute rate with no
> devfreq voltage scaling) and mark it boot-on, so it is up before the
> power domain de-idles the NPU NoC at power-on.
> 
> Signed-off-by: Midgy BALON <midgy971 at gmail.com>
> ---
>  .../arm64/boot/dts/rockchip/rk3568-rock-3b.dts | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
> index 69001e453732e..d3f9776c2bdc3 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3568-rock-3b.dts
> @@ -330,9 +330,10 @@ regulator-state-mem {
>  
>  			vdd_npu: DCDC_REG4 {
>  				regulator-name = "vdd_npu";
> +				regulator-boot-on;

There is no need for the NPU in the bootloader, do not use DT as a
workaround for software issues.

This series mention the PVTPLL NPU clk and seem to contains some
workarounds related to how the PVTPLL clock is handled in TF-A.

The PVTPLL block typically require the pclk and power domain enabled to
function, and this series seem to add workarounds to try and ensure this,
e.g. with noc_init to activate PVTPLL usage.

I would suggest that you do not involve the PVTPLL clock in this initial
NPU support for RK3568, set CLK_NPU to 400 MHz and use it instead of the
SCMI clock, or keep SCMI clk rate less than or equal to 400 MHz to
disable PVTPLL_NEED mode in TF-A.

In a future series you can extend Linux with a proper PVTPLL clk driver
and OPP support for the rocket driver to correctly ensure pclk and pd is
enabled when a PVTPLL clock is managed.

>  				regulator-initial-mode = <0x2>;
> -				regulator-min-microvolt = <500000>;
> -				regulator-max-microvolt = <1350000>;
> +				regulator-min-microvolt = <1000000>;
> +				regulator-max-microvolt = <1000000>;

Please describe the HW, do not add workarounds for software issues or
shortcomings.

Regards,
Jonas

>  				regulator-ramp-delay = <6001>;
>  
>  				regulator-state-mem {
> @@ -787,3 +788,16 @@ vp0_out_hdmi: endpoint at ROCKCHIP_VOP2_EP_HDMI0 {
>  		remote-endpoint = <&hdmi_in_vp0>;
>  	};
>  };
> +
> +&pd_npu {
> +	domain-supply = <&vdd_npu>;
> +};
> +
> +&rknn_core_0 {
> +	npu-supply = <&vdd_npu>;
> +	status = "okay";
> +};
> +
> +&rknn_mmu_0 {
> +	status = "okay";
> +};



From jonas at kwiboo.se  Sat Jun 13 01:18:09 2026
From: jonas at kwiboo.se (Jonas Karlman)
Date: Sat, 13 Jun 2026 10:18:09 +0200
Subject: [RFC PATCH v4 7/9] arm64: dts: rockchip: rk356x: Add the NPU and
 its IOMMU
In-Reply-To: <20260613070116.438906-8-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
 <20260613070116.438906-8-midgy971@gmail.com>
Message-ID: <0e6466aa-a153-446b-b31c-e9b331573358@kwiboo.se>

Hi Midgy,

On 6/13/2026 9:01 AM, MidG971 wrote:
> From: Midgy BALON <midgy971 at gmail.com>
> 
> The RK3568 has an NVDLA-derived NPU at fde40000 with its own IOMMU at
> fde4b000. Add both nodes (disabled by default) and the NPU power-domain
> child under the PMU power-controller, and point rockchip,pmu at the PMU
> syscon that controls the NPU NoC bus-idle.
> 
> Besides the SCMI compute clock, assign the CRU CLK_NPU so the NPU AXI
> bus clock comes up at 200 MHz rather than the 12 MHz boot default.
> 
> The power-domain deliberately carries no pm_qos: qos_npu sits behind the
> NPU NoC, which is gated until the NPU is brought up, so a genpd power-off
> QoS save would fault reading it.
> 
> Signed-off-by: Midgy BALON <midgy971 at gmail.com>
> ---
>  arch/arm64/boot/dts/rockchip/rk356x-base.dtsi | 38 +++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
> index 64bdd8b7754b5..313db59c1aed8 100644
> --- a/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk356x-base.dtsi
> @@ -512,6 +512,13 @@ power-domain at RK3568_PD_GPU {
>  				#power-domain-cells = <0>;
>  			};
>  
> +			pd_npu: power-domain at RK3568_PD_NPU {
> +				reg = <RK3568_PD_NPU>;
> +				clocks = <&cru ACLK_NPU_PRE>,
> +					 <&cru HCLK_NPU_PRE>;
> +				#power-domain-cells = <0>;
> +			};
> +
>  			/* These power domains are grouped by VD_LOGIC */
>  			power-domain at RK3568_PD_VI {
>  				reg = <RK3568_PD_VI>;
> @@ -572,6 +579,37 @@ power-domain at RK3568_PD_RKVENC {
>  		};
>  	};
>  
> +	rknn_core_0: npu at fde40000 {
> +		compatible = "rockchip,rk3568-rknn-core";
> +		reg = <0x0 0xfde40000 0x0 0x1000>,
> +		      <0x0 0xfde41000 0x0 0x1000>,
> +		      <0x0 0xfde43000 0x0 0x1000>;
> +		reg-names = "pc", "cna", "core";
> +		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>,
> +			 <&scmi_clk SCMI_CLK_NPU>, <&cru PCLK_NPU_PRE>;
> +		clock-names = "aclk", "hclk", "npu", "pclk";
> +		assigned-clocks = <&scmi_clk SCMI_CLK_NPU>, <&cru CLK_NPU>;
> +		assigned-clock-rates = <200000000>, <600000000>;

This looks strange, the SCMI clk can be seen as a virtual clock that
changes between normal CRU NPU clk and a PVTPLL NPU clk (depending on
rate). 200 MHz, a typical opp-suspend value (switch to CRU clk instead
of PVTPLL), will set the CLK_NPU rate to 200 MHz, then setting CLK_NPU
to 600 MHz (the lowest rate that activates PVTPLL mode) outside of SCMI
control looks strange.

Suggest you only set SCMI NPU clk rate to 200 or 400 MHz and drop any
special handling, e.g. noc_init, to closer match RK3588 and defer any
use of PVTPLL clk to a future series that also adds OPP support.

> +		resets = <&cru SRST_A_NPU>, <&cru SRST_H_NPU>;
> +		reset-names = "srst_a", "srst_h";
> +		power-domains = <&power RK3568_PD_NPU>;
> +		rockchip,pmu = <&pmu>;

This looks wrong, the rockchip,pmu prop is typically used to reference
PMU GRF, see i.e. pinctrl node, not the power-management that is seem to
be correctly abstracted using power-domains above, please drop this prop.

Regards,
Jonas

> +		iommus = <&rknn_mmu_0>;
> +		status = "disabled";
> +	};
> +
> +	rknn_mmu_0: iommu at fde4b000 {
> +		compatible = "rockchip,iommu";
> +		reg = <0x0 0xfde4b000 0x0 0x40>;
> +		interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
> +		clock-names = "aclk", "iface";
> +		clocks = <&cru ACLK_NPU>, <&cru HCLK_NPU>;
> +		power-domains = <&power RK3568_PD_NPU>;
> +		#iommu-cells = <0>;
> +		status = "disabled";
> +	};
> +
>  	gpu: gpu at fde60000 {
>  		compatible = "rockchip,rk3568-mali", "arm,mali-bifrost";
>  		reg = <0x0 0xfde60000 0x0 0x4000>;



From krzk at kernel.org  Sat Jun 13 03:44:07 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sat, 13 Jun 2026 12:44:07 +0200
Subject: [PATCH 2/4] dt-bindings: mfd: Add UGREEN NASync DH2300 MCU
In-Reply-To: <20260612-dh2300-mcu-v1-2-ab8db1617bc0@flipper.net>
References: <20260612-dh2300-mcu-v1-0-ab8db1617bc0@flipper.net>
 <20260612-dh2300-mcu-v1-2-ab8db1617bc0@flipper.net>
Message-ID: <20260613-elite-panda-of-success-75eecd@quoll>

On Fri, Jun 12, 2026 at 07:34:15PM +0400, Alexey Charkov wrote:
> Document the UGREEN NASync DH2300 embedded controller (HC32F005 MCU),
> which is responsible for gating the SATA drive-bay power rail and
> providing a hardware watchdog.
> 
> This is based on disassebly of a GPL binary from vendor firmware for which
> no source code could be found, so parts of it can be inaccurate. Only
> the power gating function is confirmed.
> 
> Signed-off-by: Alexey Charkov <alchark at flipper.net>
> ---
>  .../devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml | 62 ++++++++++++++++++++++
>  MAINTAINERS                                        |  5 ++
>  2 files changed, 67 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml b/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml
> new file mode 100644
> index 000000000000..847970c609cd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/ugreen,dh2300-mcu.yaml

Place it in embedded-controller

> @@ -0,0 +1,62 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/ugreen,dh2300-mcu.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: UGREEN NASync DH2300 embedded controller
> +
> +maintainers:
> +  - Alexey Charkov <alchark at flipper.net>
> +
> +description:
> +  The UGREEN NASync DH2300 NAS carries a HC32F005 microcontroller on I2C that
> +  acts as a board embedded controller. It gates power to the SATA drive bays
> +  through an internal register and apparently also serves as a watchdog
> +  (unconfirmed, as vendor kernel sources are unavailable, works without it)
> +
> +properties:
> +  compatible:
> +    const: ugreen,dh2300-mcu
> +
> +  reg:
> +    maxItems: 1
> +
> +  regulator:

This should have specific name matching the actual regulator name, e.g.
pin.

> +    type: object
> +    $ref: /schemas/regulator/regulator.yaml#
> +    unevaluatedProperties: false
> +    description:
> +      The SATA drive-bay power gate controlled by the MCU.
> +
> +  watchdog-gpios:
> +    description:
> +      Optional GPIO line used to ping the hardware watchdog function of the MCU
> +    maxItems: 1

Best regards,
Krzysztof



From sboyd at kernel.org  Sat Jun 13 14:51:04 2026
From: sboyd at kernel.org (Stephen Boyd)
Date: Sat, 13 Jun 2026 14:51:04 -0700
Subject: [GIT PULL] Rockchip clock changes for 7.2 #1
In-Reply-To: <4272848.9fHWaBTJ5E@phil>
References: <4272848.9fHWaBTJ5E@phil>
Message-ID: <178138746455.819343.17093210868169147733@localhost.localdomain>

Quoting Heiko Stuebner (2026-06-07 13:59:31)
> Hi Mike, Stephen,
> 
> please find below a pull-request with a Rockchip clock change for 7.2
> 
> Please pull.
> 
> Thanks
> Heiko
> 
> 
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v7.2-rockchip-clk1
> 
> for you to fetch changes up to 7edfb7fb58ee058298e18fde76a6077ef17d19d8:
> 
>   clk: rockchip: allow COMPILE_TEST builds (2026-05-13 12:35:57 +0200)
> 
> ----------------------------------------------------------------

Thanks. Pulled into clk-next


From broonie at kernel.org  Sat Jun 13 17:00:00 2026
From: broonie at kernel.org (Mark Brown)
Date: Sun, 14 Jun 2026 01:00:00 +0100
Subject: [PATCH] ASoC: Match DT helper types
In-Reply-To: <20260612214904.1882991-1-robh@kernel.org>
References: <20260612214904.1882991-1-robh@kernel.org>
Message-ID: <ai3vAG1-rXB2fanG@sirena.co.uk>

On Fri, Jun 12, 2026 at 04:49:02PM -0500, Rob Herring (Arm) wrote:
> The affected ASoC drivers read properties whose bindings use boolean
> flags, normal uint32 cells, or phandle-style arrays. Using helpers for
> a different encoding makes those accesses disagree with the binding.

> Use helpers that match the documented encoding and keep the existing
> driver storage by copying through temporary values where needed.

This feels like it would be easier to deal with as separate commits for
each issue...

> --- a/sound/soc/rockchip/rockchip_pdm.c
> +++ b/sound/soc/rockchip/rockchip_pdm.c
> @@ -546,8 +546,7 @@ static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *n
>  	unsigned int path[PDM_PATH_MAX];
>  	int cnt = 0, ret = 0, i = 0, val = 0, msk = 0;
>  
> -	cnt = of_count_phandle_with_args(node, "rockchip,path-map",
> -					 NULL);
> +	cnt = of_property_count_u32_elems(node, "rockchip,path-map");
>  	if (cnt != PDM_PATH_MAX)
>  		return cnt;

The error codes reported by these two functions for missing properties
differ (-ENOENT vs -EINVAL) and the caller of this function has a
specific check for -ENOENT which allows it.
-------------- 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-rockchip/attachments/20260614/cdde39dc/attachment.sig>

From michael.bommarito at gmail.com  Sun Jun 14 06:09:57 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:09:57 -0400
Subject: [PATCH 0/6] media: v4l2-ctrls: bound stateless HEVC/AV1 tile counts
Message-ID: <20260614131003.2524025-1-michael.bommarito@gmail.com>

The stateless HEVC and AV1 V4L2 controls carry tile counts that several SoC
decoder drivers consume as loop bounds and divisors when laying out
fixed-size hardware descriptor buffers, but std_validate_compound() does not
bound them. A process with access to a /dev/videoN stateless decoder (on a
typical desktop or SBC, the active-seat local user via the logind/udev
uaccess ACL, no extra capability) can set a HEVC PPS or AV1 frame control
with a tile count far beyond the array capacity the drivers assume, making
them loop past their fixed buffers.

Patch 1 caps the HEVC and AV1 tile counts to the uAPI array capacity in the
core. Patches 2-5 add matching bounds in the consuming driver loops (and
bound the driver-interpreted HEVC pic_parameter_set_id / AV1
context_update_tile_id indices the core does not reject). Patch 6 adds
KUnit tests for the core validation.

I did my best to reproduce these with the hardware I have, but apologies
in advance if I missed something because the soft repro.

Test matrix: patch 1 + patch 6 run the real std_validate_compound() under
KASAN on x86_64 (rejects out-of-range counts, in-range pass, stock and
patched); all objects build clean W=1; the ARM SoC decoders are not
reachable on the x86 host, so the per-driver writes are not reproduced here.

Michael Bommarito (6):
  media: v4l2-ctrls: validate HEVC and AV1 tile counts
  media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
  media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer
    capacity
  media: verisilicon: rockchip: bound VPU981 AV1 tile loop and guard
    divisor
  media: mediatek: vcodec: bound AV1 tile-start copy to the array
    capacity
  media: v4l2-ctrls: add KUnit tests for compound control tile
    validation

 .../vcodec/decoder/vdec/vdec_av1_req_lat_if.c |   5 +-
 .../rockchip/rkvdec/rkvdec-hevc-common.c      |  22 +++-
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   8 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |   2 +
 .../platform/verisilicon/hantro_g2_hevc_dec.c |   6 +
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  |  29 +++--
 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 119 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |  27 ++++
 9 files changed, 213 insertions(+), 17 deletions(-)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c

base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:09:58 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:09:58 -0400
Subject: [PATCH 1/6] media: v4l2-ctrls: validate HEVC and AV1 tile counts
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-2-michael.bommarito@gmail.com>

The stateless HEVC and AV1 controls carry tile counts that several SoC
decoder drivers consume as loop bounds when laying out fixed-size hardware
descriptor buffers, but std_validate_compound() does not bound them.

For V4L2_CTRL_TYPE_HEVC_PPS with tiling enabled, num_tile_columns_minus1
and num_tile_rows_minus1 (u8) drive loops over column_width_minus1[20] and
row_height_minus1[22]. For V4L2_CTRL_TYPE_AV1_FRAME, tile_info.tile_cols
and tile_rows (u8) bound loops over the mi_*_starts[] / *_in_sbs_minus_1[]
arrays and a zero tile_cols divides by zero. Cap both to the uAPI array
capacity and reject out-of-range values with -EINVAL.

These are active-count fields (loop bounds), so bounding them here mirrors
the existing num_active_dpb_entries check. Driver-interpreted index values
(HEVC pic_parameter_set_id, AV1 context_update_tile_id) are bounded in the
consuming drivers instead (patches 2 and 4).

Fixes: 256fa3920874 ("media: v4l: Add definitions for HEVC stateless decoding")
Fixes: 9de30f579980 ("media: Add AV1 uAPI")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
These are loop-bound counts, not per-entry index values, so bounding them
in the common path mirrors the existing num_active_dpb_entries check.

Tested with the KUnit suite in patch 6: under KASAN on x86_64 the new
checks reject the over-range HEVC/AV1 tile counts and the zero AV1
tile_cols with -EINVAL while the in-range cases still pass, on stock and
patched.

 drivers/media/v4l2-core/v4l2-ctrls-core.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6b37572..25227d9 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -790,10 +790,25 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
 	return 0;
 }
 
+static int validate_av1_tile_info(struct v4l2_av1_tile_info *t)
+{
+	/* Loop bounds and a divisor in the stateless AV1 drivers. */
+	if (t->tile_cols < 1 || t->tile_cols > V4L2_AV1_MAX_TILE_COLS)
+		return -EINVAL;
+
+	if (t->tile_rows < 1 || t->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
 {
 	int ret = 0;
 
+	ret = validate_av1_tile_info(&f->tile_info);
+	if (ret)
+		return ret;
 	ret = validate_av1_quantization(&f->quantization);
 	if (ret)
 		return ret;
@@ -1242,6 +1257,14 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 
 			p_hevc_pps->flags &=
 				~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+		} else {
+			/* Loop bounds in the stateless HEVC drivers. */
+			if (p_hevc_pps->num_tile_columns_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->column_width_minus1))
+				return -EINVAL;
+			if (p_hevc_pps->num_tile_rows_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->row_height_minus1))
+				return -EINVAL;
 		}
 
 		if (p_hevc_pps->flags &
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:09:59 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:09:59 -0400
Subject: [PATCH 2/6] media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-3-michael.bommarito@gmail.com>

compute_tiles_uniform() / compute_tiles_non_uniform() and assemble_hw_pps()
loop over num_tile_columns_minus1 / num_tile_rows_minus1 to write the
per-tile column_width[] / row_height[] arrays, sized to the PPS uAPI arrays
column_width_minus1[20] / row_height_minus1[22]; bound the loops to that
capacity. assemble_hw_pps() also indexes the fixed param_set[] table by
pic_parameter_set_id, a driver-interpreted index the core does not reject;
bound it to the table size before the access.

Fixes: 3595375c2301 ("media: rkvdec: Add HEVC backend")
Fixes: c9a59dc2acc7 ("media: rkvdec: Add HEVC support for the VDPU381 variant")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
The decoder is an ARM SoC block (Rockchip RK33xx/RK35xx) not reachable on
the x86 KUnit host, so the driver-side out-of-bounds write is not
reproduced here.

 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 22 +++++++++++++++----
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |  8 +++++--
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |  2 ++
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 3119f3b..d0f26f7 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -37,15 +37,22 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
 			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols, num_rows;
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+	/* Bound the loops to the column_width[]/row_height[] capacity. */
+	num_cols = min_t(unsigned int, pps->num_tile_columns_minus1 + 1,
+			 ARRAY_SIZE(pps->column_width_minus1));
+	num_rows = min_t(unsigned int, pps->num_tile_rows_minus1 + 1,
+			 ARRAY_SIZE(pps->row_height_minus1));
+
+	for (i = 0; i < num_cols; 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++)
+	for (i = 0; i < num_rows; i++)
 		row_height[i] = ((i + 1) * pic_in_cts_height) /
 				(pps->num_tile_rows_minus1 + 1) -
 				(i * pic_in_cts_height) /
@@ -57,17 +64,24 @@ 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)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols, num_rows;
 	s32 sum = 0;
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+	/* Leave one slot for the trailing last-tile entry written below. */
+	num_cols = min_t(unsigned int, pps->num_tile_columns_minus1,
+			 ARRAY_SIZE(pps->column_width_minus1) - 1);
+	num_rows = min_t(unsigned int, pps->num_tile_rows_minus1,
+			 ARRAY_SIZE(pps->row_height_minus1) - 1);
+
+	for (i = 0; i < num_cols; 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++) {
+	for (i = 0; i < num_rows; i++) {
 		row_height[i] = pps->row_height_minus1[i] + 1;
 		sum += row_height[i];
 	}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index ac8b825..29b5adb 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -156,6 +156,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
@@ -274,9 +276,11 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
 		/* Userspace also provide column width and row height for uniform spacing */
-		for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+		for (i = 0; i <= pps->num_tile_columns_minus1 &&
+		     i < ARRAY_SIZE(pps->column_width_minus1); i++)
 			WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i));
-		for (i = 0; i <= pps->num_tile_rows_minus1; i++)
+		for (i = 0; i <= pps->num_tile_rows_minus1 &&
+		     i < ARRAY_SIZE(pps->row_height_minus1); i++)
 			WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i));
 	} else {
 		WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index fe6414a..6dafa1d 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:10:00 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:10:00 -0400
Subject: [PATCH 3/6] media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer capacity
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-4-michael.bommarito@gmail.com>

prepare_tile_info_buffer() writes one entry per tile into the tile_sizes
DMA buffer, sized for a grid equal to the PPS uAPI array capacity. Bound
the loop to that capacity so the writes stay inside the buffer.

Fixes: cb5dd5a0fa51 ("media: hantro: Introduce G2/HEVC decoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
This is an i.MX8M Hantro G2 SoC block not reachable on the x86 KUnit host,
so the driver-side out-of-bounds write is not reproduced here.

 drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
index e8c2e83..94fbd79 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
@@ -22,6 +22,12 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
 	bool tiles_enabled, uniform_spacing;
 	u32 no_chroma = 0;
 
+	/* Bound the loops to the tile_sizes buffer capacity. */
+	num_tile_cols = min_t(unsigned int, num_tile_cols,
+			      ARRAY_SIZE(pps->column_width_minus1));
+	num_tile_rows = min_t(unsigned int, num_tile_rows,
+			      ARRAY_SIZE(pps->row_height_minus1));
+
 	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
 	uniform_spacing = !!(pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING);
 
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:10:01 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:10:01 -0400
Subject: [PATCH 4/6] media: verisilicon: rockchip: bound VPU981 AV1 tile loop and guard divisor
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-5-michael.bommarito@gmail.com>

rockchip_vpu981_av1_dec_set_tile_info() divides context_update_tile_id by
tile_info->tile_cols and writes one descriptor per tile into the tile_info
DMA buffer, sized for AV1_MAX_TILES. tile_cols / tile_rows come straight
from the bitstream; reject a zero column or row count and bound the grid to
AV1_MAX_TILES so the division is safe and the writes stay in the buffer.

Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
This is a Rockchip RK35xx SoC block not reachable on the x86 KUnit host,
so the driver-side out-of-bounds write is not reproduced here.

 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 29 +++++++++++++------
 1 file changed, 20 insertions(+), 9 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 e4e21ad..71d2ef7 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -578,21 +578,32 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
 	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
 	const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
 	    ctrls->tile_group_entry;
-	int context_update_y =
-	    tile_info->context_update_tile_id / tile_info->tile_cols;
-	int context_update_x =
-	    tile_info->context_update_tile_id % tile_info->tile_cols;
-	int context_update_tile_id =
-	    context_update_x * tile_info->tile_rows + context_update_y;
+	unsigned int tile_cols, tile_rows;
+	int context_update_y, context_update_x, context_update_tile_id;
 	u8 *dst = av1_dec->tile_info.cpu;
 	struct hantro_dev *vpu = ctx->dev;
 	int tile0, tile1;
 
+	/* Guard the divisor and bound the grid to the tile_info buffer. */
+	tile_cols = tile_info->tile_cols;
+	tile_rows = tile_info->tile_rows;
+	if (!tile_cols || !tile_rows)
+		return;
+	if (tile_cols * tile_rows > AV1_MAX_TILES) {
+		tile_cols = min_t(unsigned int, tile_cols, AV1_MAX_TILES);
+		tile_rows = min_t(unsigned int, tile_rows,
+				  AV1_MAX_TILES / tile_cols);
+	}
+
+	context_update_y = tile_info->context_update_tile_id / tile_cols;
+	context_update_x = tile_info->context_update_tile_id % tile_cols;
+	context_update_tile_id = context_update_x * tile_rows + context_update_y;
+
 	memset(dst, 0, av1_dec->tile_info.size);
 
-	for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
-		for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
-			int tile_id = tile1 * tile_info->tile_cols + tile0;
+	for (tile0 = 0; tile0 < tile_cols; tile0++) {
+		for (tile1 = 0; tile1 < tile_rows; tile1++) {
+			int tile_id = tile1 * tile_cols + tile0;
 			u32 start, end;
 			u32 y0 =
 			    tile_info->height_in_sbs_minus_1[tile1] + 1;
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:10:02 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:10:02 -0400
Subject: [PATCH 5/6] media: mediatek: vcodec: bound AV1 tile-start copy to the array capacity
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-6-michael.bommarito@gmail.com>

vdec_av1_slice_setup_tile() copies tile_cols + 1 / tile_rows + 1 start
positions into mi_col_starts[] / mi_row_starts[], which hold
V4L2_AV1_MAX_TILE_COLS + 1 / V4L2_AV1_MAX_TILE_ROWS + 1 entries. tile_cols
and tile_rows come straight from the bitstream; bound the copy to the array
capacity so the accesses stay in range.

Fixes: 0934d3759615 ("media: mediatek: vcodec: separate decoder and encoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
This is an MT8195-class SoC block not reachable on the x86 KUnit host, so
the driver-side out-of-bounds access is not reproduced here.

 .../mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c       | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 2d622e8..49d9b4a 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame,
 	tile->uniform_tile_spacing_flag =
 		BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING);
 
-	for (i = 0; i < tile->tile_cols + 1; i++)
+	/* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */
+	for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++)
 		tile->mi_col_starts[i] =
 			ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 
-	for (i = 0; i < tile->tile_rows + 1; i++)
+	for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++)
 		tile->mi_row_starts[i] =
 			ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 }
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 06:10:03 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 09:10:03 -0400
Subject: [PATCH 6/6] media: v4l2-ctrls: add KUnit tests for compound control tile validation
In-Reply-To: <20260614131003.2524025-1-michael.bommarito@gmail.com>
References: <20260614131003.2524025-1-michael.bommarito@gmail.com>
Message-ID: <20260614131003.2524025-7-michael.bommarito@gmail.com>

Drive std_validate_compound() with crafted HEVC PPS and AV1 frame controls
and assert that out-of-range tile counts and a zero AV1 tile_cols are
rejected with -EINVAL while in-range values pass. The tests are #included
at the end of v4l2-ctrls-core.c to reach the static helper, gated by
CONFIG_V4L2_CTRLS_KUNIT_TEST.

Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
The tests are #included at the end of v4l2-ctrls-core.c so they can reach
the static helper, gated by CONFIG_V4L2_CTRLS_KUNIT_TEST. Run under KASAN
on x86_64 they fail on the stock validator and pass after patch 1.

 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 119 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |   4 +
 3 files changed, 135 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index d50ccac..04b15d8 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -3,6 +3,18 @@
 # Generic video config states
 #
 
+config V4L2_CTRLS_KUNIT_TEST
+	bool "KUnit tests for V4L2 compound control validation" if !KUNIT_ALL_TESTS
+	depends on VIDEO_DEV && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  This builds KUnit tests for the stateless-codec compound control
+	  validation in std_validate_compound(). They check that out-of-range
+	  HEVC/AV1 tile counts and parameter-set / tile indices are rejected
+	  before driver code consumes them as array indices or loop bounds.
+
+	  If unsure, say N.
+
 config VIDEO_V4L2_I2C
 	bool
 	depends on I2C && VIDEO_DEV
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core-test.c b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
new file mode 100644
index 0000000..6ec48fc
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for HEVC/AV1 tile-count validation in std_validate_compound().
+ * #included at the end of v4l2-ctrls-core.c to reach the static helper.
+ */
+
+#include <kunit/test.h>
+
+static int call_validate_compound(enum v4l2_ctrl_type type, void *payload,
+				  u32 elem_size)
+{
+	struct v4l2_ctrl ctrl = {
+		.type = type,
+		.elem_size = elem_size,
+	};
+	union v4l2_ctrl_ptr ptr = { .p = payload };
+
+	return std_validate_compound(&ctrl, 0, ptr);
+}
+
+/* HEVC PPS: num_tile_columns_minus1 / num_tile_rows_minus1 bounds. */
+static void v4l2_ctrls_hevc_pps_tile_cols(struct kunit *test)
+{
+	struct v4l2_ctrl_hevc_pps *pps;
+
+	pps = kunit_kzalloc(test, sizeof(*pps), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, pps);
+
+	pps->flags = V4L2_HEVC_PPS_FLAG_TILES_ENABLED;
+
+	/* In range: count == array capacity (minus1 == capacity - 1). */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1) - 1;
+	pps->num_tile_rows_minus1 = ARRAY_SIZE(pps->row_height_minus1) - 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			0);
+
+	/* Out of range: one past the column array. */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1);
+	pps->num_tile_rows_minus1 = 0;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	pps->num_tile_columns_minus1 = 0xff;
+	pps->num_tile_rows_minus1 = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+}
+
+/* AV1 frame: tile_cols / tile_rows bounds and non-zero requirement. */
+static void v4l2_ctrls_av1_frame_tile(struct kunit *test)
+{
+	struct v4l2_ctrl_av1_frame *f;
+
+	f = kunit_kzalloc(test, sizeof(*f), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, f);
+
+	/* In range: a 1x1 tiling (a zeroed frame is otherwise valid). */
+	f->tile_info.tile_cols = 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* In range: maximal legal tile_cols / tile_rows. */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* Out of range: tile_cols past the array. */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS + 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	f->tile_info.tile_cols = 0xff;
+	f->tile_info.tile_rows = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Divide-by-zero guard: tile_cols == 0 must be rejected. */
+	f->tile_info.tile_cols = 0;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+}
+
+static struct kunit_case v4l2_ctrls_test_cases[] = {
+	KUNIT_CASE(v4l2_ctrls_hevc_pps_tile_cols),
+	KUNIT_CASE(v4l2_ctrls_av1_frame_tile),
+	{}
+};
+
+static struct kunit_suite v4l2_ctrls_test_suite = {
+	.name = "v4l2-ctrls-compound",
+	.test_cases = v4l2_ctrls_test_cases,
+};
+
+kunit_test_suite(v4l2_ctrls_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for V4L2 stateless-codec compound control validation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 25227d9..8debd0e 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -2851,3 +2851,7 @@ int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
 	return hdl->error;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
+
+#if IS_ENABLED(CONFIG_V4L2_CTRLS_KUNIT_TEST)
+#include "v4l2-ctrls-core-test.c"
+#endif
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:02 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:02 -0400
Subject: [PATCH v2 0/6] media: v4l2-ctrls: bound stateless HEVC/AV1 tile counts
Message-ID: <20260614155609.3107600-1-michael.bommarito@gmail.com>

The stateless HEVC and AV1 V4L2 controls carry tile counts that several SoC
decoder drivers consume as loop bounds when laying out fixed-size hardware
descriptor buffers, but std_validate_compound() does not bound them. A
process with access to a /dev/videoN stateless decoder (on a typical desktop
or SBC, the active-seat local user via the logind/udev uaccess ACL, no extra
capability) can set a HEVC PPS or AV1 frame control with a tile count far
beyond the array capacity the drivers assume, making them loop past their
fixed buffers.

Patch 1 caps the HEVC and AV1 tile counts to the uAPI array capacity in the
core. Patches 2-5 add matching bounds in the consuming driver loops (and
bound the driver-interpreted HEVC pic_parameter_set_id / AV1
context_update_tile_id indices the core does not reject). Patch 6 adds KUnit
tests for the core validation.

I did my best to reproduce these with the hardware I have, but apologies in
advance if I missed something because the soft repro.

Test matrix: patch 1 + patch 6 run the real std_validate_compound() under
KASAN on x86_64 (rejects out-of-range counts, in-range and the zeroed
default pass, stock and patched); all objects build clean W=1; the ARM SoC
decoders are not reachable on the x86 host, so the per-driver writes are not
reproduced here.

Changes since v1:
 - Patch 1: only reject AV1 tile_cols/tile_rows above the array capacity;
   do not reject a zero count. v1 also rejected tile_cols < 1, which made
   std_validate_compound() return -EINVAL for the zero-initialised AV1
   frame control that userspace and v4l2-compliance submit, regressing the
   visl compliance run (reported by the linux-media CI). The divide-by-zero
   that a zero tile_cols would cause is guarded where the divisor is used in
   the rockchip decoder (patch 4), so no functional protection is lost.
 - Patch 6: drop the "zero tile_cols is rejected" KUnit case (no longer the
   core's behaviour) and add a benign case asserting the zero-initialised
   AV1 frame still validates, plus a tile_rows upper-bound case.
 - No changes to patches 2-5.

Michael Bommarito (6):
  media: v4l2-ctrls: validate HEVC and AV1 tile counts
  media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
  media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer
    capacity
  media: verisilicon: rockchip: bound VPU981 AV1 tile loop and guard
    divisor
  media: mediatek: vcodec: bound AV1 tile-start copy to the array
    capacity
  media: v4l2-ctrls: add KUnit tests for compound control tile
    validation

 .../vcodec/decoder/vdec/vdec_av1_req_lat_if.c |   5 +-
 .../rockchip/rkvdec/rkvdec-hevc-common.c      |  22 ++-
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   8 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |   2 +
 .../platform/verisilicon/hantro_g2_hevc_dec.c |   6 +
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  |  29 ++--
 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 130 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |  27 ++++
 9 files changed, 224 insertions(+), 17 deletions(-)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c


base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:03 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:03 -0400
Subject: [PATCH v2 1/6] media: v4l2-ctrls: validate HEVC and AV1 tile counts
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-2-michael.bommarito@gmail.com>

The stateless HEVC and AV1 controls carry tile counts that several SoC
decoder drivers consume as loop bounds when laying out fixed-size hardware
descriptor buffers, but std_validate_compound() does not bound them.

For V4L2_CTRL_TYPE_HEVC_PPS with tiling enabled, num_tile_columns_minus1
and num_tile_rows_minus1 (u8) drive loops over column_width_minus1[20] and
row_height_minus1[22]. For V4L2_CTRL_TYPE_AV1_FRAME, tile_info.tile_cols
and tile_rows (u8) bound loops over the mi_*_starts[] / *_in_sbs_minus_1[]
arrays. Reject counts beyond the uAPI array capacity with -EINVAL.

These are active-count fields (loop bounds), so bounding the upper limit
here mirrors the existing num_active_dpb_entries check. Only the upper
bound is enforced; a zero tile count is left to the consuming driver, so
the zero-initialised AV1 frame control that existing userspace submits is
not rejected, and the AV1 divisor (context_update_tile_id / tile_cols) is
guarded where it is used in the rockchip decoder (patch 4).

Driver-interpreted index values (HEVC pic_parameter_set_id, AV1
context_update_tile_id) are bounded in the consuming drivers instead
(patches 2 and 4).

Fixes: 256fa3920874 ("media: v4l: Add definitions for HEVC stateless decoding")
Fixes: 9de30f579980 ("media: Add AV1 uAPI")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6b375720e395c..58e2eb7002a19 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -790,10 +790,25 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
 	return 0;
 }
 
+static int validate_av1_tile_info(struct v4l2_av1_tile_info *t)
+{
+	/* Loop bounds in the stateless AV1 drivers. */
+	if (t->tile_cols > V4L2_AV1_MAX_TILE_COLS)
+		return -EINVAL;
+
+	if (t->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
 {
 	int ret = 0;
 
+	ret = validate_av1_tile_info(&f->tile_info);
+	if (ret)
+		return ret;
 	ret = validate_av1_quantization(&f->quantization);
 	if (ret)
 		return ret;
@@ -1242,6 +1257,14 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 
 			p_hevc_pps->flags &=
 				~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+		} else {
+			/* Loop bounds in the stateless HEVC drivers. */
+			if (p_hevc_pps->num_tile_columns_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->column_width_minus1))
+				return -EINVAL;
+			if (p_hevc_pps->num_tile_rows_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->row_height_minus1))
+				return -EINVAL;
 		}
 
 		if (p_hevc_pps->flags &
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:04 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:04 -0400
Subject: [PATCH v2 2/6] media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-3-michael.bommarito@gmail.com>

compute_tiles_uniform() / compute_tiles_non_uniform() and assemble_hw_pps()
loop over num_tile_columns_minus1 / num_tile_rows_minus1 to write the
per-tile column_width[] / row_height[] arrays, sized to the PPS uAPI arrays
column_width_minus1[20] / row_height_minus1[22]; bound the loops to that
capacity. assemble_hw_pps() also indexes the fixed param_set[] table by
pic_parameter_set_id, a driver-interpreted index the core does not reject;
bound it to the table size before the access.

Fixes: 3595375c2301 ("media: rkvdec: Add HEVC backend")
Fixes: c9a59dc2acc7 ("media: rkvdec: Add HEVC support for the VDPU381 variant")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 22 +++++++++++++++----
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |  8 +++++--
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |  2 ++
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 3119f3bc9f98b..d0f26f736a763 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -37,15 +37,22 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
 			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols, num_rows;
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+	/* Bound the loops to the column_width[]/row_height[] capacity. */
+	num_cols = min_t(unsigned int, pps->num_tile_columns_minus1 + 1,
+			 ARRAY_SIZE(pps->column_width_minus1));
+	num_rows = min_t(unsigned int, pps->num_tile_rows_minus1 + 1,
+			 ARRAY_SIZE(pps->row_height_minus1));
+
+	for (i = 0; i < num_cols; 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++)
+	for (i = 0; i < num_rows; i++)
 		row_height[i] = ((i + 1) * pic_in_cts_height) /
 				(pps->num_tile_rows_minus1 + 1) -
 				(i * pic_in_cts_height) /
@@ -57,17 +64,24 @@ 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)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols, num_rows;
 	s32 sum = 0;
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+	/* Leave one slot for the trailing last-tile entry written below. */
+	num_cols = min_t(unsigned int, pps->num_tile_columns_minus1,
+			 ARRAY_SIZE(pps->column_width_minus1) - 1);
+	num_rows = min_t(unsigned int, pps->num_tile_rows_minus1,
+			 ARRAY_SIZE(pps->row_height_minus1) - 1);
+
+	for (i = 0; i < num_cols; 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++) {
+	for (i = 0; i < num_rows; i++) {
 		row_height[i] = pps->row_height_minus1[i] + 1;
 		sum += row_height[i];
 	}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index ac8b825d080a2..29b5adb509727 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -156,6 +156,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
@@ -274,9 +276,11 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
 		/* Userspace also provide column width and row height for uniform spacing */
-		for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+		for (i = 0; i <= pps->num_tile_columns_minus1 &&
+		     i < ARRAY_SIZE(pps->column_width_minus1); i++)
 			WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i));
-		for (i = 0; i <= pps->num_tile_rows_minus1; i++)
+		for (i = 0; i <= pps->num_tile_rows_minus1 &&
+		     i < ARRAY_SIZE(pps->row_height_minus1); i++)
 			WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i));
 	} else {
 		WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index fe6414a175510..6dafa1dd28507 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:05 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:05 -0400
Subject: [PATCH v2 3/6] media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer capacity
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-4-michael.bommarito@gmail.com>

prepare_tile_info_buffer() writes one entry per tile into the tile_sizes
DMA buffer, sized for a grid equal to the PPS uAPI array capacity. Bound
the loop to that capacity so the writes stay inside the buffer.

Fixes: cb5dd5a0fa51 ("media: hantro: Introduce G2/HEVC decoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
index e8c2e83379def..94fbd79885aa5 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
@@ -22,6 +22,12 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
 	bool tiles_enabled, uniform_spacing;
 	u32 no_chroma = 0;
 
+	/* Bound the loops to the tile_sizes buffer capacity. */
+	num_tile_cols = min_t(unsigned int, num_tile_cols,
+			      ARRAY_SIZE(pps->column_width_minus1));
+	num_tile_rows = min_t(unsigned int, num_tile_rows,
+			      ARRAY_SIZE(pps->row_height_minus1));
+
 	tiles_enabled = !!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED);
 	uniform_spacing = !!(pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING);
 
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:06 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:06 -0400
Subject: [PATCH v2 4/6] media: verisilicon: rockchip: bound VPU981 AV1 tile loop and guard divisor
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-5-michael.bommarito@gmail.com>

rockchip_vpu981_av1_dec_set_tile_info() divides context_update_tile_id by
tile_info->tile_cols and writes one descriptor per tile into the tile_info
DMA buffer, sized for AV1_MAX_TILES. tile_cols / tile_rows come straight
from the bitstream; reject a zero column or row count and bound the grid to
AV1_MAX_TILES so the division is safe and the writes stay in the buffer.

Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 29 +++++++++++++------
 1 file changed, 20 insertions(+), 9 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 e4e21ad373233..71d2ef72c4402 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -578,21 +578,32 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
 	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
 	const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
 	    ctrls->tile_group_entry;
-	int context_update_y =
-	    tile_info->context_update_tile_id / tile_info->tile_cols;
-	int context_update_x =
-	    tile_info->context_update_tile_id % tile_info->tile_cols;
-	int context_update_tile_id =
-	    context_update_x * tile_info->tile_rows + context_update_y;
+	unsigned int tile_cols, tile_rows;
+	int context_update_y, context_update_x, context_update_tile_id;
 	u8 *dst = av1_dec->tile_info.cpu;
 	struct hantro_dev *vpu = ctx->dev;
 	int tile0, tile1;
 
+	/* Guard the divisor and bound the grid to the tile_info buffer. */
+	tile_cols = tile_info->tile_cols;
+	tile_rows = tile_info->tile_rows;
+	if (!tile_cols || !tile_rows)
+		return;
+	if (tile_cols * tile_rows > AV1_MAX_TILES) {
+		tile_cols = min_t(unsigned int, tile_cols, AV1_MAX_TILES);
+		tile_rows = min_t(unsigned int, tile_rows,
+				  AV1_MAX_TILES / tile_cols);
+	}
+
+	context_update_y = tile_info->context_update_tile_id / tile_cols;
+	context_update_x = tile_info->context_update_tile_id % tile_cols;
+	context_update_tile_id = context_update_x * tile_rows + context_update_y;
+
 	memset(dst, 0, av1_dec->tile_info.size);
 
-	for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
-		for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
-			int tile_id = tile1 * tile_info->tile_cols + tile0;
+	for (tile0 = 0; tile0 < tile_cols; tile0++) {
+		for (tile1 = 0; tile1 < tile_rows; tile1++) {
+			int tile_id = tile1 * tile_cols + tile0;
 			u32 start, end;
 			u32 y0 =
 			    tile_info->height_in_sbs_minus_1[tile1] + 1;
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:07 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:07 -0400
Subject: [PATCH v2 5/6] media: mediatek: vcodec: bound AV1 tile-start copy to the array capacity
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-6-michael.bommarito@gmail.com>

vdec_av1_slice_setup_tile() copies tile_cols + 1 / tile_rows + 1 start
positions into mi_col_starts[] / mi_row_starts[], which hold
V4L2_AV1_MAX_TILE_COLS + 1 / V4L2_AV1_MAX_TILE_ROWS + 1 entries. tile_cols
and tile_rows come straight from the bitstream; bound the copy to the array
capacity so the accesses stay in range.

Fixes: 0934d3759615 ("media: mediatek: vcodec: separate decoder and encoder")
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 .../mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c       | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 2d622e85f8271..49d9b4a72387e 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame,
 	tile->uniform_tile_spacing_flag =
 		BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING);
 
-	for (i = 0; i < tile->tile_cols + 1; i++)
+	/* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */
+	for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++)
 		tile->mi_col_starts[i] =
 			ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 
-	for (i = 0; i < tile->tile_rows + 1; i++)
+	for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++)
 		tile->mi_row_starts[i] =
 			ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 }
-- 
2.53.0



From michael.bommarito at gmail.com  Sun Jun 14 08:56:08 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Sun, 14 Jun 2026 11:56:08 -0400
Subject: [PATCH v2 6/6] media: v4l2-ctrls: add KUnit tests for compound control tile validation
In-Reply-To: <20260614155609.3107600-1-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
Message-ID: <20260614155609.3107600-7-michael.bommarito@gmail.com>

Drive std_validate_compound() with crafted HEVC PPS and AV1 frame controls
and assert that out-of-range tile counts are rejected with -EINVAL while
in-range values pass, including the zero-initialised AV1 frame default that
userspace and v4l2-compliance submit. The tests are #included at the end of
v4l2-ctrls-core.c to reach the static helper, gated by
CONFIG_V4L2_CTRLS_KUNIT_TEST.

Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
Assisted-by: Claude:claude-opus-4-8
---
 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 130 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |   4 +
 3 files changed, 146 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index d50ccac9733cc..04b15d860a0af 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -3,6 +3,18 @@
 # Generic video config states
 #
 
+config V4L2_CTRLS_KUNIT_TEST
+	bool "KUnit tests for V4L2 compound control validation" if !KUNIT_ALL_TESTS
+	depends on VIDEO_DEV && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  This builds KUnit tests for the stateless-codec compound control
+	  validation in std_validate_compound(). They check that out-of-range
+	  HEVC/AV1 tile counts and parameter-set / tile indices are rejected
+	  before driver code consumes them as array indices or loop bounds.
+
+	  If unsure, say N.
+
 config VIDEO_V4L2_I2C
 	bool
 	depends on I2C && VIDEO_DEV
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core-test.c b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
new file mode 100644
index 0000000000000..813872694eb46
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for HEVC/AV1 tile-count validation in std_validate_compound().
+ * #included at the end of v4l2-ctrls-core.c to reach the static helper.
+ */
+
+#include <kunit/test.h>
+
+static int call_validate_compound(enum v4l2_ctrl_type type, void *payload,
+				  u32 elem_size)
+{
+	struct v4l2_ctrl ctrl = {
+		.type = type,
+		.elem_size = elem_size,
+	};
+	union v4l2_ctrl_ptr ptr = { .p = payload };
+
+	return std_validate_compound(&ctrl, 0, ptr);
+}
+
+/* HEVC PPS: num_tile_columns_minus1 / num_tile_rows_minus1 bounds. */
+static void v4l2_ctrls_hevc_pps_tile_cols(struct kunit *test)
+{
+	struct v4l2_ctrl_hevc_pps *pps;
+
+	pps = kunit_kzalloc(test, sizeof(*pps), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, pps);
+
+	pps->flags = V4L2_HEVC_PPS_FLAG_TILES_ENABLED;
+
+	/* In range: count == array capacity (minus1 == capacity - 1). */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1) - 1;
+	pps->num_tile_rows_minus1 = ARRAY_SIZE(pps->row_height_minus1) - 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			0);
+
+	/* Out of range: one past the column array. */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1);
+	pps->num_tile_rows_minus1 = 0;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	pps->num_tile_columns_minus1 = 0xff;
+	pps->num_tile_rows_minus1 = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+}
+
+/* AV1 frame: tile_cols / tile_rows upper bounds. */
+static void v4l2_ctrls_av1_frame_tile(struct kunit *test)
+{
+	struct v4l2_ctrl_av1_frame *f;
+
+	f = kunit_kzalloc(test, sizeof(*f), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, f);
+
+	/*
+	 * Benign control: a zero-initialised frame (tile_cols == 0) must
+	 * still pass. Userspace and v4l2-compliance set the zeroed default,
+	 * and the divisor that a zero tile_cols would feed is guarded in the
+	 * consuming driver rather than rejected here.
+	 */
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* In range: a 1x1 tiling. */
+	f->tile_info.tile_cols = 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* In range: maximal legal tile_cols / tile_rows. */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* Out of range: tile_cols past the array. */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS + 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	f->tile_info.tile_cols = 0xff;
+	f->tile_info.tile_rows = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: tile_rows past the array. */
+	f->tile_info.tile_cols = 1;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS + 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+}
+
+static struct kunit_case v4l2_ctrls_test_cases[] = {
+	KUNIT_CASE(v4l2_ctrls_hevc_pps_tile_cols),
+	KUNIT_CASE(v4l2_ctrls_av1_frame_tile),
+	{}
+};
+
+static struct kunit_suite v4l2_ctrls_test_suite = {
+	.name = "v4l2-ctrls-compound",
+	.test_cases = v4l2_ctrls_test_cases,
+};
+
+kunit_test_suite(v4l2_ctrls_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for V4L2 stateless-codec compound control validation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 58e2eb7002a19..5e86b6373a136 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -2851,3 +2851,7 @@ int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
 	return hdl->error;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
+
+#if IS_ENABLED(CONFIG_V4L2_CTRLS_KUNIT_TEST)
+#include "v4l2-ctrls-core-test.c"
+#endif
-- 
2.53.0



From jic23 at kernel.org  Sun Jun 14 09:18:47 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 14 Jun 2026 17:18:47 +0100
Subject: [PATCH V12 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260611202607.85376-4-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
	<20260611202607.85376-4-macroalpha82@gmail.com>
Message-ID: <20260614171847.3c412ca3@jic23-huawei>

On Thu, 11 Jun 2026 15:26:00 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add the core component of a new inv_icm42607 driver. This includes
> a few setup functions and the full register definition in the
> header file, as well as the bits necessary to compile and probe the
> device when used on an i2c bus.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Hi Chris,

Given this is nearly ready to merge I took a look at Sashiko and
seems it has found a few more things.

Other than those, looks good to me.

Jonathan

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> new file mode 100644
> index 000000000000..c85d3b74166f
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h

> +#define INV_ICM42607_REG_INTF_CONFIG0			0x35
> +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
> +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
> +#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
> +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
> +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	\
> +	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
Define this as simply 2.

> +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	\
> +	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
and 3
not the FIELD_PREPified version

Sashiko correctly called out that it is field_prepped again at
the callsite.  As the mask includes lowest bit this is will 'work'
but definitely isn't what you intended!


> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> new file mode 100644
> index 000000000000..5d40f1ee53d6
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c

> +static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
> +	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
> +	case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
> +	case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
Sashiko pointed out that the WOM_ registers, 4b to 4d are in the defines, but
not readable or writeable which seems like an omission.

So far only matters for debug, but perhaps better to add them from the start.

> +	case INV_ICM42607_REG_WHOAMI:
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
> +	case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
> +	case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
> +		return true;
> +	}
> +
> +	return false;
> +}


From jic23 at kernel.org  Sun Jun 14 09:34:53 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 14 Jun 2026 17:34:53 +0100
Subject: [PATCH V12 6/9] iio: imu: inv_icm42607: Add Temp Support in
 icm42607
In-Reply-To: <20260611202607.85376-7-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
	<20260611202607.85376-7-macroalpha82@gmail.com>
Message-ID: <20260614173453.0db01d3f@jic23-huawei>

On Thu, 11 Jun 2026 15:26:03 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add functions for reading temperature sensor data.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
The buffer isn't safe for use for DMA.  See below.
I'm not sure I'd have noticed. This used to be a common bug but not seen it that
often recently for some reason!

Jonathan

  
> ---
>  drivers/iio/imu/inv_icm42607/Makefile         |  1 +
>  drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  5 ++
>  .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 18 +++++
>  .../iio/imu/inv_icm42607/inv_icm42607_temp.c  | 76 +++++++++++++++++++
>  .../iio/imu/inv_icm42607/inv_icm42607_temp.h  | 37 +++++++++
>  5 files changed, 137 insertions(+)
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
> 
> diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
> index be109102e203..c04953ed42ce 100644
> --- a/drivers/iio/imu/inv_icm42607/Makefile
> +++ b/drivers/iio/imu/inv_icm42607/Makefile
> @@ -2,6 +2,7 @@
>  
>  obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
>  inv-icm42607-y += inv_icm42607_core.o
> +inv-icm42607-y += inv_icm42607_temp.o
>  
>  obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
>  inv-icm42607-i2c-y += inv_icm42607_i2c.o
> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> index 28edc12d5373..53dd23509a53 100644
> --- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> @@ -114,6 +114,7 @@ struct inv_icm42607_suspended {
>  
>  /**
>   *  struct inv_icm42607_state - driver state variables
> + *  @buffer:		data transfer buffer aligned for DMA.
>   *  @hw:		Hardware specific data.
>   *  @map:		regmap pointer.
>   *  @vddio_supply:	I/O voltage regulator for the chip.
> @@ -124,6 +125,7 @@ struct inv_icm42607_suspended {
>   *  @orientation:	sensor chip orientation relative to main hardware.
>   */
>  struct inv_icm42607_state {
> +	__be16 buffer[3] __aligned(IIO_DMA_MINALIGN);

Look in more depth at what this does.   Key thing is there is a reason
this should always be at the end of the iio_priv() structure.

(Sashiko caught this btw)

>  	const struct inv_icm42607_hw *hw;
>  	struct regmap *map;
>  	struct regulator *vddio_supply;
> @@ -363,6 +365,9 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
>  extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
>  extern const struct dev_pm_ops inv_icm42607_pm_ops;
>  




From jic23 at kernel.org  Sun Jun 14 09:43:17 2026
From: jic23 at kernel.org (Jonathan Cameron)
Date: Sun, 14 Jun 2026 17:43:17 +0100
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <20260611202607.85376-8-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
	<20260611202607.85376-8-macroalpha82@gmail.com>
Message-ID: <20260614174317.2a47f191@jic23-huawei>

On Thu, 11 Jun 2026 15:26:04 -0500
Chris Morgan <macroalpha82 at gmail.com> wrote:

> From: Chris Morgan <macromorgan at hotmail.com>
> 
> Add icm42607 accelerometer sensor for icm42607.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Really trivial stuff that I'd not have mentioned if you weren't
doing a v13 for other reasons.

> ---
>  drivers/iio/imu/inv_icm42607/Makefile         |   1 +
>  drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  34 ++
>  .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 376 ++++++++++++++++++
>  .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  61 +++
>  4 files changed, 472 insertions(+)
>  create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

> diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
> new file mode 100644
> index 000000000000..5e260ddad641
> --- /dev/null
> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
> @@ -0,0 +1,376 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2026 InvenSense, Inc.
> + */
> +
> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +
> +#include "inv_icm42607.h"
> +#include "inv_icm42607_temp.h"
> +
> +#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)		\
> +{									\
> +	.type = IIO_ACCEL,						\
> +	.modified = 1,							\
> +	.channel2 = _modifier,						\
> +	.info_mask_separate =						\
> +		BIT(IIO_CHAN_INFO_RAW),					\
> +	.info_mask_shared_by_type =					\
> +		BIT(IIO_CHAN_INFO_SCALE),				\
> +	.info_mask_shared_by_type_available =				\
> +		BIT(IIO_CHAN_INFO_SCALE),				\
> +	.info_mask_shared_by_all =					\
> +		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
> +	.info_mask_shared_by_all_available =				\
> +		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
Maybe for these, just go a bit long on line length (so 81 chars).
I don't really care either way!

> +	.scan_index = _index,						\
> +	.scan_type = {							\
> +		.sign = 's',						\
> +		.realbits = 16,						\
> +		.storagebits = 16,					\
> +		.endianness = IIO_BE,					\
> +	},								\
> +	.ext_info = _ext_info,						\
> +}


> +
> +static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
> +					int val, int val2)
> +{
> +	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	struct device *dev = regmap_get_device(st->map);
> +	unsigned int idx;
> +	int ret;
> +
> +	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
> +		if (val == inv_icm42607_accel_odr[idx][0] &&
> +		    val2 == inv_icm42607_accel_odr[idx][1])
> +			break;
> +	}
> +	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
> +		return -EINVAL;
> +
> +	conf.odr = idx;
> +
> +	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> +	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&st->lock);
> +
> +	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
> +	if (ret)
> +		return ret;

return inv_icm....

> +
> +	return 0;
> +}


From birenpandya at gmail.com  Sun Jun 14 09:55:53 2026
From: birenpandya at gmail.com (Biren Pandya)
Date: Sun, 14 Jun 2026 22:25:53 +0530
Subject: [PATCH 16/22] media: platform: hantro_drv: Add missing media_entity_cleanup()
In-Reply-To: <20260614165630.3896-1-birenpandya@gmail.com>
References: <20260614165630.3896-1-birenpandya@gmail.com>
Message-ID: <20260614165630.3896-17-birenpandya@gmail.com>

Signed-off-by: Biren Pandya <birenpandya at gmail.com>
---
 drivers/media/platform/verisilicon/hantro_drv.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 2e81877f640f..ad71c0402ef3 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -771,8 +771,10 @@ static int hantro_register_entity(struct media_device *mdev,
 		return ret;
 
 	ret = media_device_register_entity(mdev, entity);
-	if (ret)
+	if (ret) {
+		media_entity_cleanup(entity);
 		return ret;
+	}
 
 	return 0;
 }
@@ -860,12 +862,13 @@ static int hantro_attach_func(struct hantro_dev *vpu,
 
 err_rel_entity2:
 	media_device_unregister_entity(&func->sink);
-
+	media_entity_cleanup(&func->sink);
 err_rel_entity1:
 	media_device_unregister_entity(&func->proc);
-
+	media_entity_cleanup(&func->proc);
 err_rel_entity0:
 	media_device_unregister_entity(&func->vdev.entity);
+	media_entity_cleanup(&func->vdev.entity);
 	return ret;
 }
 
@@ -878,6 +881,9 @@ static void hantro_detach_func(struct hantro_func *func)
 	media_device_unregister_entity(&func->sink);
 	media_device_unregister_entity(&func->proc);
 	media_device_unregister_entity(&func->vdev.entity);
+	media_entity_cleanup(&func->sink);
+	media_entity_cleanup(&func->proc);
+	media_entity_cleanup(&func->vdev.entity);
 }
 
 static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid)
-- 
2.50.1 (Apple Git-155)



From macromorgan at hotmail.com  Sun Jun 14 19:12:56 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Sun, 14 Jun 2026 21:12:56 -0500
Subject: [PATCH V12 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260614171847.3c412ca3@jic23-huawei>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-4-macroalpha82@gmail.com>
 <20260614171847.3c412ca3@jic23-huawei>
Message-ID: <PH0PR19MB9973389B1648F13113B00B3E3EA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>

On Sun, Jun 14, 2026 at 05:18:47PM +0100, Jonathan Cameron wrote:
> On Thu, 11 Jun 2026 15:26:00 -0500
> Chris Morgan <macroalpha82 at gmail.com> wrote:
> 
> > From: Chris Morgan <macromorgan at hotmail.com>
> > 
> > Add the core component of a new inv_icm42607 driver. This includes
> > a few setup functions and the full register definition in the
> > header file, as well as the bits necessary to compile and probe the
> > device when used on an i2c bus.
> > 
> > Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> Hi Chris,
> 
> Given this is nearly ready to merge I took a look at Sashiko and
> seems it has found a few more things.
> 
> Other than those, looks good to me.
> 
> Jonathan

Thanks. I'm going to resubmit again probably tomorrow (even though
it's merge window, again unless you don't want it).

I've removed the buffer from the main st struct, since it's really
no longer needed given the lack of buffer support. Additionally
I've removed the registers completely that sashiko was complaining
about, since it only applies to the 42607c and isn't used by this
driver right now anyway (only needed for APEX/WoM). I also altered
the power management logic a bit to prevent it from delaying on
shutdown, except for when the gyro changes state which the datasheet
says is needed. If Sashiko continues to complain about power management
for the temp sensor that can be ignored, as I've confirmed so long as
both the gyro and accel are off the whole chip is "off". Along with
making a change from 42607x to just 42607 in a few places those are
the only major changes.

Chris

> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> > new file mode 100644
> > index 000000000000..c85d3b74166f
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
> 
> > +#define INV_ICM42607_REG_INTF_CONFIG0			0x35
> > +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
> > +#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
> > +#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
> > +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
> > +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	\
> > +	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
> Define this as simply 2.
> 
> > +#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	\
> > +	FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
> and 3
> not the FIELD_PREPified version
> 
> Sashiko correctly called out that it is field_prepped again at
> the callsite.  As the mask includes lowest bit this is will 'work'
> but definitely isn't what you intended!
> 
> 
> > diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> > new file mode 100644
> > index 000000000000..5d40f1ee53d6
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
> 
> > +static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
> > +{
> > +	switch (reg) {
> > +	case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
> > +	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
> > +	case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
> > +	case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
> Sashiko pointed out that the WOM_ registers, 4b to 4d are in the defines, but
> not readable or writeable which seems like an omission.
> 
> So far only matters for debug, but perhaps better to add them from the start.
> 
> > +	case INV_ICM42607_REG_WHOAMI:
> > +		return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
> > +{
> > +	switch (reg) {
> > +	case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
> > +	case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
> > +	case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
> > +		return true;
> > +	}
> > +
> > +	return false;
> > +}


From neil.armstrong at linaro.org  Mon Jun 15 01:18:58 2026
From: neil.armstrong at linaro.org (neil.armstrong at linaro.org)
Date: Mon, 15 Jun 2026 10:18:58 +0200
Subject: [PATCH V7 4/6] drm/panel: anbernic-td4310: Add RG Vita Pro panel
In-Reply-To: <20260610144407.438846-5-macroalpha82@gmail.com>
References: <20260610144407.438846-1-macroalpha82@gmail.com>
 <20260610144407.438846-5-macroalpha82@gmail.com>
Message-ID: <8c0c992e-5e41-4a2c-bf4b-0b6755b9659a@linaro.org>

On 6/10/26 16:44, Chris Morgan wrote:
> From: Chris Morgan <macromorgan at hotmail.com>
> 
> The panel used by Anbernic in the RG Vita-Pro is a DSI panel based
> on the TD4310 controller IC. It measures approximately 5.5 inches
> diagonally and is 1080x1920 in resolution.
> 
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> ---
>   drivers/gpu/drm/panel/Kconfig                 |  10 +
>   drivers/gpu/drm/panel/Makefile                |   1 +
>   drivers/gpu/drm/panel/panel-anbernic-td4310.c | 257 ++++++++++++++++++
>   3 files changed, 268 insertions(+)
>   create mode 100644 drivers/gpu/drm/panel/panel-anbernic-td4310.c
> 
> diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
> index d592f4f4b939..61dd00297ecc 100644
> --- a/drivers/gpu/drm/panel/Kconfig
> +++ b/drivers/gpu/drm/panel/Kconfig
> @@ -17,6 +17,16 @@ config DRM_PANEL_ABT_Y030XX067A
>   	  Y030XX067A 320x480 3.0" panel as found in the YLM RG-280M, RG-300
>   	  and RG-99 handheld gaming consoles.
>   
> +config DRM_PANEL_ANBERNIC_TD4310
> +	tristate "Anbernic TD4310 LCD panel"
> +	depends on GPIOLIB && OF
> +	depends on DRM_MIPI_DSI
> +	depends on BACKLIGHT_CLASS_DEVICE
> +	help
> +	  Say Y here to enable support for Anbernic designed panels with the
> +	  TD4310 panel controller such as the ones used on the Anbernic RG
> +	  Vita Pro.
> +
>   config DRM_PANEL_ARM_VERSATILE
>   	tristate "ARM Versatile panel driver"
>   	depends on OF
> diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
> index a4291dc3905b..9d8f70c9de3e 100644
> --- a/drivers/gpu/drm/panel/Makefile
> +++ b/drivers/gpu/drm/panel/Makefile
> @@ -1,5 +1,6 @@
>   # SPDX-License-Identifier: GPL-2.0
>   obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o
> +obj-$(CONFIG_DRM_PANEL_ANBERNIC_TD4310) += panel-anbernic-td4310.o
>   obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o
>   obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o
>   obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
> diff --git a/drivers/gpu/drm/panel/panel-anbernic-td4310.c b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
> new file mode 100644
> index 000000000000..9a1b4525423c
> --- /dev/null
> +++ b/drivers/gpu/drm/panel/panel-anbernic-td4310.c
> @@ -0,0 +1,257 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for Anbernic panels with TD4310 panel controller.
> + *
> + * Copyright (C) 2026 Chris Morgan <macromorgan at hotmail.com>
> + *
> + */
> +
> +#include <linux/gpio/consumer.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_probe_helper.h>
> +
> +#include <video/mipi_display.h>
> +
> +struct anbernic_panel_td4310_info {
> +	const struct drm_display_mode *display_mode;
> +	u16 width_mm;
> +	u16 height_mm;
> +	u32 bus_flags;
> +	unsigned long mode_flags;
> +	u32 format;
> +	u32 lanes;
> +	u16 prepare_delay;
> +	u16 reset_delay;
> +	u16 init_delay;
> +	u16 enable_delay;
> +	u16 disable_delay;
> +	u16 unprepare_delay;
> +};
> +
> +struct anbernic_panel_td4310 {
> +	struct device *dev;
> +	struct mipi_dsi_device *dsi;
> +	struct drm_panel panel;
> +	const struct anbernic_panel_td4310_info *panel_info;
> +	struct gpio_desc *reset_gpio;
> +	struct gpio_desc *enable_gpio;
> +	struct regulator *vdd;
> +	enum drm_panel_orientation orientation;
> +};
> +
> +static inline struct anbernic_panel_td4310 *panel_to_anbernic_panel_td4310(struct drm_panel *panel)
> +{
> +	return container_of(panel, struct anbernic_panel_td4310, panel);
> +}
> +
> +static int panel_anbernic_td4310_prepare(struct drm_panel *panel)
> +{
> +	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
> +	struct mipi_dsi_device *dsi = ctx->dsi;
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
> +	int ret;
> +
> +	ret = regulator_enable(ctx->vdd);
> +	if (ret)
> +		return ret;
> +
> +	ret = gpiod_set_value_cansleep(ctx->enable_gpio, 1);
> +	if (ret)
> +		goto err_enable;
> +
> +	if (ctx->panel_info->enable_delay)
> +		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->enable_delay);
> +
> +	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +	if (ret)
> +		goto err_reset;
> +
> +	mipi_dsi_msleep(&dsi_ctx, 10);
> +
> +	ret = gpiod_set_value_cansleep(ctx->reset_gpio, 0);
> +	if (ret)
> +		goto err_reset;
> +
> +	if (ctx->panel_info->reset_delay)
> +		mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->reset_delay);
> +
> +	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
> +	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->prepare_delay);
> +
> +	if (dsi_ctx.accum_err) {
> +		ret = dsi_ctx.accum_err;
> +		goto err_reset;
> +	}
> +
> +	return 0;
> +
> +err_reset:
> +	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
> +err_enable:
> +	regulator_disable(ctx->vdd);
> +	return ret;
> +}
> +
> +static int panel_anbernic_td4310_unprepare(struct drm_panel *panel)
> +{
> +	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
> +	struct mipi_dsi_device *dsi = ctx->dsi;
> +	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
> +
> +	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->unprepare_delay);
> +	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
> +	mipi_dsi_msleep(&dsi_ctx, ctx->panel_info->disable_delay);
> +
> +	gpiod_set_value_cansleep(ctx->enable_gpio, 0);
> +
> +	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
> +
> +	regulator_disable(ctx->vdd);
> +
> +	return 0;
> +}
> +
> +static int panel_anbernic_td4310_get_mode(struct drm_panel *panel,
> +				    struct drm_connector *connector)
> +{
> +	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
> +	const struct anbernic_panel_td4310_info *panel_info = ctx->panel_info;
> +
> +	connector->display_info.bpc = 8;
> +	connector->display_info.width_mm = panel_info->width_mm;
> +	connector->display_info.height_mm = panel_info->height_mm;
> +	connector->display_info.bus_flags = panel_info->bus_flags;
> +
> +	return drm_connector_helper_get_modes_fixed(connector, panel_info->display_mode);
> +}
> +
> +static enum drm_panel_orientation panel_anbernic_td4310_get_orientation(struct drm_panel *panel)
> +{
> +	struct anbernic_panel_td4310 *ctx = panel_to_anbernic_panel_td4310(panel);
> +
> +	return ctx->orientation;
> +}
> +
> +static const struct drm_panel_funcs panel_anbernic_td4310_funcs = {
> +	.prepare = panel_anbernic_td4310_prepare,
> +	.unprepare = panel_anbernic_td4310_unprepare,
> +	.get_modes = panel_anbernic_td4310_get_mode,
> +	.get_orientation = panel_anbernic_td4310_get_orientation,
> +};
> +
> +static int panel_anbernic_td4310_probe(struct mipi_dsi_device *dsi)
> +{
> +	struct device *dev = &dsi->dev;
> +	struct anbernic_panel_td4310 *ctx;
> +	int ret;
> +
> +	ctx = devm_drm_panel_alloc(dev, struct anbernic_panel_td4310, panel,
> +				   &panel_anbernic_td4310_funcs,
> +				   DRM_MODE_CONNECTOR_DSI);
> +	if (IS_ERR(ctx))
> +		return PTR_ERR(ctx);
> +
> +	ctx->dev = dev;
> +
> +	ctx->panel_info = of_device_get_match_data(dev);
> +	if (!ctx->panel_info)
> +		return -EINVAL;
> +
> +	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to get panel orientation\n");
> +
> +	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> +	if (IS_ERR(ctx->reset_gpio))
> +		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
> +				     "Cannot get reset gpio\n");
> +
> +	ctx->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
> +	if (IS_ERR(ctx->enable_gpio))
> +		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio),
> +				     "Cannot get enable gpio\n");
> +
> +	ctx->vdd = devm_regulator_get(dev, "vdd");
> +	if (IS_ERR(ctx->vdd))
> +		return dev_err_probe(dev, PTR_ERR(ctx->vdd),
> +				     "Failed to request vdd regulator\n");
> +
> +	ctx->dsi = dsi;
> +	mipi_dsi_set_drvdata(dsi, ctx);
> +
> +	dsi->lanes = ctx->panel_info->lanes;
> +	dsi->format = ctx->panel_info->format;
> +	dsi->mode_flags = ctx->panel_info->mode_flags;
> +
> +	ret = drm_panel_of_backlight(&ctx->panel);
> +	if (ret)
> +		return ret;
> +
> +	devm_drm_panel_add(dev, &ctx->panel);
> +
> +	ret = devm_mipi_dsi_attach(dev, dsi);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
> +
> +	return 0;
> +}
> +
> +static const struct drm_display_mode anbernic_vitapro_mode = {
> +	.clock = 140020,
> +	.hdisplay = 1080,
> +	.hsync_start = 1080 + 50,
> +	.hsync_end = 1080 + 50 + 4,
> +	.htotal = 1080 + 50 + 4 + 50,
> +	.vdisplay = 1920,
> +	.vsync_start = 1920 + 15,
> +	.vsync_end = 1920 + 15 + 4,
> +	.vtotal = 1920 + 15 + 4 + 32,
> +	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
> +};
> +
> +static const struct anbernic_panel_td4310_info anbernic_vitapro_info = {
> +	.display_mode = &anbernic_vitapro_mode,
> +	.width_mm = 69,
> +	.height_mm = 121,
> +	.bus_flags = DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
> +	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> +		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
> +		      MIPI_DSI_CLOCK_NON_CONTINUOUS,
> +	.format = MIPI_DSI_FMT_RGB888,
> +	.lanes = 4,
> +	.prepare_delay = 50,
> +	.reset_delay = 220,
> +	.enable_delay = 120,
> +	.disable_delay = 50,
> +	.unprepare_delay = 20,
> +};
> +
> +static const struct of_device_id panel_anbernic_td4310_of_match[] = {
> +	{
> +		.compatible = "anbernic,panel-vita-pro",
> +		.data = &anbernic_vitapro_info,
> +	},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, panel_anbernic_td4310_of_match);
> +
> +static struct mipi_dsi_driver anbernic_panel_td4310_driver = {
> +	.driver = {
> +		.name = "panel-anbernic-td4310",
> +		.of_match_table = panel_anbernic_td4310_of_match,
> +	},
> +	.probe	= panel_anbernic_td4310_probe,
> +};
> +module_mipi_dsi_driver(anbernic_panel_td4310_driver);
> +
> +MODULE_AUTHOR("Chris Morgan <macromorgan at hotmail.com>");
> +MODULE_DESCRIPTION("DRM driver for Anbernic TD4310 MIPI DSI panels");
> +MODULE_LICENSE("GPL");

Reviewed-by: Neil Armstrong <neil.armstrong at linaro.org>

Thanks,
Neil


From benjamin.gaignard at collabora.com  Mon Jun 15 01:25:53 2026
From: benjamin.gaignard at collabora.com (Benjamin Gaignard)
Date: Mon, 15 Jun 2026 10:25:53 +0200
Subject: [PATCH v2 4/6] media: verisilicon: rockchip: bound VPU981 AV1
 tile loop and guard divisor
In-Reply-To: <20260614155609.3107600-5-michael.bommarito@gmail.com>
References: <20260614155609.3107600-1-michael.bommarito@gmail.com>
 <20260614155609.3107600-5-michael.bommarito@gmail.com>
Message-ID: <cf38fbb9-a17c-4297-a696-2efa199afcbb@collabora.com>


Le 14/06/2026 ? 17:56, Michael Bommarito a ?crit?:
> rockchip_vpu981_av1_dec_set_tile_info() divides context_update_tile_id by
> tile_info->tile_cols and writes one descriptor per tile into the tile_info
> DMA buffer, sized for AV1_MAX_TILES. tile_cols / tile_rows come straight
> from the bitstream; reject a zero column or row count and bound the grid to
> AV1_MAX_TILES so the division is safe and the writes stay in the buffer.
>
> Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
> Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
> Assisted-by: Claude:claude-opus-4-8
> ---
>   .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 29 +++++++++++++------
>   1 file changed, 20 insertions(+), 9 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 e4e21ad373233..71d2ef72c4402 100644
> --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> @@ -578,21 +578,32 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
>   	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
>   	const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
>   	    ctrls->tile_group_entry;
> -	int context_update_y =
> -	    tile_info->context_update_tile_id / tile_info->tile_cols;
> -	int context_update_x =
> -	    tile_info->context_update_tile_id % tile_info->tile_cols;
> -	int context_update_tile_id =
> -	    context_update_x * tile_info->tile_rows + context_update_y;
> +	unsigned int tile_cols, tile_rows;
> +	int context_update_y, context_update_x, context_update_tile_id;
>   	u8 *dst = av1_dec->tile_info.cpu;
>   	struct hantro_dev *vpu = ctx->dev;
>   	int tile0, tile1;
>   
> +	/* Guard the divisor and bound the grid to the tile_info buffer. */
> +	tile_cols = tile_info->tile_cols;
> +	tile_rows = tile_info->tile_rows;
> +	if (!tile_cols || !tile_rows)
> +		return;

NACK
because you completely ignore how these values are used later in this function
to set registers.

> +	if (tile_cols * tile_rows > AV1_MAX_TILES) {
> +		tile_cols = min_t(unsigned int, tile_cols, AV1_MAX_TILES);
> +		tile_rows = min_t(unsigned int, tile_rows,
> +				  AV1_MAX_TILES / tile_cols);
> +	}
> +

It isn't possible to recompute tile_cols and tile_rows like that.
Please add this check in validate_av1_tile_info().

> +	context_update_y = tile_info->context_update_tile_id / tile_cols;
> +	context_update_x = tile_info->context_update_tile_id % tile_cols;
> +	context_update_tile_id = context_update_x * tile_rows + context_update_y;

To fix the possible division by zero: initialize the variable to zero when declare them
and only do the division if tile_cols isn't zero.

Thanks,
Benjamin

> +
>   	memset(dst, 0, av1_dec->tile_info.size);
>   
> -	for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
> -		for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
> -			int tile_id = tile1 * tile_info->tile_cols + tile0;
> +	for (tile0 = 0; tile0 < tile_cols; tile0++) {
> +		for (tile1 = 0; tile1 < tile_rows; tile1++) {
> +			int tile_id = tile1 * tile_cols + tile0;
>   			u32 start, end;
>   			u32 y0 =
>   			    tile_info->height_in_sbs_minus_1[tile1] + 1;


From andriy.shevchenko at intel.com  Mon Jun 15 03:23:37 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Mon, 15 Jun 2026 13:23:37 +0300
Subject: [PATCH V12 4/9] iio: imu: inv_icm42607: Add SPI For icm42607
In-Reply-To: <20260611202607.85376-5-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-5-macroalpha82@gmail.com>
Message-ID: <ai_SqaTvBYI7wL79@ashevche-desk.local>

On Thu, Jun 11, 2026 at 03:26:01PM -0500, Chris Morgan wrote:

> Add SPI driver support for InvenSense ICM-42607 devices.

...

> +#include <linux/bitfield.h>
> +#include <linux/dev_printk.h>
> +#include <linux/err.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include <linux/spi/spi.h>

...

> +static const struct spi_device_id inv_icm42607_spi_id_table[] = {
> +	{
> +		.name = "icm42607",
> +		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data
> +	}, {
> +		.name = "icm42607p",
> +		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data

I believe I have commented on this already. But anyway, please leave
a trailing comma for .driver_data assignments as well. Same for I?C
driver.

> +	},
> +	{ }
> +};

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Mon Jun 15 03:28:29 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Mon, 15 Jun 2026 13:28:29 +0300
Subject: [PATCH V12 5/9] iio: imu: inv_icm42607: Add PM support for
 icm42607
In-Reply-To: <20260611202607.85376-6-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-6-macroalpha82@gmail.com>
Message-ID: <ai_Tzbl3sZlyrh2M@ashevche-desk.local>

On Thu, Jun 11, 2026 at 03:26:02PM -0500, Chris Morgan wrote:

> Add power management support for the ICM42607 device driver.

...

> +static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
> +				      enum inv_icm42607_sensor_mode gyro,
> +				      enum inv_icm42607_sensor_mode accel,
> +				      bool temp, unsigned int *sleep_ms)
> +{
> +	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
> +	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
> +	bool oldtemp = st->conf.temp_en;
> +	unsigned int sleepval_ms;
> +	unsigned int val;
> +	int ret;
> +
> +	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
> +		return 0;

This validation seems weak, see below why.

> +	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
> +	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
> +	/*
> +	 * Note that temp being enabled here doesn't affect PM since
> +	 * per 10.25 of the datasheet the clock will be off by default
> +	 * if both the gyro and accel modes are off.
> +	 */
> +	if (!temp)
> +		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
> +	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
> +	if (ret)
> +		return ret;
> +
> +	st->conf.gyro.mode = gyro;
> +	st->conf.accel.mode = accel;
> +	st->conf.temp_en = temp;

> +	sleepval_ms = 0;
> +	if (temp && !oldtemp)
> +		sleepval_ms = max(sleepval_ms, INV_ICM42607_TEMP_STARTUP_TIME_MS);
> +
> +	if (accel != oldaccel)
> +		sleepval_ms = max(sleepval_ms, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
> +
> +	if (gyro != oldgyro)
> +		sleepval_ms = max(sleepval_ms, INV_ICM42607_GYRO_STARTUP_TIME_MS);

Does it mean that it might be more than a single conditional to become true?
If so, the last code wins, which is most likely buggy approach. Can you put
a comment, and possible convert this to if-else-if, to clarify what's going
on here?

> +	if (sleep_ms)
> +		*sleep_ms = sleepval_ms;
> +	else if (sleepval_ms)
> +		fsleep(sleepval_ms * USEC_PER_MSEC);
> +
> +	return 0;
> +}

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Mon Jun 15 04:21:05 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Mon, 15 Jun 2026 14:21:05 +0300
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <20260611202607.85376-8-macroalpha82@gmail.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-8-macroalpha82@gmail.com>
Message-ID: <ai_gIR2d9fzHLZ-G@ashevche-desk.local>

On Thu, Jun 11, 2026 at 03:26:04PM -0500, Chris Morgan wrote:

> Add icm42607 accelerometer sensor for icm42607.

...

> +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

Please, please, use IWYU! So many headers are missing...
(Same comment to all files in this series.)

+ array_size.h
+ bits.h // BIT()
+ cleanup.h // guard()()
+ device/devres.h // devm_kasprintf()
+ err.h // -EINVAL, IS_ERR()

> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>

+ types.h // s16, __be16

Also you need to have

asm/byteorder.h // be16_to_cpup()

...

> +static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
> +				       int *val, int *val2)
> +{
> +	unsigned int odr;
> +	unsigned int i;
> +
> +	guard(mutex)(&st->lock);
> +
> +	odr = st->conf.accel.odr;
> +
> +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {

Why pre-increment? Same for all other cases.

> +		if (i == odr)
> +			break;
> +	}
> +	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
> +		return -EINVAL;
> +
> +	*val = inv_icm42607_accel_odr[i][0];
> +	*val2 = inv_icm42607_accel_odr[i][1];
> +
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}

-- 
With Best Regards,
Andy Shevchenko




From damon.ding at rock-chips.com  Mon Jun 15 05:33:03 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Mon, 15 Jun 2026 20:33:03 +0800
Subject: [PATCH v11 0/3] Add eDP support for RK3576
In-Reply-To: <20260605022305.3058853-1-damon.ding@rock-chips.com>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
Message-ID: <cd1f968a-2e1b-434f-a331-a60cd8740032@rock-chips.com>

Hi all,

Gentle ping on this patch series.

Best regards,
Damon

On 6/5/2026 10:23 AM, Damon Ding wrote:
> Picked from:
> https://lore.kernel.org/all/20260601065100.1103873-1-damon.ding at rock-chips.com/
> 
> Patch 1-2 are to add missing clock "hclk" for RK3588 eDP nodes.
> Patch 3 is to add the RK3576 eDP node.
> 
> Damon Ding (3):
>    arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
>    arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
>    arm64: dts: rockchip: Add eDP node for RK3576
> 
>   arch/arm64/boot/dts/rockchip/rk3576.dtsi      | 28 +++++++++++++++++++
>   arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  4 +--
>   .../arm64/boot/dts/rockchip/rk3588-extra.dtsi |  4 +--
>   3 files changed, 32 insertions(+), 4 deletions(-)
> 
> ---
> 
> Changes in v2:
> - Split out separate patches to add the "hclk" clock reference.
> - Split out separate patches to enable the "hclk" clock.
> - Add Reviewed-by tag.
> 
> Changes in v3:
> - Add a patch to expand descriptions for clocks of the eDP node.
> - Add Reviewed-by tag.
> 
> Changes in v4:
> - Modify commit msg.
> 
> Changes in v5:
> - Enforce the correct third clock name on a per-compatible basis.
> - Modify the commit msg simultaneously.
> - Add Acked-by tag.
> 
> Changes in v6:
> - Expand more detail commit msg about using hclk instead of grf clock.
> 
> Changes in v7:
> - List all valid clock names at the top level, and constrain the clock
>    count for each platform with minItems/maxItems in allOf.
> 
> Changes in v8:
> - Fix indentation to 10 for enum in clock-names property.
> 
> Changes in v9:
> - Restore the explicit clock-names for RK3399 and RK3588 eDP dt-bindings.
> 
> Changes in v10:
> - Use automatic cleanup to fix OF node reference leak reported by
>    Sashiko.
> 
> Changes in v11:
> - Pick and rebase DT related patches.
> 



From damon.ding at rock-chips.com  Mon Jun 15 05:34:58 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Mon, 15 Jun 2026 20:34:58 +0800
Subject: [PATCH v5 0/4] Add eDP lane mapping support
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
References: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Message-ID: <8da02c6f-030d-4033-935b-a44c777a14d2@rock-chips.com>

Hi all,

Gentle ping on this patch series.

Best regards,
Damon

On 6/4/2026 4:52 PM, Damon Ding wrote:
> This series adds configurable eDP physical lane mapping support via
> device tree data-lanes property.
> 
> Lane mapping is mainly used for below scenarios:
> 1. Correct PCB lane swap and differential line routing crossover
>     without hardware changes;
> 2. Adapt mismatched lane pin definitions between SoC and eDP panel;
> 3. Support multiple panel hardware variants on the same board
>     by configuring data-lanes in device tree only.
> 
> The series includes driver implementation and device tree binding
> updates to support custom lane mapping configuration from endpoint
> node, and keeps default linear lane order if no configuration is given.
> 
> Patch 1: Add endpoint data-lanes property to analogix-dp binding
> Patch 2: Add DRM DP helper API to validate DP lane counts
> Patch 3: Add validation for samsung,lane-count property as preparation
> Patch 4: Implement lane mapping in analogix_dp driver
> 
> Damon Ding (4):
>    dt-bindings: display: bridge: analogix-dp: Add data-lanes support for
>      endpoint
>    drm/dp: Add helper to validate DP lane counts
>    drm/bridge: analogix_dp: Add validation for samsung,lane-count
>      property
>    drm/bridge: analogix_dp: Add support for optional data-lanes mapping
> 
>   .../bindings/display/bridge/analogix,dp.yaml  | 19 ++++--
>   .../rockchip/rockchip,analogix-dp.yaml        |  1 +
>   .../drm/bridge/analogix/analogix_dp_core.c    | 64 ++++++++++++++++++-
>   .../drm/bridge/analogix/analogix_dp_core.h    |  4 +-
>   .../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 ++---
>   .../gpu/drm/bridge/analogix/analogix_dp_reg.h |  4 ++
>   include/drm/display/drm_dp_helper.h           |  6 ++
>   7 files changed, 97 insertions(+), 16 deletions(-)
> 
> ---
> 
> Changes in v2:
> - Add lane mapping application scenarios in commit message.
> - Remove redundant deprecated property 'data-lanes' for eDP node.
> - Update port at 1 $ref to /schemas/graph.yaml#/$defs/port-base.
> 
> Changes in v3:
> - Squash [PATCH v2 2/3] into [PATCH v2 1/3].
> - Add unevaluatedProperties: false to both the port at 1 and endpoint
>    nodes.
> 
> Changes in v4:
> - Add validation for samsung,lane-count property as preparation.
> 
> Changes in v5:
> - Add DRM DP helper API to validate DP lane counts.
> - Apply DRM DP helper API to check the validity of samsung,lane-count
>    property.
> - Add Acked-by and Reviewed-by tags.
> 



From heiko at sntech.de  Mon Jun 15 06:01:38 2026
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Mon, 15 Jun 2026 15:01:38 +0200
Subject: [PATCH v11 0/3] Add eDP support for RK3576
In-Reply-To: <cd1f968a-2e1b-434f-a331-a60cd8740032@rock-chips.com>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
 <cd1f968a-2e1b-434f-a331-a60cd8740032@rock-chips.com>
Message-ID: <3213683.CbtlEUcBR6@diego>

Hi Damon,

Am Montag, 15. Juni 2026, 14:33:03 Mitteleurop?ische Sommerzeit schrieb Damon Ding:
> Gentle ping on this patch series.

Linux 7.1 was released yesterday, so we're in the merge-window now.
(And the 5th of june was shortly before -rc7, so too late for 7.2)

So I'll pick those up after the merge window end in 2 weeks.


Heiko

> 
> Best regards,
> Damon
> 
> On 6/5/2026 10:23 AM, Damon Ding wrote:
> > Picked from:
> > https://lore.kernel.org/all/20260601065100.1103873-1-damon.ding at rock-chips.com/
> > 
> > Patch 1-2 are to add missing clock "hclk" for RK3588 eDP nodes.
> > Patch 3 is to add the RK3576 eDP node.
> > 
> > Damon Ding (3):
> >    arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
> >    arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
> >    arm64: dts: rockchip: Add eDP node for RK3576
> > 
> >   arch/arm64/boot/dts/rockchip/rk3576.dtsi      | 28 +++++++++++++++++++
> >   arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  4 +--
> >   .../arm64/boot/dts/rockchip/rk3588-extra.dtsi |  4 +--
> >   3 files changed, 32 insertions(+), 4 deletions(-)
> > 
> > ---
> > 
> > Changes in v2:
> > - Split out separate patches to add the "hclk" clock reference.
> > - Split out separate patches to enable the "hclk" clock.
> > - Add Reviewed-by tag.
> > 
> > Changes in v3:
> > - Add a patch to expand descriptions for clocks of the eDP node.
> > - Add Reviewed-by tag.
> > 
> > Changes in v4:
> > - Modify commit msg.
> > 
> > Changes in v5:
> > - Enforce the correct third clock name on a per-compatible basis.
> > - Modify the commit msg simultaneously.
> > - Add Acked-by tag.
> > 
> > Changes in v6:
> > - Expand more detail commit msg about using hclk instead of grf clock.
> > 
> > Changes in v7:
> > - List all valid clock names at the top level, and constrain the clock
> >    count for each platform with minItems/maxItems in allOf.
> > 
> > Changes in v8:
> > - Fix indentation to 10 for enum in clock-names property.
> > 
> > Changes in v9:
> > - Restore the explicit clock-names for RK3399 and RK3588 eDP dt-bindings.
> > 
> > Changes in v10:
> > - Use automatic cleanup to fix OF node reference leak reported by
> >    Sashiko.
> > 
> > Changes in v11:
> > - Pick and rebase DT related patches.
> > 
> 
> 






From damon.ding at rock-chips.com  Mon Jun 15 06:32:08 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Mon, 15 Jun 2026 21:32:08 +0800
Subject: [PATCH v11 0/3] Add eDP support for RK3576
In-Reply-To: <3213683.CbtlEUcBR6@diego>
References: <20260605022305.3058853-1-damon.ding@rock-chips.com>
 <cd1f968a-2e1b-434f-a331-a60cd8740032@rock-chips.com>
 <3213683.CbtlEUcBR6@diego>
Message-ID: <a007b499-fbb8-4fcd-b1f2-c1ab3d6a25cb@rock-chips.com>

On 6/15/2026 9:01 PM, Heiko St?bner wrote:
> Hi Damon,
> 
> Am Montag, 15. Juni 2026, 14:33:03 Mitteleurop?ische Sommerzeit schrieb Damon Ding:
>> Gentle ping on this patch series.
> 
> Linux 7.1 was released yesterday, so we're in the merge-window now.
> (And the 5th of june was shortly before -rc7, so too late for 7.2)
> 
> So I'll pick those up after the merge window end in 2 weeks.
> 
> 

Thanks for the heads-up. Got it. ;-)

Best regards,
Damon

>>
>> On 6/5/2026 10:23 AM, Damon Ding wrote:
>>> Picked from:
>>> https://lore.kernel.org/all/20260601065100.1103873-1-damon.ding at rock-chips.com/
>>>
>>> Patch 1-2 are to add missing clock "hclk" for RK3588 eDP nodes.
>>> Patch 3 is to add the RK3576 eDP node.
>>>
>>> Damon Ding (3):
>>>     arm64: dts: rockchip: Add missing hclk for RK3588 eDP0
>>>     arm64: dts: rockchip: Add missing hclk for RK3588 eDP1
>>>     arm64: dts: rockchip: Add eDP node for RK3576
>>>
>>>    arch/arm64/boot/dts/rockchip/rk3576.dtsi      | 28 +++++++++++++++++++
>>>    arch/arm64/boot/dts/rockchip/rk3588-base.dtsi |  4 +--
>>>    .../arm64/boot/dts/rockchip/rk3588-extra.dtsi |  4 +--
>>>    3 files changed, 32 insertions(+), 4 deletions(-)
>>>
>>> ---
>>>
>>> Changes in v2:
>>> - Split out separate patches to add the "hclk" clock reference.
>>> - Split out separate patches to enable the "hclk" clock.
>>> - Add Reviewed-by tag.
>>>
>>> Changes in v3:
>>> - Add a patch to expand descriptions for clocks of the eDP node.
>>> - Add Reviewed-by tag.
>>>
>>> Changes in v4:
>>> - Modify commit msg.
>>>
>>> Changes in v5:
>>> - Enforce the correct third clock name on a per-compatible basis.
>>> - Modify the commit msg simultaneously.
>>> - Add Acked-by tag.
>>>
>>> Changes in v6:
>>> - Expand more detail commit msg about using hclk instead of grf clock.
>>>
>>> Changes in v7:
>>> - List all valid clock names at the top level, and constrain the clock
>>>     count for each platform with minItems/maxItems in allOf.
>>>
>>> Changes in v8:
>>> - Fix indentation to 10 for enum in clock-names property.
>>>
>>> Changes in v9:
>>> - Restore the explicit clock-names for RK3399 and RK3588 eDP dt-bindings.
>>>
>>> Changes in v10:
>>> - Use automatic cleanup to fix OF node reference leak reported by
>>>     Sashiko.
>>>
>>> Changes in v11:
>>> - Pick and rebase DT related patches.
>>>
>>
>>
> 
> 
> 
> 
> 
> 



From macromorgan at hotmail.com  Mon Jun 15 07:49:26 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 09:49:26 -0500
Subject: [PATCH V12 5/9] iio: imu: inv_icm42607: Add PM support for
 icm42607
In-Reply-To: <ai_Tzbl3sZlyrh2M@ashevche-desk.local>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-6-macroalpha82@gmail.com>
 <ai_Tzbl3sZlyrh2M@ashevche-desk.local>
Message-ID: <PH0PR19MB997338D8F4A9372647962B97DFA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>

On Mon, Jun 15, 2026 at 01:28:29PM +0300, Andy Shevchenko wrote:
> On Thu, Jun 11, 2026 at 03:26:02PM -0500, Chris Morgan wrote:
> 
> > Add power management support for the ICM42607 device driver.
> 
> ...
> 
> > +static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
> > +				      enum inv_icm42607_sensor_mode gyro,
> > +				      enum inv_icm42607_sensor_mode accel,
> > +				      bool temp, unsigned int *sleep_ms)
> > +{
> > +	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
> > +	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
> > +	bool oldtemp = st->conf.temp_en;
> > +	unsigned int sleepval_ms;
> > +	unsigned int val;
> > +	int ret;
> > +
> > +	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
> > +		return 0;
> 
> This validation seems weak, see below why.
> 
> > +	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
> > +	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
> > +	/*
> > +	 * Note that temp being enabled here doesn't affect PM since
> > +	 * per 10.25 of the datasheet the clock will be off by default
> > +	 * if both the gyro and accel modes are off.
> > +	 */
> > +	if (!temp)
> > +		val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
> > +	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
> > +	if (ret)
> > +		return ret;
> > +
> > +	st->conf.gyro.mode = gyro;
> > +	st->conf.accel.mode = accel;
> > +	st->conf.temp_en = temp;
> 
> > +	sleepval_ms = 0;
> > +	if (temp && !oldtemp)
> > +		sleepval_ms = max(sleepval_ms, INV_ICM42607_TEMP_STARTUP_TIME_MS);
> > +
> > +	if (accel != oldaccel)
> > +		sleepval_ms = max(sleepval_ms, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
> > +
> > +	if (gyro != oldgyro)
> > +		sleepval_ms = max(sleepval_ms, INV_ICM42607_GYRO_STARTUP_TIME_MS);
> 
> Does it mean that it might be more than a single conditional to become true?
> If so, the last code wins, which is most likely buggy approach. Can you put
> a comment, and possible convert this to if-else-if, to clarify what's going
> on here?

I've changed this logic in the next version, but basically what needs
to be done is ensure if any sensor changes from off to on we wait the
startup delay amount of time for that sensor. If more than one sensor
changes from off to on, we wait the maximum of the two sensors delay.

I'm going to change this instead to just (sensor && !oldsensor) for
each of the three. Note that I also have to insert a shutdown delay
for the gyro to ensure if the state goes from on to off the sensor is
on a minimum of 45ms per the datasheet.

So I do expect it to be possible for more than one condition to be true
here, and when it is I want to select the maximum value for the sleep.
If the sleep_ms is specified however, we will use that value.

> 
> > +	if (sleep_ms)
> > +		*sleep_ms = sleepval_ms;
> > +	else if (sleepval_ms)
> > +		fsleep(sleepval_ms * USEC_PER_MSEC);
> > +
> > +	return 0;
> > +}
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you,
Chris


From macromorgan at hotmail.com  Mon Jun 15 07:51:40 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 09:51:40 -0500
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <ai_gIR2d9fzHLZ-G@ashevche-desk.local>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-8-macroalpha82@gmail.com>
 <ai_gIR2d9fzHLZ-G@ashevche-desk.local>
Message-ID: <PH0PR19MB997338010EC6FA92E0AA63875FA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>

On Mon, Jun 15, 2026 at 02:21:05PM +0300, Andy Shevchenko wrote:
> On Thu, Jun 11, 2026 at 03:26:04PM -0500, Chris Morgan wrote:
> 
> > Add icm42607 accelerometer sensor for icm42607.
> 
> ...
> 
> > +++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
> 
> Please, please, use IWYU! So many headers are missing...
> (Same comment to all files in this series.)
> 
> + array_size.h
> + bits.h // BIT()
> + cleanup.h // guard()()
> + device/devres.h // devm_kasprintf()
> + err.h // -EINVAL, IS_ERR()
> 
> > +#include <linux/iio/iio.h>
> > +#include <linux/mutex.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> 
> + types.h // s16, __be16
> 
> Also you need to have
> 
> asm/byteorder.h // be16_to_cpup()

How are you running IWYU against the builds? So far I've tried but I
can't seem to get it to run properly. 

> 
> ...
> 
> > +static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
> > +				       int *val, int *val2)
> > +{
> > +	unsigned int odr;
> > +	unsigned int i;
> > +
> > +	guard(mutex)(&st->lock);
> > +
> > +	odr = st->conf.accel.odr;
> > +
> > +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
> 
> Why pre-increment? Same for all other cases.

The register starts at 5 and all values below 5 are invalid. Starting
this increment at 5 ensures we don't expose invalid values to
userspace.

> 
> > +		if (i == odr)
> > +			break;
> > +	}
> > +	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
> > +		return -EINVAL;
> > +
> > +	*val = inv_icm42607_accel_odr[i][0];
> > +	*val2 = inv_icm42607_accel_odr[i][1];
> > +
> > +	return IIO_VAL_INT_PLUS_MICRO;
> > +}
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you,
Chris


From andriy.shevchenko at intel.com  Mon Jun 15 08:07:15 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Mon, 15 Jun 2026 18:07:15 +0300
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <PH0PR19MB997338010EC6FA92E0AA63875FA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-8-macroalpha82@gmail.com>
 <ai_gIR2d9fzHLZ-G@ashevche-desk.local>
 <PH0PR19MB997338010EC6FA92E0AA63875FA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <ajAVI0KXkx3FM1ZX@ashevche-desk.local>

On Mon, Jun 15, 2026 at 09:51:40AM -0500, Chris Morgan wrote:
> On Mon, Jun 15, 2026 at 02:21:05PM +0300, Andy Shevchenko wrote:
> > On Thu, Jun 11, 2026 at 03:26:04PM -0500, Chris Morgan wrote:

...

> > Please, please, use IWYU! So many headers are missing...
> > (Same comment to all files in this series.)
> > 
> > + array_size.h
> > + bits.h // BIT()
> > + cleanup.h // guard()()
> > + device/devres.h // devm_kasprintf()
> > + err.h // -EINVAL, IS_ERR()
> > 
> > > +#include <linux/iio/iio.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include <linux/regmap.h>
> > 
> > + types.h // s16, __be16
> > 
> > Also you need to have
> > 
> > asm/byteorder.h // be16_to_cpup()
> 
> How are you running IWYU against the builds? So far I've tried but I
> can't seem to get it to run properly. 

Sorry, I meant "use IWYU principle". I don't run the tool, I just looked into
the code.

...

> > > +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
> > 
> > Why pre-increment? Same for all other cases.
> 
> The register starts at 5 and all values below 5 are invalid. Starting
> this increment at 5 ensures we don't expose invalid values to
> userspace.

It doesn't explain pre-increment. Post-increment should work as is.

> > > +		if (i == odr)
> > > +			break;
> > > +	}

-- 
With Best Regards,
Andy Shevchenko




From macromorgan at hotmail.com  Mon Jun 15 09:40:31 2026
From: macromorgan at hotmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 11:40:31 -0500
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <ajAVI0KXkx3FM1ZX@ashevche-desk.local>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-8-macroalpha82@gmail.com>
 <ai_gIR2d9fzHLZ-G@ashevche-desk.local>
 <PH0PR19MB997338010EC6FA92E0AA63875FA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
 <ajAVI0KXkx3FM1ZX@ashevche-desk.local>
Message-ID: <PH0PR19MB9973380BF26E3EF16BD2D35ED0A5E62@PH0PR19MB997338.namprd19.prod.outlook.com>

On Mon, Jun 15, 2026 at 06:07:15PM +0300, Andy Shevchenko wrote:
> On Mon, Jun 15, 2026 at 09:51:40AM -0500, Chris Morgan wrote:
> > On Mon, Jun 15, 2026 at 02:21:05PM +0300, Andy Shevchenko wrote:
> > > On Thu, Jun 11, 2026 at 03:26:04PM -0500, Chris Morgan wrote:
> 
> ...
> 
> > > Please, please, use IWYU! So many headers are missing...
> > > (Same comment to all files in this series.)
> > > 
> > > + array_size.h
> > > + bits.h // BIT()
> > > + cleanup.h // guard()()
> > > + device/devres.h // devm_kasprintf()
> > > + err.h // -EINVAL, IS_ERR()
> > > 
> > > > +#include <linux/iio/iio.h>
> > > > +#include <linux/mutex.h>
> > > > +#include <linux/pm_runtime.h>
> > > > +#include <linux/regmap.h>
> > > 
> > > + types.h // s16, __be16
> > > 
> > > Also you need to have
> > > 
> > > asm/byteorder.h // be16_to_cpup()
> > 
> > How are you running IWYU against the builds? So far I've tried but I
> > can't seem to get it to run properly. 
> 
> Sorry, I meant "use IWYU principle". I don't run the tool, I just looked into
> the code.

I've done what I can then, I have added these headers where I am using
them. I'm not going to add asm/byteorder.h though because I am dropping
that in the next revision and replacing it with get_unaligned_be16() to
further simplify things. Note that I am adding linux/unaligned.h for
the files where I use that function.

The additional headers will be added in the next revision. If you see
any other obvious ones missing let me know but for now I *think* it's
correct.

> 
> ...
> 
> > > > +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
> > > 
> > > Why pre-increment? Same for all other cases.
> > 
> > The register starts at 5 and all values below 5 are invalid. Starting
> > this increment at 5 ensures we don't expose invalid values to
> > userspace.
> 
> It doesn't explain pre-increment. Post-increment should work as is.

The array this references starts at 5, because those correspond to the
values written to the odr register. That said, I do see a bug because
the odr register is from highest to smallest and this array is
backwards in the accel and gyro code. I'll fix that.

> 
> > > > +		if (i == odr)
> > > > +			break;
> > > > +	}
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 

Thank you,
Chris


From conor at kernel.org  Mon Jun 15 09:49:06 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:49:06 +0100
Subject: [RFC PATCH v4 6/9] dt-bindings: npu: rockchip,rk3588-rknn-core:
 Add RK3568
In-Reply-To: <20260613070116.438906-7-midgy971@gmail.com>
References: <20260613070116.438906-1-midgy971@gmail.com>
 <20260613070116.438906-7-midgy971@gmail.com>
Message-ID: <20260615-drift-dreamlike-0323a8dc5ce9@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-rockchip/attachments/20260615/a40a213b/attachment.sig>

From macroalpha82 at gmail.com  Mon Jun 15 10:25:43 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:43 -0500
Subject: [PATCH V13 0/9] Add Invensense ICM42607
Message-ID: <20260615172554.160910-1-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.

This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.

Changes Since V1:
 - Instead of creating a new driver, merged with the existing inv_icm42600
   driver. This necessitated adding some code to the existing driver to
   permit using a different register layout for the same functionality.
 - Split changes up a bit more to decrease the size of the individual
   patches. Note that patch 0004 is still pretty hefty; if I need to split
   further I may need to create some temporary stub functions.
 - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
   per Jonathan's recommendations.

Changes Since V2:
 - Went back to using a new driver on advice from Invensense engineer.
 - Further split changes up into smaller chunks of functionality. Note
   still that the largest patch is approximately 900 lines, and that while
   the driver compiles cleanly at each commit it is not able to drive the
   hardware until the commit that adds the Interrupt (as it also adds the
   Makefile).
 - Change the error to a warning when the devicetree binding does not match
   the hardware ID.
 - Dropped the ack on the devicetree bindings, as I am creating a new file
   (for a new driver) instead of modifying the existing one.

Changes Since V3:
 - Numerous small fixes (too many to list here). Thank you to everyone who
   provided feedback.
 - Split power management additions into an additional commit to break
   things up further.
 - Consolidated devicetree documentation in existing
   invensense,icm42600.yaml file.
 - Removed most of the FIELD_PREP from header file to c files to make code
   easier to read.
 - Changed scale values to 2D arrays for Gyro and Accelerometer.
 - Removed IIO_CHAN_INFO_CALIBBIAS attribute.

Changes Since V4:
 - Additional numerous small fixes, thank you again for all the feedback.
 - Dropped power control API and instead run device in low noise mode.
 - Split devicetree bindings into two distinct changes.
 - Reordered adding of enums and structs to main header file so that they
   are only brought in when needed.
 - Stopped using enum for driver data and instead am using pointer to
   device specific driver data.

Changes Since V5:
 - Corrected use of "dev_warn_probe" to just "dev_warn".
 - Fixed some return scenarios which would unconditionally return 0
   when an error was present.
 - Corrected use of max() to min() for bounds checking. max() was
   incorrect.
 - Fixed using "st->conf.accel.odr" in the gyroscope function. It
   should have been "st->conf.gyro.odr" which it now is.
 - Additional small fixes suggested by "sashiko.dev".
 - Added a regmap cache. I used the datasheet to try and determine
   which registers might change without explicit writes.

Changes Since V6:
 - Corrected additional errors identified by sashiko.dev, mostly
   fixing potential deadlocks, missing calls for pm runtime, and
   potential overflow issues.

Changes Since V7:
 - Dropped Wake on Movement patches, since some of the functionality
   was only available for a device on which I cannot test.
 - Dropped support for SPI 3-Wire mode, since it complicated the
   bus setup (and I lack the hardware to test such features anyway).
 - Fixed a few additional bugs identified by sashiko.dev bot.

Changes Since V8:
 - Added back IRQ dropped accidentally when dropping wake on movement
   patches.
 - Dropped "Reviewed-By" tag on patch 2 because of substantial changes
   made to devicetree binding documentation.
 - Additional small fixes as suggested.

Changes Since V9:
 - Removed interrupts (and buffers) from the driver. I previously was
   unable to detect deadlocks because it turns out my IRQ was not even
   wired correctly in my device.
 - Updated devicetree binding commits to make interrupts optional for
   users of the icm42607 driver.

Changes Since V10:
 - Explicitly specified enum values in header file.
 - Removed additional dead code for buffer handling.
 - Cleaned up headers.
 - Added additional locks as requested by sashiko.dev bot.

Changes Since V11:
 - Since driver has shrunk in size considerably, moved i2c bits into
   first code commit. This ensures that the very first commit with code
   can now be compiled. The commit after that adds SPI support as it
   was in the previous versions.
 - Used pahole to optimize inv_icm42607_state. Reordering elements
   reduced size in memory from 384 bytes to 256 bytes.
 - Added a map of all readable registers and all writeable registers
   according to the datasheet.
 - Added back some missing headers pointed out by the maintainers.
 - Added FIELD_PREP in a few more places to make the code more
   obvious on what it's doing.
 - Added a comment to the power management code to note that
   temperature sensor being enabled doesn't matter as the clocks
   are off by default when the gyro and accel channels are off.
 - Removed iio_device_claim_direct() calls since it was no longer
   needed.
 - Fixed shared_by_all attributes for temperature sensor.
 - Additional miscellanous fixes as requested.

Changes Since V12:
 - Removed aligned buffer from inv_icm42607_state struct as we do not
   currently have the need for it.
 - Corrected the order of the odr values in the accel and gyro files
   as the values were out of order (the place in the array corresponds
   to the register value).
 - Stopped setting the clock value depending upon the temp config. The
   datasheet advised to keep using the default value.
 - Corrected logic when changing between states. We only need to pause
   when a sensor changes from off to an on state or when the gyro
   changes from an on state to off.
 - Added missing includes for several files.

Chris Morgan (9):
  dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
  dt-bindings: iio: imu: icm42600: Add icm42607
  iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
  iio: imu: inv_icm42607: Add SPI For icm42607
  iio: imu: inv_icm42607: Add PM support for icm42607
  iio: imu: inv_icm42607: Add Temp Support in icm42607
  iio: imu: inv_icm42607: Add Accelerometer for icm42607
  iio: imu: inv_icm42607: Add Gyroscope to icm42607
  arm64: dts: rockchip: Add icm42607p IMU for RG-DS

 .../bindings/iio/imu/invensense,icm42600.yaml |  20 +-
 .../dts/rockchip/rk3568-anbernic-rg-ds.dts    |   8 +-
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  30 +
 drivers/iio/imu/inv_icm42607/Makefile         |  13 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 410 +++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 373 ++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 546 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 369 ++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  98 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 108 ++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  |  81 +++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  |  37 ++
 14 files changed, 2093 insertions(+), 2 deletions(-)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:44 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:44 -0500
Subject: [PATCH V13 1/9] dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-2-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add mount-matrix attribute to schema. This attribute has been supported
since the first revision of this driver, but was not documented.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../devicetree/bindings/iio/imu/invensense,icm42600.yaml        | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd..9b2af104f186 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -53,6 +53,8 @@ properties:
   drive-open-drain:
     type: boolean
 
+  mount-matrix: true
+
   vdd-supply:
     description: Regulator that provides power to the sensor
 
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:45 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:45 -0500
Subject: [PATCH V13 2/9] dt-bindings: iio: imu: icm42600: Add icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-3-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the ICM42607 and ICM42607P inertial measurement unit.

This device is functionally very similar to the icm42600 series with a
very different register layout. The driver does not require an
interrupt for these specific chip revisions.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
---
 .../bindings/iio/imu/invensense,icm42600.yaml  | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 9b2af104f186..81b6e85decd5 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
       - invensense,icm42600
       - invensense,icm42602
       - invensense,icm42605
+      - invensense,icm42607
+      - invensense,icm42607p
       - invensense,icm42622
       - invensense,icm42631
       - invensense,icm42686
@@ -67,10 +69,24 @@ properties:
 required:
   - compatible
   - reg
-  - interrupts
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - invensense,icm42600
+              - invensense,icm42602
+              - invensense,icm42605
+              - invensense,icm42622
+              - invensense,icm42631
+              - invensense,icm42686
+              - invensense,icm42688
+    then:
+      required:
+        - interrupts
 
 unevaluatedProperties: false
 
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:46 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:46 -0500
Subject: [PATCH V13 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-4-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the core component of a new inv_icm42607 driver. This includes
a few setup functions and the full register definition in the
header file, as well as the bits necessary to compile and probe the
device when used on an i2c bus.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/Kconfig                       |   1 +
 drivers/iio/imu/Makefile                      |   1 +
 drivers/iio/imu/inv_icm42607/Kconfig          |  18 +
 drivers/iio/imu/inv_icm42607/Makefile         |   7 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   | 347 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 280 ++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |  97 +++++
 7 files changed, 751 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig
 create mode 100644 drivers/iio/imu/inv_icm42607/Makefile
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c

diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 7e0181c27bb6..8bab4616be20 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -109,6 +109,7 @@ config KMX61
 	  be called kmx61.
 
 source "drivers/iio/imu/inv_icm42600/Kconfig"
+source "drivers/iio/imu/inv_icm42607/Kconfig"
 source "drivers/iio/imu/inv_icm45600/Kconfig"
 source "drivers/iio/imu/inv_mpu6050/Kconfig"
 
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 13fb7846e9c9..3268dc2371ae 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
 obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
 
 obj-y += inv_icm42600/
+obj-y += inv_icm42607/
 obj-y += inv_icm45600/
 obj-y += inv_mpu6050/
 
diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
new file mode 100644
index 000000000000..083c212087ab
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42607
+	tristate
+	select IIO_BUFFER
+	select IIO_INV_SENSORS_TIMESTAMP
+
+config INV_ICM42607_I2C
+	tristate "InvenSense ICM-42607 I2C driver"
+	depends on I2C
+	select INV_ICM42607
+	select REGMAP_I2C
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over I2C.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-i2c.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
new file mode 100644
index 000000000000..32046e2727d7
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
+inv-icm42607-y += inv_icm42607_core.o
+
+obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
+inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..a6a58571935f
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+/*
+ * Serial bus slew rates. Rates are expressed as range between the two
+ * values with the midpoint as the typical rate. For the final value of
+ * 2ns, 2ns is considered the max value with no expressed minimum or
+ * typical value.
+ */
+enum inv_icm42607_slew_rate {
+	INV_ICM42607_SLEW_RATE_20_60NS = 0,
+	INV_ICM42607_SLEW_RATE_12_36NS = 1,
+	INV_ICM42607_SLEW_RATE_6_19NS = 2,
+	INV_ICM42607_SLEW_RATE_4_14NS = 3,
+	INV_ICM42607_SLEW_RATE_2_6NS = 4,
+	INV_ICM42607_SLEW_RATE_2NS = 5,
+	INV_ICM42607_SLEW_RATE_NB
+};
+
+enum inv_icm42607_sensor_mode {
+	INV_ICM42607_SENSOR_MODE_OFF = 0,
+	INV_ICM42607_SENSOR_MODE_STANDBY = 1,
+	INV_ICM42607_SENSOR_MODE_LOW_POWER = 2,
+	INV_ICM42607_SENSOR_MODE_LOW_NOISE = 3,
+	INV_ICM42607_SENSOR_MODE_NB
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42607_gyro_fs {
+	INV_ICM42607_GYRO_FS_2000DPS = 0,
+	INV_ICM42607_GYRO_FS_1000DPS = 1,
+	INV_ICM42607_GYRO_FS_500DPS = 2,
+	INV_ICM42607_GYRO_FS_250DPS = 3,
+	INV_ICM42607_GYRO_FS_NB
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42607_accel_fs {
+	INV_ICM42607_ACCEL_FS_16G = 0,
+	INV_ICM42607_ACCEL_FS_8G = 1,
+	INV_ICM42607_ACCEL_FS_4G = 2,
+	INV_ICM42607_ACCEL_FS_2G = 3,
+	INV_ICM42607_ACCEL_FS_NB
+};
+
+/* ODR values  - Note Gyro does not support ODR less than 12.5Hz */
+enum inv_icm42607_odr {
+	INV_ICM42607_ODR_1600HZ = 5,
+	INV_ICM42607_ODR_800HZ = 6,
+	INV_ICM42607_ODR_400HZ = 7,
+	INV_ICM42607_ODR_200HZ = 8,
+	INV_ICM42607_ODR_100HZ = 9,
+	INV_ICM42607_ODR_50HZ = 10,
+	INV_ICM42607_ODR_25HZ = 11,
+	INV_ICM42607_ODR_12_5HZ = 12,
+	INV_ICM42607_ODR_6_25HZ_LP = 13,
+	INV_ICM42607_ODR_3_125HZ_LP = 14,
+	INV_ICM42607_ODR_1_5625HZ_LP = 15,
+	INV_ICM42607_ODR_NB
+};
+
+/* Low-Noise mode sensor data filter (bandwidth) */
+enum inv_icm42607_filter_bw {
+	INV_ICM42607_FILTER_BYPASS = 0,
+	INV_ICM42607_FILTER_BW_180HZ = 1,
+	INV_ICM42607_FILTER_BW_121HZ = 2,
+	INV_ICM42607_FILTER_BW_73HZ = 3,
+	INV_ICM42607_FILTER_BW_53HZ = 4,
+	INV_ICM42607_FILTER_BW_34HZ = 5,
+	INV_ICM42607_FILTER_BW_25HZ = 6,
+	INV_ICM42607_FILTER_BW_16HZ = 7,
+	INV_ICM42607_FILTER_BW_NB
+};
+
+/* Signed so that negative values can signify an invalid condition. */
+struct inv_icm42607_sensor_conf {
+	int mode;
+	int fs;
+	int odr;
+	int filter;
+};
+
+struct inv_icm42607_conf {
+	struct inv_icm42607_sensor_conf gyro;
+	struct inv_icm42607_sensor_conf accel;
+	bool temp_en;
+};
+
+struct inv_icm42607_hw {
+	const char *name;
+	const struct inv_icm42607_conf *conf;
+	u8 whoami;
+};
+
+/**
+ *  struct inv_icm42607_state - driver state variables
+ *  @hw:		Hardware specific data.
+ *  @lock:		lock for serializing multiple registers access.
+ *  @map:		regmap pointer.
+ *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @conf:		chip sensors configurations.
+ *  @orientation:	sensor chip orientation relative to main hardware.
+ */
+struct inv_icm42607_state {
+	const struct inv_icm42607_hw *hw;
+	struct mutex lock;
+	struct regmap *map;
+	struct regulator *vddio_supply;
+	struct inv_icm42607_conf conf;
+	struct iio_mount_matrix orientation;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_MCLK_RDY			0x00
+
+#define INV_ICM42607_REG_DEVICE_CONFIG			0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE		BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE		BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET		0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET	BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH	BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1			0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2			0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK		GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3			0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_CONFIG			0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED		BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL		BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH	BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW		0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED		BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL		BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH	BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW		0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1			0x09
+#define INV_ICM42607_REG_TEMP_DATA0			0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1			0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0			0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1			0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0			0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1			0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0			0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1			0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0			0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1			0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0			0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1			0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0			0x16
+#define INV_ICM42607_DATA_INVALID			-32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH			0x17
+#define INV_ICM42607_REG_TMST_FSYNCL			0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0			0x31
+#define INV_ICM42607_REG_APEX_DATA1			0x32
+#define INV_ICM42607_REG_APEX_DATA2			0x33
+#define INV_ICM42607_REG_APEX_DATA3			0x34
+#define INV_ICM42607_REG_APEX_DATA4			0x1D
+#define INV_ICM42607_REG_APEX_DATA5			0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0			0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL		BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE			BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK		GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_GYRO_CONFIG0			0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0			0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK		GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK		GENMASK(3, 0)
+
+#define INV_ICM42607_REG_TEMP_CONFIG0			0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK		GENMASK(6, 4)
+
+#define INV_ICM42607_REG_GYRO_CONFIG1			0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1			0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK		GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_APEX_CONFIG0			0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN	BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN		BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN	BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1			0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE		BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE		BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE		BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE		BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK		GENMASK(1, 0)
+
+#define INV_ICM42607_REG_WOM_CONFIG			0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK		GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_MODE		BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE			BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN			BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1			0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE			BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2			0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3			0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm)		\
+		cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX			(2048 - 12 * 16)
+#define INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE		8
+#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE		16
+
+#define INV_ICM42607_REG_INT_SOURCE0			0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1			0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3			0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN		BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN		BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN	BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN	BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN	BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN	BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN	BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4			0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN	BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN		BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN		BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN		BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN		BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0			0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1			0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0			0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT	BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN	BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN	BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK	GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS	2
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS	3
+
+#define INV_ICM42607_REG_INTF_CONFIG1			0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN		BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN		BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK		GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_INT		0
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL		1
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF		2
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY		0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY		BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS			0x3A
+#define INV_ICM42607_INT_STATUS_ST			BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC			BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY			BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE		BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS		BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL		BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY			BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2			0x3B
+#define INV_ICM42607_INT_STATUS2_SMD			BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT		GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3			0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET		BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF		BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET		BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET			BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH			0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL			0x3E
+#define INV_ICM42607_REG_FIFO_DATA			0x3F
+
+#define INV_ICM42607_REG_WHOAMI				0x75
+#define INV_ICM42607P_WHOAMI				0x60
+#define INV_ICM42607_WHOAMI				0x67
+
+/* Timings as listed in section 3 of datasheet */
+#define INV_ICM42607_POWER_UP_TIME_US			(100 * USEC_PER_MSEC)
+#define INV_ICM42607_RESET_TIME_MS			1
+#define INV_ICM42607_ACCEL_STARTUP_TIME_MS		10
+#define INV_ICM42607_GYRO_STARTUP_TIME_MS		30
+#define INV_ICM42607_GYRO_STOP_TIME_MS			45
+#define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+extern const struct regmap_config inv_icm42607_regmap_config;
+extern const struct inv_icm42607_hw inv_icm42607_hw_data;
+extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..4b8e19091786
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+#include "inv_icm42607.h"
+
+static bool inv_icm42607_is_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY ... INV_ICM42607_REG_INT_CONFIG:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_TMST_FSYNCL:
+	case INV_ICM42607_REG_APEX_DATA4 ... INV_ICM42607_REG_INTF_CONFIG1:
+	case INV_ICM42607_REG_INT_STATUS_DRDY ... INV_ICM42607_REG_FIFO_DATA:
+	case INV_ICM42607_REG_WHOAMI:
+		return true;
+	}
+
+	return false;
+}
+
+static bool inv_icm42607_is_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_DEVICE_CONFIG ... INV_ICM42607_REG_INT_CONFIG:
+	case INV_ICM42607_REG_PWR_MGMT0 ... INV_ICM42607_REG_INT_SOURCE4:
+	case INV_ICM42607_REG_INTF_CONFIG0 ... INV_ICM42607_REG_INTF_CONFIG1:
+		return true;
+	}
+
+	return false;
+}
+
+static bool inv_icm42607_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case INV_ICM42607_REG_MCLK_RDY:
+	case INV_ICM42607_REG_SIGNAL_PATH_RESET:
+	case INV_ICM42607_REG_TEMP_DATA1 ... INV_ICM42607_REG_APEX_DATA5:
+	case INV_ICM42607_REG_APEX_CONFIG0:
+	case INV_ICM42607_REG_FIFO_CONFIG2 ... INV_ICM42607_REG_FIFO_CONFIG3:
+	case INV_ICM42607_REG_FIFO_LOST_PKT0 ... INV_ICM42607_REG_APEX_DATA3:
+	case INV_ICM42607_REG_INT_STATUS_DRDY:
+	case INV_ICM42607_REG_INT_STATUS ... INV_ICM42607_REG_FIFO_DATA:
+		return true;
+	}
+
+	return false;
+}
+
+const struct regmap_config inv_icm42607_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = inv_icm42607_is_writeable_reg,
+	.readable_reg = inv_icm42607_is_readable_reg,
+	.volatile_reg = inv_icm42607_is_volatile_reg,
+	.max_register = INV_ICM42607_REG_WHOAMI,
+	.cache_type = REGCACHE_MAPLE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42607");
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+	.gyro = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_GYRO_FS_1000DPS,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.accel = {
+		.mode = INV_ICM42607_SENSOR_MODE_OFF,
+		.fs = INV_ICM42607_ACCEL_FS_4G,
+		.odr = INV_ICM42607_ODR_100HZ,
+		.filter = INV_ICM42607_FILTER_BW_25HZ,
+	},
+	.temp_en = false,
+};
+
+const struct inv_icm42607_hw inv_icm42607_hw_data = {
+	.whoami = INV_ICM42607_WHOAMI,
+	.name = "icm42607",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_hw_data, "IIO_ICM42607");
+
+const struct inv_icm42607_hw inv_icm42607p_hw_data = {
+	.whoami = INV_ICM42607P_WHOAMI,
+	.name = "icm42607p",
+	.conf = &inv_icm42607_default_conf,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
+
+static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
+				 const struct inv_icm42607_conf *conf)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, conf->gyro.mode);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, conf->accel.mode);
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, conf->gyro.fs);
+	val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, conf->gyro.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->accel.fs);
+	val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->accel.odr);
+	ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, conf->gyro.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+				 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, conf->accel.filter);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+				 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	st->conf = *conf;
+
+	return 0;
+}
+
+static int inv_icm42607_setup(struct inv_icm42607_state *st,
+			      inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	const struct device *dev = regmap_get_device(st->map);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+	if (ret)
+		return ret;
+
+	/* Warn, but don't fail. */
+	if (val != st->hw->whoami)
+		dev_warn(dev, "Unknown whoami %#02x expected %#02x (%s)\n",
+			 val, st->hw->whoami, st->hw->name);
+
+	ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+			   INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+	if (ret)
+		return ret;
+
+	fsleep(1 * USEC_PER_MSEC);
+
+	/*
+	 * No polling interval specified in datasheet, so use reset time as
+	 * polling interval and 10x reset time as timeout period.
+	 */
+	ret = regmap_read_poll_timeout(st->map, INV_ICM42607_REG_INT_STATUS,
+				       val, val & INV_ICM42607_INT_STATUS_RESET_DONE,
+				       1 * USEC_PER_MSEC, 10 * USEC_PER_MSEC);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "reset error, reset done bit not set\n");
+
+	/* Sync the regcache again after a reset. */
+	regcache_mark_dirty(st->map);
+	ret = regcache_sync(st->map);
+	if (ret)
+		return ret;
+
+	ret = inv_icm42607_bus_setup(st);
+	if (ret)
+		return ret;
+
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+			      INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+			 INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				 INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+				 val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_conf(st, st->hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+	int ret;
+
+	ret = regulator_enable(st->vddio_supply);
+	if (ret)
+		return ret;
+
+	fsleep(INV_ICM42607_POWER_UP_TIME_US);
+
+	return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+	struct inv_icm42607_state *st = _data;
+
+	regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap,
+			    const struct inv_icm42607_hw *hw,
+			    inv_icm42607_bus_setup inv_icm42607_bus_setup)
+{
+	struct device *dev = regmap_get_device(regmap);
+	struct inv_icm42607_state *st;
+	int ret;
+
+	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+	if (!st)
+		return -ENOMEM;
+
+	ret = devm_mutex_init(dev, &st->lock);
+	if (ret)
+		return ret;
+
+	st->hw = hw;
+	st->map = regmap;
+
+	ret = iio_read_mount_matrix(dev, &st->orientation);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to retrieve mounting matrix\n");
+
+	ret = devm_regulator_get_enable(dev, "vdd");
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to get vdd regulator\n");
+
+	st->vddio_supply = devm_regulator_get(dev, "vddio");
+	if (IS_ERR(st->vddio_supply))
+		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
+				     "Failed to get vddio regulator\n");
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, inv_icm42607_disable_vddio_reg, st);
+	if (ret)
+		return ret;
+
+	/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */
+	ret = inv_icm42607_setup(st, inv_icm42607_bus_setup);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
new file mode 100644
index 000000000000..bde931752eb8
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK,
+			 INV_ICM42607_SLEW_RATE_12_36NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+				 INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+			 INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  val);
+}
+
+static int inv_icm42607_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	const struct inv_icm42607_hw *hw;
+	struct regmap *regmap;
+
+	hw = i2c_get_match_data(client);
+	if (!hw)
+		return dev_err_probe(dev, -ENODEV, "Failed to get i2c data\n");
+
+	regmap = devm_regmap_init_i2c(client, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to register i2c regmap\n");
+
+	return inv_icm42607_core_probe(regmap, hw, inv_icm42607_i2c_bus_setup);
+}
+
+static const struct i2c_device_id inv_icm42607_id[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, inv_icm42607_id);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	}, {
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct i2c_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-i2c",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_id,
+	.probe = inv_icm42607_probe,
+};
+module_i2c_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:47 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:47 -0500
Subject: [PATCH V13 4/9] iio: imu: inv_icm42607: Add SPI For icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-5-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add SPI driver support for InvenSense ICM-42607 devices.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Kconfig          |  12 ++
 drivers/iio/imu/inv_icm42607/Makefile         |   3 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   | 107 ++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c

diff --git a/drivers/iio/imu/inv_icm42607/Kconfig b/drivers/iio/imu/inv_icm42607/Kconfig
index 083c212087ab..23f461f57afc 100644
--- a/drivers/iio/imu/inv_icm42607/Kconfig
+++ b/drivers/iio/imu/inv_icm42607/Kconfig
@@ -16,3 +16,15 @@ config INV_ICM42607_I2C
 
 	  This driver can be built as a module. The module will be called
 	  inv-icm42607-i2c.
+
+config INV_ICM42607_SPI
+	tristate "InvenSense ICM-42607 SPI driver"
+	depends on SPI_MASTER
+	select INV_ICM42607
+	select REGMAP_SPI
+	help
+	  This driver supports the InvenSense ICM-42607 motion tracking
+	  device over SPI.
+
+	  This driver can be built as a module. The module will be called
+	  inv-icm42607-spi.
diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index 32046e2727d7..be109102e203 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -5,3 +5,6 @@ inv-icm42607-y += inv_icm42607_core.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
+
+obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o
+inv-icm42607-spi-y += inv_icm42607_spi.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
new file mode 100644
index 000000000000..6072ed7adc86
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "inv_icm42607.h"
+
+static int inv_icm42607_spi_bus_setup(struct inv_icm42607_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	/* Only support 4-wire mode for now. */
+	ret = regmap_set_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+				      INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+	if (ret)
+		return ret;
+
+	ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+				INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+				INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK,
+			 INV_ICM42607_SLEW_RATE_2NS);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+				 INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+			 INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+	return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+				  INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+				  val);
+}
+
+static int inv_icm42607_probe(struct spi_device *spi)
+{
+	const struct inv_icm42607_hw *hw;
+	struct device *dev = &spi->dev;
+	struct regmap *regmap;
+
+	hw = spi_get_device_match_data(spi);
+	if (!hw)
+		return dev_err_probe(dev, -ENODEV, "Failed to get SPI data\n");
+
+	if (spi->mode & SPI_3WIRE)
+		return dev_err_probe(dev, -ENODEV, "SPI 3-wire mode not supported\n");
+
+	regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to register spi regmap\n");
+
+	return inv_icm42607_core_probe(regmap, hw,
+				       inv_icm42607_spi_bus_setup);
+}
+
+static const struct spi_device_id inv_icm42607_spi_id_table[] = {
+	{
+		.name = "icm42607",
+		.driver_data = (kernel_ulong_t)&inv_icm42607_hw_data,
+	}, {
+		.name = "icm42607p",
+		.driver_data = (kernel_ulong_t)&inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, inv_icm42607_spi_id_table);
+
+static const struct of_device_id inv_icm42607_of_matches[] = {
+	{
+		.compatible = "invensense,icm42607",
+		.data = &inv_icm42607_hw_data,
+	},
+	{
+		.compatible = "invensense,icm42607p",
+		.data = &inv_icm42607p_hw_data,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, inv_icm42607_of_matches);
+
+static struct spi_driver inv_icm42607_driver = {
+	.driver = {
+		.name = "inv-icm42607-spi",
+		.of_match_table = inv_icm42607_of_matches,
+	},
+	.id_table = inv_icm42607_spi_id_table,
+	.probe = inv_icm42607_probe,
+};
+module_spi_driver(inv_icm42607_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-42607 SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:48 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:48 -0500
Subject: [PATCH V13 5/9] iio: imu: inv_icm42607: Add PM support for icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-6-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add power management support for the ICM42607 device driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  18 +++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 139 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_i2c.c   |   1 +
 .../iio/imu/inv_icm42607/inv_icm42607_spi.c   |   1 +
 4 files changed, 159 insertions(+)

diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index a6a58571935f..4f4f541027dc 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -9,6 +9,7 @@
 #include <linux/bits.h>
 #include <linux/iio/iio.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time.h>
@@ -105,12 +106,20 @@ struct inv_icm42607_hw {
 	u8 whoami;
 };
 
+struct inv_icm42607_suspended {
+	enum inv_icm42607_sensor_mode gyro;
+	enum inv_icm42607_sensor_mode accel;
+	bool temp;
+};
+
 /**
  *  struct inv_icm42607_state - driver state variables
  *  @hw:		Hardware specific data.
  *  @lock:		lock for serializing multiple registers access.
  *  @map:		regmap pointer.
  *  @vddio_supply:	I/O voltage regulator for the chip.
+ *  @vddio_en:		I/O voltage status for runtime PM.
+ *  @suspended:		suspended sensors configuration.
  *  @conf:		chip sensors configurations.
  *  @orientation:	sensor chip orientation relative to main hardware.
  */
@@ -119,6 +128,8 @@ struct inv_icm42607_state {
 	struct mutex lock;
 	struct regmap *map;
 	struct regulator *vddio_supply;
+	bool vddio_en;
+	struct inv_icm42607_suspended suspended;
 	struct inv_icm42607_conf conf;
 	struct iio_mount_matrix orientation;
 };
@@ -334,11 +345,18 @@ struct inv_icm42607_state {
 #define INV_ICM42607_GYRO_STOP_TIME_MS			45
 #define INV_ICM42607_TEMP_STARTUP_TIME_MS		77
 
+/*
+ * Suspend delay assumed from other icm42600 series device, not
+ * documented in datasheet.
+ */
+#define INV_ICM42607_SUSPEND_DELAY_MS			(2 * USEC_PER_MSEC)
+
 typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
 
 extern const struct regmap_config inv_icm42607_regmap_config;
 extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
+extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 4b8e19091786..64f5d263de4f 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/cleanup.h>
 #include <linux/delay.h>
 #include <linux/dev_printk.h>
 #include <linux/device/devres.h>
@@ -11,6 +12,7 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time.h>
@@ -103,6 +105,63 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
+				      enum inv_icm42607_sensor_mode gyro,
+				      enum inv_icm42607_sensor_mode accel,
+				      bool temp, unsigned int *sleep_ms)
+{
+	enum inv_icm42607_sensor_mode oldaccel = st->conf.accel.mode;
+	enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode;
+	bool oldtemp = st->conf.temp_en;
+	unsigned int sleepval_ms;
+	unsigned int val;
+	int ret;
+
+	if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+		return 0;
+
+	/*
+	 * Datasheet on page 14.26 says we need to ensure the gyro sensor is on
+	 * for a minimum of 45ms. So if we transition from an on state to an
+	 * off state wait 45ms to ensure a sufficient pause before power off.
+	 */
+	if (!gyro && oldgyro)
+		fsleep(INV_ICM42607_GYRO_STOP_TIME_MS * USEC_PER_MSEC);
+
+	val = FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, gyro);
+	val |= FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, accel);
+	ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+	if (ret)
+		return ret;
+
+	st->conf.gyro.mode = gyro;
+	st->conf.accel.mode = accel;
+	st->conf.temp_en = temp;
+
+	/*
+	 * If a state change occurs from off to on, sleep for the startup
+	 * time of the sensor, unless a sleep_ms is specified. Since more
+	 * than one sensor can be transitioned from off to on, select the
+	 * maximum time from each of the sensors changing from off to on.
+	 */
+	sleepval_ms = 0;
+	if (temp && !oldtemp)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_TEMP_STARTUP_TIME_MS);
+
+	if (accel && !oldaccel)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_ACCEL_STARTUP_TIME_MS);
+
+	if (gyro && !oldgyro)
+		sleepval_ms = max(sleepval_ms, INV_ICM42607_GYRO_STARTUP_TIME_MS);
+
+	if (sleep_ms)
+		*sleep_ms = sleepval_ms;
+	else if (sleepval_ms)
+		fsleep(sleepval_ms * USEC_PER_MSEC);
+
+	return 0;
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
@@ -208,12 +267,17 @@ static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
 {
 	int ret;
 
+	if (st->vddio_en)
+		return 0;
+
 	ret = regulator_enable(st->vddio_supply);
 	if (ret)
 		return ret;
 
 	fsleep(INV_ICM42607_POWER_UP_TIME_US);
 
+	st->vddio_en = true;
+
 	return 0;
 }
 
@@ -221,7 +285,12 @@ static void inv_icm42607_disable_vddio_reg(void *_data)
 {
 	struct inv_icm42607_state *st = _data;
 
+	if (!st->vddio_en)
+		return;
+
 	regulator_disable(st->vddio_supply);
+
+	st->vddio_en = false;
 }
 
 int inv_icm42607_core_probe(struct regmap *regmap,
@@ -236,6 +305,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (!st)
 		return -ENOMEM;
 
+	dev_set_drvdata(dev, st);
+
 	ret = devm_mutex_init(dev, &st->lock);
 	if (ret)
 		return ret;
@@ -271,10 +342,78 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (ret)
 		return ret;
 
+	ret = devm_pm_runtime_set_active_enabled(dev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(dev);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
 
+static int inv_icm42607_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		return ret;
+
+	inv_icm42607_disable_vddio_reg(st);
+
+	return 0;
+}
+
+static int inv_icm42607_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+	int ret;
+
+	ret = inv_icm42607_enable_vddio_reg(st);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_resume(dev);
+}
+
+static int inv_icm42607_runtime_suspend(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* save sensors state */
+	st->suspended.gyro = st->conf.gyro.mode;
+	st->suspended.accel = st->conf.accel.mode;
+	st->suspended.temp = st->conf.temp_en;
+
+	return inv_icm42607_set_pwr_mgmt0(st, INV_ICM42607_SENSOR_MODE_OFF,
+					  INV_ICM42607_SENSOR_MODE_OFF, false,
+					  NULL);
+}
+
+static int inv_icm42607_runtime_resume(struct device *dev)
+{
+	struct inv_icm42607_state *st = dev_get_drvdata(dev);
+
+	guard(mutex)(&st->lock);
+
+	/* restore sensors state */
+	return inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
+					  st->suspended.accel,
+					  st->suspended.temp, NULL);
+}
+
+EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = {
+	SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume)
+	RUNTIME_PM_OPS(inv_icm42607_runtime_suspend,
+		       inv_icm42607_runtime_resume,
+		       NULL)
+};
+
 MODULE_AUTHOR("InvenSense, Inc.");
 MODULE_DESCRIPTION("InvenSense ICM-42607 device driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
index bde931752eb8..aed04be28528 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c
@@ -85,6 +85,7 @@ static struct i2c_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-i2c",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_id,
 	.probe = inv_icm42607_probe,
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
index 6072ed7adc86..137cd34582d8 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
@@ -95,6 +95,7 @@ static struct spi_driver inv_icm42607_driver = {
 	.driver = {
 		.name = "inv-icm42607-spi",
 		.of_match_table = inv_icm42607_of_matches,
+		.pm = pm_ptr(&inv_icm42607_pm_ops),
 	},
 	.id_table = inv_icm42607_spi_id_table,
 	.probe = inv_icm42607_probe,
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:49 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:49 -0500
Subject: [PATCH V13 6/9] iio: imu: inv_icm42607: Add Temp Support in icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-7-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add functions for reading temperature sensor data.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |  1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  3 +
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  | 18 +++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.c  | 81 +++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_temp.h  | 37 +++++++++
 5 files changed, 140 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index be109102e203..c04953ed42ce 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
 inv-icm42607-i2c-y += inv_icm42607_i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 4f4f541027dc..726b836582a2 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -358,6 +358,9 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 64f5d263de4f..644cd7f821b9 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -162,6 +162,24 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
+			       unsigned int *sleep_ms)
+{
+	unsigned int val;
+	int ret;
+
+	val = FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK,
+			 INV_ICM42607_FILTER_BW_34HZ);
+	ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+				 INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+	if (ret)
+		return ret;
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+					  st->conf.accel.mode, enable,
+					  sleep_ms);
+}
+
 static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
 				 const struct inv_icm42607_conf *conf)
 {
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
new file mode 100644
index 000000000000..9a60e1a478b0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+static int inv_icm42607_temp_read(struct inv_icm42607_state *st, s16 *temp)
+{
+	struct device *dev = regmap_get_device(st->map);
+	u8 raw[2];
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	st->conf.temp_en = true;
+	ret = inv_icm42607_set_temp_conf(st, st->conf.temp_en, NULL);
+	st->conf.temp_en = false;
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1,
+			       raw, sizeof(raw));
+	if (ret)
+		return ret;
+
+	*temp = get_unaligned_be16(raw);
+	if (*temp == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 temp;
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_temp_read(st, &temp);
+		if (ret)
+			return ret;
+		*val = temp;
+		return IIO_VAL_INT;
+	/*
+	 * T?C = (temp / 128) + 25
+	 * Tm?C = 1000 * ((temp * 100 / 12800) + 25)
+	 * scale: 100000 / 12800 ~= 7.8125
+	 * offset: 3200
+	 */
+	case IIO_CHAN_INFO_SCALE:
+		*val = 7;
+		*val2 = 812500000;
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = 3200;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
new file mode 100644
index 000000000000..cb7b460ffb44
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_TEMP_H_
+#define INV_ICM42607_TEMP_H_
+
+#include <linux/bitops.h>
+
+struct iio_dev;
+struct iio_chan_spec;
+
+#define INV_ICM42607_TEMP_CHAN(_index)				\
+{								\
+	.type = IIO_TEMP,					\
+	.info_mask_separate =					\
+		BIT(IIO_CHAN_INFO_RAW) |			\
+		BIT(IIO_CHAN_INFO_OFFSET) |			\
+		BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_all =				\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.info_mask_shared_by_all_available =			\
+		BIT(IIO_CHAN_INFO_SAMP_FREQ),			\
+	.scan_index = _index,					\
+	.scan_type = {						\
+		.sign = 's',					\
+		.realbits = 16,					\
+		.storagebits = 16,				\
+	},							\
+}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long mask);
+
+#endif
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:50 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:50 -0500
Subject: [PATCH V13 7/9] iio: imu: inv_icm42607: Add Accelerometer for icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-8-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add icm42607 accelerometer sensor for icm42607.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |  34 ++
 .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 373 ++++++++++++++++++
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  61 +++
 4 files changed, 469 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index c04953ed42ce..d74b23b1e1be 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
 obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index 726b836582a2..c71d667dadb7 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -86,6 +86,17 @@ enum inv_icm42607_filter_bw {
 	INV_ICM42607_FILTER_BW_NB
 };
 
+/* Low-Power mode sensor data filter (averaging) */
+enum inv_icm42607_filter_avg {
+	INV_ICM42607_FILTER_AVG_2X = 0,
+	INV_ICM42607_FILTER_AVG_4X = 1,
+	INV_ICM42607_FILTER_AVG_8X = 2,
+	INV_ICM42607_FILTER_AVG_16X = 3,
+	INV_ICM42607_FILTER_AVG_32X = 4,
+	INV_ICM42607_FILTER_AVG_64X = 5,
+	/* values 6 and 7 also correspond to 64x. */
+};
+
 /* Signed so that negative values can signify an invalid condition. */
 struct inv_icm42607_sensor_conf {
 	int mode;
@@ -93,6 +104,7 @@ struct inv_icm42607_sensor_conf {
 	int odr;
 	int filter;
 };
+#define INV_ICM42607_SENSOR_CONF_INIT		{ -1, -1, -1, -1 }
 
 struct inv_icm42607_conf {
 	struct inv_icm42607_sensor_conf gyro;
@@ -117,6 +129,7 @@ struct inv_icm42607_suspended {
  *  @hw:		Hardware specific data.
  *  @lock:		lock for serializing multiple registers access.
  *  @map:		regmap pointer.
+ *  @indio_accel:	accelerometer IIO device.
  *  @vddio_supply:	I/O voltage regulator for the chip.
  *  @vddio_en:		I/O voltage status for runtime PM.
  *  @suspended:		suspended sensors configuration.
@@ -127,6 +140,7 @@ struct inv_icm42607_state {
 	const struct inv_icm42607_hw *hw;
 	struct mutex lock;
 	struct regmap *map;
+	struct iio_dev *indio_accel;
 	struct regulator *vddio_supply;
 	bool vddio_en;
 	struct inv_icm42607_suspended suspended;
@@ -134,6 +148,16 @@ struct inv_icm42607_state {
 	struct iio_mount_matrix orientation;
 };
 
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @power_mode:		sensor requested power mode (for common frequencies)
+ * @filter:		sensor filter.
+ */
+struct inv_icm42607_sensor_state {
+	enum inv_icm42607_sensor_mode power_mode;
+	int filter;
+};
+
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
 
 /* Register Map for User Bank 0 */
@@ -358,6 +382,14 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;
 extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
 extern const struct dev_pm_ops inv_icm42607_pm_ops;
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan);
+
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -365,4 +397,6 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
+
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
new file mode 100644
index 000000000000..41e6a9283608
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info)			\
+{										\
+	.type = IIO_ACCEL,							\
+	.modified = 1,								\
+	.channel2 = _modifier,							\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),				\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),		\
+	.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = _index,							\
+	.scan_type = {								\
+		.sign = 's',							\
+		.realbits = 16,							\
+		.storagebits = 16,						\
+		.endianness = IIO_BE,						\
+	},									\
+	.ext_info = _ext_info,							\
+}
+
+enum inv_icm42607_accel_scan {
+	INV_ICM42607_ACCEL_SCAN_X,
+	INV_ICM42607_ACCEL_SCAN_Y,
+	INV_ICM42607_ACCEL_SCAN_Z,
+	INV_ICM42607_ACCEL_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_accel_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42607_ACCEL_SCAN_X,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42607_ACCEL_SCAN_Y,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42607_ACCEL_SCAN_Z,
+				inv_icm42607_accel_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_ACCEL_SCAN_TEMP),
+};
+
+static int inv_icm42607_accel_read_sensor(struct iio_dev *indio_dev,
+					  struct iio_chan_spec const *chan,
+					  s16 *val)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *accel_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int reg;
+	u8 data[2];
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable accel sensor */
+	conf.mode = accel_st->power_mode;
+	conf.filter = accel_st->filter;
+	ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read accel register data */
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(data));
+	if (ret)
+		return ret;
+
+	*val = get_unaligned_be16(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_accel_scale_nano[][2] = {
+	[INV_ICM42607_ACCEL_FS_16G] = { 0, 4788403 },
+	[INV_ICM42607_ACCEL_FS_8G] = { 0, 2394202 },
+	[INV_ICM42607_ACCEL_FS_4G] = { 0, 1197101 },
+	[INV_ICM42607_ACCEL_FS_2G] = { 0, 598550 },
+};
+
+static int inv_icm42607_accel_read_scale(struct iio_dev *indio_dev,
+					 int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.accel.fs;
+
+	*val = inv_icm42607_accel_scale_nano[idx][0];
+	*val2 = inv_icm42607_accel_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_accel_write_scale(struct iio_dev *indio_dev,
+					  int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_accel_scale_nano);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_accel_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_accel_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_accel_conf(st, &conf, NULL);
+}
+
+/* IIO format int + micro , values 0-5 reserved. */
+static const int inv_icm42607_accel_odr[][2] = {
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+	[INV_ICM42607_ODR_6_25HZ_LP] = { 6, 250000 },
+	[INV_ICM42607_ODR_3_125HZ_LP] = { 3, 125000 },
+	[INV_ICM42607_ODR_1_5625HZ_LP] = { 1, 562500 },
+};
+
+static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
+				       int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.accel.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_accel_odr[i][0];
+	*val2 = inv_icm42607_accel_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
+					int val, int val2)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {
+		if (val == inv_icm42607_accel_odr[idx][0] &&
+		    val2 == inv_icm42607_accel_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_accel_conf(st, &conf, NULL);
+}
+
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ACCEL:
+		break;
+	case IIO_TEMP:
+		if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+			return inv_icm42607_temp_read_raw(indio_dev, chan,
+							  val, val2, mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_accel_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_read_avail(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 const int **vals,
+					 int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_accel_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_accel_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_accel_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_accel_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		ret = inv_icm42607_accel_write_scale(indio_dev, val, val2);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
+						struct iio_chan_spec const *chan,
+						long mask)
+{
+	if (chan->type != IIO_ACCEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_accel_info = {
+	.read_raw = inv_icm42607_accel_read_raw,
+	.read_avail = inv_icm42607_accel_read_avail,
+	.write_raw = inv_icm42607_accel_write_raw,
+	.write_raw_get_fmt = inv_icm42607_accel_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	struct inv_icm42607_sensor_state *accel_st;
+	struct iio_dev *indio_dev;
+	const char *name;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	accel_st = iio_priv(indio_dev);
+
+	accel_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+	accel_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_accel_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_accel_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index 644cd7f821b9..eb239987a1ce 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -105,6 +105,15 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = {
 };
 EXPORT_SYMBOL_NS_GPL(inv_icm42607p_hw_data, "IIO_ICM42607");
 
+const struct iio_mount_matrix *
+inv_icm42607_get_mount_matrix(struct iio_dev *indio_dev,
+			      const struct iio_chan_spec *chan)
+{
+	const struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+	return &st->orientation;
+}
+
 static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 				      enum inv_icm42607_sensor_mode gyro,
 				      enum inv_icm42607_sensor_mode accel,
@@ -162,6 +171,53 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,
 	return 0;
 }
 
+int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
+				struct inv_icm42607_sensor_conf *conf,
+				unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.accel;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		if (conf->mode == INV_ICM42607_SENSOR_MODE_LOW_POWER) {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
+		} else {
+			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
+					 conf->filter);
+			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+						 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+		}
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -367,6 +423,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	pm_runtime_set_autosuspend_delay(dev, INV_ICM42607_SUSPEND_DELAY_MS);
 	pm_runtime_use_autosuspend(dev);
 
+	/* Initialize IIO device for Accel */
+	st->indio_accel = inv_icm42607_accel_init(st);
+	if (IS_ERR(st->indio_accel))
+		return PTR_ERR(st->indio_accel);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:51 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:51 -0500
Subject: [PATCH V13 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-9-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add gyroscope functions to the icm42607 driver.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 drivers/iio/imu/inv_icm42607/Makefile         |   1 +
 drivers/iio/imu/inv_icm42607/inv_icm42607.h   |   8 +
 .../iio/imu/inv_icm42607/inv_icm42607_core.c  |  48 +++
 .../iio/imu/inv_icm42607/inv_icm42607_gyro.c  | 369 ++++++++++++++++++
 4 files changed, 426 insertions(+)
 create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c

diff --git a/drivers/iio/imu/inv_icm42607/Makefile b/drivers/iio/imu/inv_icm42607/Makefile
index d74b23b1e1be..7b907e019601 100644
--- a/drivers/iio/imu/inv_icm42607/Makefile
+++ b/drivers/iio/imu/inv_icm42607/Makefile
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o
 inv-icm42607-y += inv_icm42607_core.o
+inv-icm42607-y += inv_icm42607_gyro.o
 inv-icm42607-y += inv_icm42607_accel.o
 inv-icm42607-y += inv_icm42607_temp.o
 
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
index c71d667dadb7..ab529e6191f6 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607.h
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -130,6 +130,7 @@ struct inv_icm42607_suspended {
  *  @lock:		lock for serializing multiple registers access.
  *  @map:		regmap pointer.
  *  @indio_accel:	accelerometer IIO device.
+ *  @indio_gyro:	gyroscope IIO device.
  *  @vddio_supply:	I/O voltage regulator for the chip.
  *  @vddio_en:		I/O voltage status for runtime PM.
  *  @suspended:		suspended sensors configuration.
@@ -141,6 +142,7 @@ struct inv_icm42607_state {
 	struct mutex lock;
 	struct regmap *map;
 	struct iio_dev *indio_accel;
+	struct iio_dev *indio_gyro;
 	struct regulator *vddio_supply;
 	bool vddio_en;
 	struct inv_icm42607_suspended suspended;
@@ -390,6 +392,10 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 				struct inv_icm42607_sensor_conf *conf,
 				unsigned int *sleep_ms);
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms);
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms);
 
@@ -397,6 +403,8 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 			    const struct inv_icm42607_hw *hw,
 			    inv_icm42607_bus_setup bus_setup);
 
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st);
+
 struct iio_dev *inv_icm42607_accel_init(struct inv_icm42607_state *st);
 
 #endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
index eb239987a1ce..23ca7529825c 100644
--- a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -218,6 +218,49 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
 					  st->conf.temp_en, sleep_ms);
 }
 
+int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
+			       struct inv_icm42607_sensor_conf *conf,
+			       unsigned int *sleep_ms)
+{
+	struct inv_icm42607_sensor_conf *oldconf = &st->conf.gyro;
+	unsigned int val;
+	int ret;
+
+	if (conf->mode < 0)
+		conf->mode = oldconf->mode;
+	if (conf->fs < 0)
+		conf->fs = oldconf->fs;
+	if (conf->odr < 0)
+		conf->odr = oldconf->odr;
+	if (conf->filter < 0)
+		conf->filter = oldconf->filter;
+
+	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK,
+				 conf->fs);
+		val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK,
+				  conf->odr);
+		ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+		if (ret)
+			return ret;
+		oldconf->fs = conf->fs;
+		oldconf->odr = conf->odr;
+	}
+
+	if (conf->filter != oldconf->filter) {
+		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
+				 conf->filter);
+		ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+					 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+		if (ret)
+			return ret;
+		oldconf->filter = conf->filter;
+	}
+
+	return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+					  st->conf.temp_en, sleep_ms);
+}
+
 int inv_icm42607_set_temp_conf(struct inv_icm42607_state *st, bool enable,
 			       unsigned int *sleep_ms)
 {
@@ -428,6 +471,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,
 	if (IS_ERR(st->indio_accel))
 		return PTR_ERR(st->indio_accel);
 
+	/* Initialize IIO device for Gyro */
+	st->indio_gyro = inv_icm42607_gyro_init(st);
+	if (IS_ERR(st->indio_gyro))
+		return PTR_ERR(st->indio_gyro);
+
 	return 0;
 }
 EXPORT_SYMBOL_NS_GPL(inv_icm42607_core_probe, "IIO_ICM42607");
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
new file mode 100644
index 000000000000..ef73560b39d7
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+#include "inv_icm42607.h"
+#include "inv_icm42607_temp.h"
+
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info)			\
+{										\
+	.type = IIO_ANGL_VEL,							\
+	.modified = 1,								\
+	.channel2 = _modifier,							\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),				\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),			\
+	.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),		\
+	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),		\
+	.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+	.scan_index = _index,							\
+	.scan_type = {								\
+		.sign = 's',							\
+		.realbits = 16,							\
+		.storagebits = 16,						\
+		.endianness = IIO_BE,						\
+	},									\
+	.ext_info = _ext_info,							\
+}
+
+enum inv_icm42607_gyro_scan {
+	INV_ICM42607_GYRO_SCAN_X,
+	INV_ICM42607_GYRO_SCAN_Y,
+	INV_ICM42607_GYRO_SCAN_Z,
+	INV_ICM42607_GYRO_SCAN_TEMP,
+};
+
+static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = {
+	IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42607_get_mount_matrix),
+	{ }
+};
+
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42607_GYRO_SCAN_X,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42607_GYRO_SCAN_Y,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42607_GYRO_SCAN_Z,
+			       inv_icm42607_gyro_ext_infos),
+	INV_ICM42607_TEMP_CHAN(INV_ICM42607_GYRO_SCAN_TEMP),
+};
+
+static int inv_icm42607_gyro_read_sensor(struct iio_dev *indio_dev,
+					 struct iio_chan_spec const *chan,
+					 s16 *val)
+{
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct inv_icm42607_sensor_state *gyro_st = iio_priv(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int reg;
+	u8 data[2];
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (chan->channel2) {
+	case IIO_MOD_X:
+		reg = INV_ICM42607_REG_GYRO_DATA_X1;
+		break;
+	case IIO_MOD_Y:
+		reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+		break;
+	case IIO_MOD_Z:
+		reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	/* enable gyro sensor */
+	conf.mode = gyro_st->power_mode;
+	conf.filter = gyro_st->filter;
+	ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+	if (ret)
+		return ret;
+
+	/* read gyro register data */
+	ret = regmap_bulk_read(st->map, reg, data, sizeof(data));
+	if (ret)
+		return ret;
+
+	*val = get_unaligned_be16(data);
+	if (*val == INV_ICM42607_DATA_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const int inv_icm42607_gyro_scale_nano[][2] = {
+	[INV_ICM42607_GYRO_FS_2000DPS] = { 0, 1065264 },
+	[INV_ICM42607_GYRO_FS_1000DPS] = { 0, 532632 },
+	[INV_ICM42607_GYRO_FS_500DPS] = { 0, 266316 },
+	[INV_ICM42607_GYRO_FS_250DPS] = { 0, 133158 },
+};
+
+static int inv_icm42607_gyro_read_scale(struct iio_dev *indio_dev,
+					int *val, int *val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	unsigned int idx;
+
+	guard(mutex)(&st->lock);
+
+	idx = st->conf.gyro.fs;
+
+	*val = inv_icm42607_gyro_scale_nano[idx][0];
+	*val2 = inv_icm42607_gyro_scale_nano[idx][1];
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static int inv_icm42607_gyro_write_scale(struct iio_dev *indio_dev,
+					 int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	size_t scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale_nano);
+	int ret;
+
+	for (idx = 0; idx < scales_len; idx++) {
+		if (val == inv_icm42607_gyro_scale_nano[idx][0] &&
+		    val2 == inv_icm42607_gyro_scale_nano[idx][1])
+			break;
+	}
+	if (idx >= scales_len)
+		return -EINVAL;
+
+	conf.fs = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
+}
+
+static const int inv_icm42607_gyro_odr[][2] = {
+	[INV_ICM42607_ODR_1600HZ] = { 1600, 0 },
+	[INV_ICM42607_ODR_800HZ] = { 800, 0 },
+	[INV_ICM42607_ODR_400HZ] = { 400, 0 },
+	[INV_ICM42607_ODR_200HZ] = { 200, 0 },
+	[INV_ICM42607_ODR_100HZ] = { 100, 0 },
+	[INV_ICM42607_ODR_50HZ] = { 50, 0 },
+	[INV_ICM42607_ODR_25HZ] = { 25, 0 },
+	[INV_ICM42607_ODR_12_5HZ] = { 12, 500000 },
+};
+
+static int inv_icm42607_gyro_read_odr(struct inv_icm42607_state *st,
+				      int *val, int *val2)
+{
+	unsigned int odr;
+	unsigned int i;
+
+	guard(mutex)(&st->lock);
+
+	odr = st->conf.gyro.odr;
+
+	for (i = 5; i < ARRAY_SIZE(inv_icm42607_gyro_odr); ++i) {
+		if (i == odr)
+			break;
+	}
+	if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	*val = inv_icm42607_gyro_odr[i][0];
+	*val2 = inv_icm42607_gyro_odr[i][1];
+
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
+				       int val, int val2)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	struct device *dev = regmap_get_device(st->map);
+	unsigned int idx;
+	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
+	int ret;
+
+	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); ++idx) {
+		if (val == inv_icm42607_gyro_odr[idx][0] &&
+		    val2 == inv_icm42607_gyro_odr[idx][1])
+			break;
+	}
+	if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+		return -EINVAL;
+
+	conf.odr = idx;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&st->lock);
+
+	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
+}
+
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+				      struct iio_chan_spec const *chan,
+				      int *val, int *val2, long mask)
+{
+	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+	s16 data;
+	int ret;
+
+	switch (chan->type) {
+	case IIO_ANGL_VEL:
+		break;
+	case IIO_TEMP:
+		if (mask != IIO_CHAN_INFO_SAMP_FREQ)
+			return inv_icm42607_temp_read_raw(indio_dev, chan,
+							  val, val2, mask);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = inv_icm42607_gyro_read_sensor(indio_dev, chan, &data);
+		if (ret)
+			return ret;
+		*val = data;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		return inv_icm42607_gyro_read_scale(indio_dev, val, val2);
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_read_odr(st, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_read_avail(struct iio_dev *indio_dev,
+					struct iio_chan_spec const *chan,
+					const int **vals,
+					int *type, int *length, long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		*vals = (const int *)inv_icm42607_gyro_scale_nano;
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*length = ARRAY_SIZE(inv_icm42607_gyro_scale_nano) * 2;
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*vals = (const int *)inv_icm42607_gyro_odr[5];
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*length = (ARRAY_SIZE(inv_icm42607_gyro_odr) - 5) * 2;
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+				       struct iio_chan_spec const *chan,
+				       int val, int val2, long mask)
+{
+	int ret;
+
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		ret = inv_icm42607_gyro_write_scale(indio_dev, val, val2);
+		return ret;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int inv_icm42607_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
+					       struct iio_chan_spec const *chan,
+					       long mask)
+{
+	if (chan->type != IIO_ANGL_VEL)
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		return IIO_VAL_INT_PLUS_NANO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info inv_icm42607_gyro_info = {
+	.read_raw = inv_icm42607_gyro_read_raw,
+	.read_avail = inv_icm42607_gyro_read_avail,
+	.write_raw = inv_icm42607_gyro_write_raw,
+	.write_raw_get_fmt = inv_icm42607_gyro_write_raw_get_fmt,
+};
+
+struct iio_dev *inv_icm42607_gyro_init(struct inv_icm42607_state *st)
+{
+	struct device *dev = regmap_get_device(st->map);
+	const char *name;
+	struct inv_icm42607_sensor_state *gyro_st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->hw->name);
+	if (!name)
+		return ERR_PTR(-ENOMEM);
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+	if (!indio_dev)
+		return ERR_PTR(-ENOMEM);
+	gyro_st = iio_priv(indio_dev);
+
+	gyro_st->power_mode = INV_ICM42607_SENSOR_MODE_LOW_NOISE;
+	gyro_st->filter = INV_ICM42607_FILTER_BW_73HZ;
+
+	iio_device_set_drvdata(indio_dev, st);
+	indio_dev->name = name;
+	indio_dev->info = &inv_icm42607_gyro_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = inv_icm42607_gyro_channels;
+	indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return indio_dev;
+}
-- 
2.43.0



From macroalpha82 at gmail.com  Mon Jun 15 10:25:52 2026
From: macroalpha82 at gmail.com (Chris Morgan)
Date: Mon, 15 Jun 2026 12:25:52 -0500
Subject: [PATCH V13 9/9] arm64: dts: rockchip: Add icm42607p IMU for RG-DS
In-Reply-To: <20260615172554.160910-1-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
Message-ID: <20260615172554.160910-10-macroalpha82@gmail.com>

From: Chris Morgan <macromorgan at hotmail.com>

Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix
was tested with iio-sensor-proxy and reports correct orientation.

Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
 arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
index 8d906ab02c5f..b770bfd5268d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
@@ -871,7 +871,13 @@ aw87391_pa_r: audio-codec at 5b {
 		sound-name-prefix = "Right Amp";
 	};
 
-	/* invensense,icm42607p at 0x68 */
+	icm42607p: imu at 68 {
+		compatible = "invensense,icm42607p";
+		reg = <0x68>;
+		mount-matrix = "-1", "0", "0",
+			       "0", "1", "0",
+			       "0", "0", "-1";
+	};
 };
 
 &i2c3 {
-- 
2.43.0



From geraldogabriel at gmail.com  Mon Jun 15 12:30:38 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Mon, 15 Jun 2026 16:30:38 -0300
Subject: [PATCH v6 3/3] PCI: rockchip: drive at 2.5 GT/s, error other
 speeds
In-Reply-To: <4ac5cd7d2271df375ed6307f5c394247721395d9.1781207474.git.geraldogabriel@gmail.com>
References: <cover.1781207474.git.geraldogabriel@gmail.com>
 <4ac5cd7d2271df375ed6307f5c394247721395d9.1781207474.git.geraldogabriel@gmail.com>
Message-ID: <ajBS3tGp0wqLyVq7@geday>

Hi,

On Thu, Jun 11, 2026 at 05:04:22PM -0300, Geraldo Nascimento wrote:
> Configure the core to be driven at 2.5 GT/s Link Speed and ignore
> any other speed with a warning. Also drop the 5.0 GT/s Link Speed
> defines from Rockchip PCIe header.
> 
> The reason is that Shawn Lin from Rockchip has reiterated that there
> may be danger of "catastrophic failure" in using their PCIe with
> 5.0 GT/s speeds.
> 
> While Rockchip has done so informally without issuing a proper errata,
> and the particulars are thus unknown, this may cause data loss or
> worse.
> 
> This change is corroborated by RK3399 official datasheet [1], which
> states 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>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip.c | 16 +++++++++-------
>  drivers/pci/controller/pcie-rockchip.h |  3 ---
>  2 files changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> index 0f88da3788054..5a2876d7c8547 100644
> --- a/drivers/pci/controller/pcie-rockchip.c
> +++ b/drivers/pci/controller/pcie-rockchip.c
> @@ -66,8 +66,10 @@ 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, limited 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];
> @@ -147,12 +149,12 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
>  		goto err_exit_phy;
>  	}
>  
> +	/* 5.0 GT/s may cause catastrophic failure for this core */
>  	if (rockchip->link_gen == 2)
> -		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,

Sashiko caught unreachable dead code rightfully here. It looks like I
had got it right in v4 and then the fix regressed.

Will address this for v7 after I get more comments.

Thanks,
Geraldo Nascimento


From oklopfer37 at gmail.com  Mon Jun 15 15:50:13 2026
From: oklopfer37 at gmail.com (Oren Klopfer)
Date: Mon, 15 Jun 2026 18:50:13 -0400
Subject: [PATCH] Revert "arm64: dts: rockchip: Further describe the WiFi for the Pinephone Pro"
Message-ID: <20260615225014.219115-1-oklopfer37@gmail.com>

This reverts commit 096bd8c679185f898cae9933c6a68650fa26ea4f.

Just as with the Pinebook Pro, there are multiple chipset variants for the Pinephone Pro, and multiple firmware binaries for different distributions. The change causes issues with some of these combinations, and reverting it resolves the issues. See the Closes below for the full report.

Similarly with the Pinebook Pro adjustment, the original commit only indicates "further description" and not indicative of fixing any existing issues, so reverting should not kick any back up.

Fixes: 096bd8c67918 ("arm64: dts: rockchip: Further describe the WiFi for the Pinephone Pro")
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: Peter Robinson <pbrobinson at gmail.com>
Cc: Thorsten Leemhuis <regressions at leemhuis.info>
Cc: stable at vger.kernel.org
Closes: https://lore.kernel.org/r/20260607225901.64019-1-oklopfer37 at gmail.com/
Signed-off-by: Oren Klopfer <oklopfer37 at gmail.com>
---
 .../boot/dts/rockchip/rk3399-pinephone-pro.dts | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 8d26bd9b7500..d46cdfe3f784 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -734,12 +734,6 @@ light_int_l: light-int-l {
         };
     };
 
-    wifi {
-        wifi_host_wake_l: wifi-host-wake-l {
-            rockchip,pins = <4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>;
-        };
-    };
-
     wireless-bluetooth {
         bt_wake_pin: bt-wake-pin {
             rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -766,19 +760,7 @@ &sdio0 {
     pinctrl-names = "default";
     pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
     sd-uhs-sdr104;
-    #address-cells = <1>;
-    #size-cells = <0>;
     status = "okay";
-
-    brcmf: wifi at 1 {
-        compatible = "brcm,bcm4329-fmac";
-        reg = <1>;
-        interrupt-parent = <&gpio4>;
-        interrupts = <RK_PD0 IRQ_TYPE_LEVEL_HIGH>;
-        interrupt-names = "host-wake";
-        pinctrl-names = "default";
-        pinctrl-0 = <&wifi_host_wake_l>;
-    };
 };
 
 &pwm0 {
-- 
2.53.0


From mani at kernel.org  Mon Jun 15 22:39:26 2026
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 16 Jun 2026 07:39:26 +0200
Subject: [PATCH v6 3/3] PCI: rockchip: drive at 2.5 GT/s, error other
 speeds
In-Reply-To: <ajBS3tGp0wqLyVq7@geday>
References: <cover.1781207474.git.geraldogabriel@gmail.com>
 <4ac5cd7d2271df375ed6307f5c394247721395d9.1781207474.git.geraldogabriel@gmail.com>
 <ajBS3tGp0wqLyVq7@geday>
Message-ID: <2nhgubo6h6eo5t5mzzizhiatea2f6if6fgjumzb7qae7idw34x@nljy2gwgi64g>

On Mon, Jun 15, 2026 at 04:30:38PM -0300, Geraldo Nascimento wrote:
> Hi,
> 
> On Thu, Jun 11, 2026 at 05:04:22PM -0300, Geraldo Nascimento wrote:
> > Configure the core to be driven at 2.5 GT/s Link Speed and ignore
> > any other speed with a warning. Also drop the 5.0 GT/s Link Speed
> > defines from Rockchip PCIe header.
> > 
> > The reason is that Shawn Lin from Rockchip has reiterated that there
> > may be danger of "catastrophic failure" in using their PCIe with
> > 5.0 GT/s speeds.
> > 
> > While Rockchip has done so informally without issuing a proper errata,
> > and the particulars are thus unknown, this may cause data loss or
> > worse.
> > 
> > This change is corroborated by RK3399 official datasheet [1], which
> > states 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>
> > Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> > ---
> >  drivers/pci/controller/pcie-rockchip.c | 16 +++++++++-------
> >  drivers/pci/controller/pcie-rockchip.h |  3 ---
> >  2 files changed, 9 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> > index 0f88da3788054..5a2876d7c8547 100644
> > --- a/drivers/pci/controller/pcie-rockchip.c
> > +++ b/drivers/pci/controller/pcie-rockchip.c
> > @@ -66,8 +66,10 @@ 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, limited 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];
> > @@ -147,12 +149,12 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
> >  		goto err_exit_phy;
> >  	}
> >  
> > +	/* 5.0 GT/s may cause catastrophic failure for this core */
> >  	if (rockchip->link_gen == 2)
> > -		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
> 
> Sashiko caught unreachable dead code rightfully here. It looks like I
> had got it right in v4 and then the fix regressed.
> 
> Will address this for v7 after I get more comments.
> 

I don't have any comments other than this.

- Mani

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


From andriy.shevchenko at intel.com  Tue Jun 16 00:07:55 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Tue, 16 Jun 2026 10:07:55 +0300
Subject: [PATCH V12 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <PH0PR19MB9973380BF26E3EF16BD2D35ED0A5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
References: <20260611202607.85376-1-macroalpha82@gmail.com>
 <20260611202607.85376-8-macroalpha82@gmail.com>
 <ai_gIR2d9fzHLZ-G@ashevche-desk.local>
 <PH0PR19MB997338010EC6FA92E0AA63875FA5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
 <ajAVI0KXkx3FM1ZX@ashevche-desk.local>
 <PH0PR19MB9973380BF26E3EF16BD2D35ED0A5E62@PH0PR19MB997338.namprd19.prod.outlook.com>
Message-ID: <ajD2S8nBhRn1-C_G@ashevche-desk.local>

On Mon, Jun 15, 2026 at 11:40:31AM -0500, Chris Morgan wrote:
> On Mon, Jun 15, 2026 at 06:07:15PM +0300, Andy Shevchenko wrote:
> > On Mon, Jun 15, 2026 at 09:51:40AM -0500, Chris Morgan wrote:
> > > On Mon, Jun 15, 2026 at 02:21:05PM +0300, Andy Shevchenko wrote:
> > > > On Thu, Jun 11, 2026 at 03:26:04PM -0500, Chris Morgan wrote:

...

> > > > > +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {
> > > > 
> > > > Why pre-increment? Same for all other cases.
> > > 
> > > The register starts at 5 and all values below 5 are invalid. Starting
> > > this increment at 5 ensures we don't expose invalid values to
> > > userspace.
> > 
> > It doesn't explain pre-increment. Post-increment should work as is.
> 
> The array this references starts at 5, because those correspond to the
> values written to the odr register. That said, I do see a bug because
> the odr register is from highest to smallest and this array is
> backwards in the accel and gyro code. I'll fix that.

Good we even managed to find a bug, but what I initially pointed out is simply
as ++i versus i++. When I see ++i, it rises a flag: "this code is special", but
looking closer, I see nothing special about it.

> > > > > +		if (i == odr)
> > > > > +			break;
> > > > > +	}

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Tue Jun 16 01:53:35 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Tue, 16 Jun 2026 11:53:35 +0300
Subject: [PATCH V13 3/9] iio: imu: inv_icm42607: Add inv_icm42607 Core
 Driver
In-Reply-To: <20260615172554.160910-4-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
 <20260615172554.160910-4-macroalpha82@gmail.com>
Message-ID: <ajEPD8gdgiuQdZ7Q@ashevche-desk.local>

On Mon, Jun 15, 2026 at 12:25:46PM -0500, Chris Morgan wrote:

> Add the core component of a new inv_icm42607 driver. This includes
> a few setup functions and the full register definition in the
> header file, as well as the bits necessary to compile and probe the
> device when used on an i2c bus.

...

> +#ifndef INV_ICM42607_H_
> +#define INV_ICM42607_H_
> +
> +#include <linux/bits.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mutex.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/time.h>
> +#include <linux/types.h>

+ asm/byteorder.h // cpu_to_le16()

...

> +#include <linux/bitfield.h>
> +#include <linux/dev_printk.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +

Single blank line is enough.

> +#include "inv_icm42607.h"

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Tue Jun 16 03:04:36 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Tue, 16 Jun 2026 13:04:36 +0300
Subject: [PATCH V13 7/9] iio: imu: inv_icm42607: Add Accelerometer for
 icm42607
In-Reply-To: <20260615172554.160910-8-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
 <20260615172554.160910-8-macroalpha82@gmail.com>
Message-ID: <ajEftPsZVtmKS6dr@ashevche-desk.local>

On Mon, Jun 15, 2026 at 12:25:50PM -0500, Chris Morgan wrote:

> Add icm42607 accelerometer sensor for icm42607.

...

> +static int inv_icm42607_accel_read_odr(struct inv_icm42607_state *st,
> +				       int *val, int *val2)
> +{
> +	unsigned int odr;
> +	unsigned int i;
> +
> +	guard(mutex)(&st->lock);
> +
> +	odr = st->conf.accel.odr;
> +
> +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_accel_odr); ++i) {

Same comment stays. Why pre-increment?

> +		if (i == odr)
> +			break;
> +	}
> +	if (i >= ARRAY_SIZE(inv_icm42607_accel_odr))
> +		return -EINVAL;
> +
> +	*val = inv_icm42607_accel_odr[i][0];
> +	*val2 = inv_icm42607_accel_odr[i][1];
> +
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}

...

> +static int inv_icm42607_accel_write_odr(struct iio_dev *indio_dev,
> +					int val, int val2)
> +{
> +	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	struct device *dev = regmap_get_device(st->map);
> +	unsigned int idx;
> +	int ret;
> +
> +	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_accel_odr); ++idx) {

Ditto.

> +		if (val == inv_icm42607_accel_odr[idx][0] &&
> +		    val2 == inv_icm42607_accel_odr[idx][1])
> +			break;
> +	}
> +	if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
> +		return -EINVAL;
> +
> +	conf.odr = idx;
> +
> +	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> +	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&st->lock);
> +
> +	return inv_icm42607_set_accel_conf(st, &conf, NULL);
> +}

...

> +int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,
> +				struct inv_icm42607_sensor_conf *conf,
> +				unsigned int *sleep_ms)
> +{
> +	struct inv_icm42607_sensor_conf *oldconf = &st->conf.accel;
> +	unsigned int val;
> +	int ret;
> +
> +	if (conf->mode < 0)
> +		conf->mode = oldconf->mode;

Also as per below.

> +	if (conf->fs < 0)
> +		conf->fs = oldconf->fs;
> +	if (conf->odr < 0)
> +		conf->odr = oldconf->odr;

> +	if (conf->filter < 0)
> +		conf->filter = oldconf->filter;

This conditional is not immediately used below...

> +	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
> +		val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, conf->fs);
> +		val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, conf->odr);
> +		ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
> +		if (ret)
> +			return ret;
> +		oldconf->fs = conf->fs;
> +		oldconf->odr = conf->odr;
> +	}

...you can move it here.

> +	if (conf->filter != oldconf->filter) {
> +		if (conf->mode == INV_ICM42607_SENSOR_MODE_LOW_POWER) {
> +			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, conf->filter);
> +			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
> +						 INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
> +		} else {
> +			val = FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK,
> +					 conf->filter);
> +			ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
> +						 INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
> +		}
> +		if (ret)
> +			return ret;
> +		oldconf->filter = conf->filter;
> +	}
> +
> +	return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
> +					  st->conf.temp_en, sleep_ms);
> +}

-- 
With Best Regards,
Andy Shevchenko




From andriy.shevchenko at intel.com  Tue Jun 16 03:13:03 2026
From: andriy.shevchenko at intel.com (Andy Shevchenko)
Date: Tue, 16 Jun 2026 13:13:03 +0300
Subject: [PATCH V13 8/9] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In-Reply-To: <20260615172554.160910-9-macroalpha82@gmail.com>
References: <20260615172554.160910-1-macroalpha82@gmail.com>
 <20260615172554.160910-9-macroalpha82@gmail.com>
Message-ID: <ajEhr0JIQwzRgoZa@ashevche-desk.local>

On Mon, Jun 15, 2026 at 12:25:51PM -0500, Chris Morgan wrote:

> Add gyroscope functions to the icm42607 driver.

...

> +int inv_icm42607_set_gyro_conf(struct inv_icm42607_state *st,
> +			       struct inv_icm42607_sensor_conf *conf,
> +			       unsigned int *sleep_ms)
> +{
> +	struct inv_icm42607_sensor_conf *oldconf = &st->conf.gyro;
> +	unsigned int val;
> +	int ret;
> +
> +	if (conf->mode < 0)
> +		conf->mode = oldconf->mode;
> +	if (conf->fs < 0)
> +		conf->fs = oldconf->fs;
> +	if (conf->odr < 0)
> +		conf->odr = oldconf->odr;
> +	if (conf->filter < 0)
> +		conf->filter = oldconf->filter;

Same comment as per previous patch. But looking at this, can you rather have
a helper that answers the below two questions? Something like

void _assign_conf(..., bool *write_odr, bool *write_filter)
{
	...
}
EXPORT_...

in the core driver? But wight both approaches and choose either existing one
(as in this patch series) or what I suggested.

> +	if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
> +		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK,
> +				 conf->fs);
> +		val |= FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK,
> +				  conf->odr);
> +		ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
> +		if (ret)
> +			return ret;
> +		oldconf->fs = conf->fs;
> +		oldconf->odr = conf->odr;
> +	}
> +
> +	if (conf->filter != oldconf->filter) {
> +		val = FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK,
> +				 conf->filter);
> +		ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
> +					 INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
> +		if (ret)
> +			return ret;
> +		oldconf->filter = conf->filter;
> +	}
> +
> +	return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
> +					  st->conf.temp_en, sleep_ms);
> +}

...

> +{
> +	unsigned int odr;
> +	unsigned int i;
> +
> +	guard(mutex)(&st->lock);
> +
> +	odr = st->conf.gyro.odr;
> +
> +	for (i = 5; i < ARRAY_SIZE(inv_icm42607_gyro_odr); ++i) {

Same comment, why pre-increment?

> +		if (i == odr)
> +			break;
> +	}
> +	if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr))
> +		return -EINVAL;
> +
> +	*val = inv_icm42607_gyro_odr[i][0];
> +	*val2 = inv_icm42607_gyro_odr[i][1];
> +
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}
> +
> +static int inv_icm42607_gyro_write_odr(struct iio_dev *indio_dev,
> +				       int val, int val2)
> +{
> +	struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
> +	struct device *dev = regmap_get_device(st->map);
> +	unsigned int idx;
> +	struct inv_icm42607_sensor_conf conf = INV_ICM42607_SENSOR_CONF_INIT;
> +	int ret;
> +
> +	for (idx = 5; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); ++idx) {

Ditto.

> +		if (val == inv_icm42607_gyro_odr[idx][0] &&
> +		    val2 == inv_icm42607_gyro_odr[idx][1])
> +			break;
> +	}
> +	if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
> +		return -EINVAL;
> +
> +	conf.odr = idx;
> +
> +	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> +	ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
> +	if (ret)
> +		return ret;
> +
> +	guard(mutex)(&st->lock);
> +
> +	return inv_icm42607_set_gyro_conf(st, &conf, NULL);
> +}

Can be some of the code deduplicated between gyro and accel?

-- 
With Best Regards,
Andy Shevchenko




From piotr.oniszczuk at gmail.com  Tue Jun 16 05:44:16 2026
From: piotr.oniszczuk at gmail.com (Piotr Oniszczuk)
Date: Tue, 16 Jun 2026 14:44:16 +0200
Subject: [BUG] rkvdec-vdpu383-h264: wrong pixels at horizontal de-blocking
 edges y=4 and y=12
In-Reply-To: <1f178828-2cba-4120-bc6d-bb3be7b24073@symple.nz>
References: <52a01f1f-5b36-429b-96cf-f1a0a1c8f5e4@symple.nz>
 <5939C396-3A70-458F-8E6B-A55319929564@gmail.com>
 <4b3a9f32-807a-4b9e-8df2-d22f872d288e@symple.nz>
 <2CB1844A-3DB7-4973-98E0-0C141DD38B45@gmail.com>
 <1f178828-2cba-4120-bc6d-bb3be7b24073@symple.nz>
Message-ID: <5ABBE81F-3560-402D-B9D3-94F6D9842A4B@gmail.com>



> Wiadomo?? napisana przez Simon Wright <Simon at symple.nz> w dniu 11 cze 2026, o godz. 08:15:
> 
> Hi Piotr,
> 
> Short version: the in-tree port didn't actually have the warmup running (it needs a
> probe-time buffer alloc + a pm_runtime_resume hook, not just the decode code). Rather
> than pick that apart, here's a clean patch that wires it properly - and I've now
> validated it on hardware.
> 
> The patch is self-contained and needs no devicetree change (mainline already maps the
> "link" register bank it uses); git apply-clean on 7.0 and 7.1-rc7:
> 
>    https://github.com/SympleNZ/rkvdec-vdpu383-h264-bug/tree/master/fix
> 
>     

Simon,

After multiple users tests I?m happy to confirm: with above patch applied on mainline 7.1 h264 decoder works perfectly.

So:

Tested-by: Piotr Oniszczuk <piotr.oniszczuk at gmail.com>

From geraldogabriel at gmail.com  Tue Jun 16 08:24:48 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Tue, 16 Jun 2026 12:24:48 -0300
Subject: [PATCH v7 0/3] PCI: rockchip: 5.0 GT/s speed discouraged by Rockchip
Message-ID: <cover.1781622998.git.geraldogabriel@gmail.com>

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, including data loss.

Drop all code related to 5.0 GT/s operational speed from this driver.

Endpoint Mode driver was not tested.

Changes in v7:
- In pcie-rockchip.c (PATCH 3) drop unreachable code
- Link to v6: https://lore.kernel.org/all/cover.1781207474.git.geraldogabriel at gmail.com/T/

Changes in v6:
- Squashed patches 3 & 4 together as suggested by Mani
- More formal warning message as suggested by Dragan
- Set the 2.5 GT/s bit regardless of if link-speed is set to 2
- Link to v5: https://lore.kernel.org/all/cover.1772239598.git.geraldogabriel at gmail.com/T/

Changes in v5:
- Changed commit order to not break builds and adjusted copy pasted
  commit message. (thanks Charalampos!)
- Reintroduced behavior to force 2.5 GT/s in case there's something
  non-default in the DT. (thanks Dragan!)
- Link to v4: https://lore.kernel.org/linux-rockchip/cover.1772169998.git.geraldogabriel at gmail.com/T/

Changes in v4:
- Incorporate suggestion by Bjorn and refined by Dragan to drop the
  "catastrophic" code
- Link to v3: https://lore.kernel.org/linux-rockchip/cover.1772057799.git.geraldogabriel at gmail.com/T/

Changes in v3:
- Clarify warning message even though Rockchip won't disclose details
- Drop DT changes as they were applied as subset by Heiko
- Link to v2: https://lore.kernel.org/all/cover.1763415705.git.geraldogabriel at gmail.com/T/

Changes in v2:
- hard limit to 2.5 GT/s, not just warn
- add Reported-by: and Reviewed-by: Dragan Simic
- remove redundant declaration of max-link-speed from helios64 dts
- fix Link: of helios64 patch
- simplify RC mode comment
- Link to v1: https://lore.kernel.org/all/aRhR79u5BPtRRFw3 at geday/T/

Geraldo Nascimento (3):
  PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
  PCI: rockchip-host: do not attempt 5.0 GT/s retraining
  PCI: rockchip: drive at 2.5 GT/s, error other speeds

 drivers/pci/controller/pcie-rockchip-ep.c   | 13 -------------
 drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
 drivers/pci/controller/pcie-rockchip.c      | 14 ++++++--------
 drivers/pci/controller/pcie-rockchip.h      |  3 ---
 4 files changed, 6 insertions(+), 44 deletions(-)

-- 
2.54.0



From geraldogabriel at gmail.com  Tue Jun 16 08:25:28 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Tue, 16 Jun 2026 12:25:28 -0300
Subject: [PATCH v7 1/3] PCI: rockchip-ep: do not attempt 5.0 GT/s retraining
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <d994f8fb3481bbb8f3972f117334a6e8aea383fb.1781622998.git.geraldogabriel@gmail.com>

Drop the 5.0 GT/s Link Speed retraining code block from Rockchip PCIe
EP driver. The reason is that Shawn Lin from Rockchip has reiterated
that there may be danger of "catastrophic failure" in using their PCIe
with 5.0 GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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

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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip-ep.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index 799461335762e..9ebc227a1ef84 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -553,19 +553,6 @@ static void rockchip_pcie_ep_link_training(struct work_struct *work)
 	if (ret)
 		goto again;
 
-	/*
-	 * Check the current speed: if gen2 speed was requested and we are not
-	 * at gen2 speed yet, retrain again for gen2.
-	 */
-	val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
-	if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) {
-		/* Enable retrain for gen2 */
-		rockchip_pcie_ep_retrain_link(rockchip);
-		readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
-				   val, PCIE_LINK_IS_GEN2(val), 50,
-				   LINK_TRAIN_TIMEOUT);
-	}
-
 	/* Check again that the link is up */
 	if (!rockchip_pcie_ep_link_up(rockchip))
 		goto again;
-- 
2.54.0



From geraldogabriel at gmail.com  Tue Jun 16 08:25:45 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Tue, 16 Jun 2026 12:25:45 -0300
Subject: [PATCH v7 2/3] PCI: rockchip-host: do not attempt 5.0 GT/s retraining
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <68f6353e3a2ea4914de36c42b6906e41282adad3.1781622998.git.geraldogabriel@gmail.com>

Drop the 5.0 GT/s Link Speed retraining from Rockchip PCIe Root
Complex Mode Operation, so called host driver.

The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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

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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
 1 file changed, 20 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index ee1822ca01db3..1374a2c92b563 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -328,26 +328,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
 		goto err_power_off_phy;
 	}
 
-	if (rockchip->link_gen == 2) {
-		/*
-		 * Enable retrain for gen2. This should be configured only after
-		 * gen1 finished.
-		 */
-		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
-		status &= ~PCI_EXP_LNKCTL2_TLS;
-		status |= PCI_EXP_LNKCTL2_TLS_5_0GT;
-		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
-		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
-		status |= PCI_EXP_LNKCTL_RL;
-		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
-
-		err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
-					 status, PCIE_LINK_IS_GEN2(status), 20,
-					 500 * USEC_PER_MSEC);
-		if (err)
-			dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
-	}
-
 	/* Check the final link width from negotiated lane counter from MGMT */
 	status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
 	status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>
-- 
2.54.0



From geraldogabriel at gmail.com  Tue Jun 16 08:26:10 2026
From: geraldogabriel at gmail.com (Geraldo Nascimento)
Date: Tue, 16 Jun 2026 12:26:10 -0300
Subject: [PATCH v7 3/3] PCI: rockchip: drive at 2.5 GT/s, error other speeds
In-Reply-To: <cover.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <7421df7a7b7778ee99363cccfdfabbfa8aa6ab5e.1781622998.git.geraldogabriel@gmail.com>

Configure the core to be driven at 2.5 GT/s Link Speed and ignore
any other speed with a warning. Also drop the 5.0 GT/s Link Speed
defines from Rockchip PCIe header.

The reason is that Shawn Lin from Rockchip has reiterated that there
may be danger of "catastrophic failure" in using their PCIe with
5.0 GT/s speeds.

While Rockchip has done so informally without issuing a proper errata,
and the particulars are thus unknown, this may cause data loss or
worse.

This change is corroborated by RK3399 official datasheet [1], which
states 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>
Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
---
 drivers/pci/controller/pcie-rockchip.c | 14 ++++++--------
 drivers/pci/controller/pcie-rockchip.h |  3 ---
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
index 0f88da3788054..456dcfd676ed7 100644
--- a/drivers/pci/controller/pcie-rockchip.c
+++ b/drivers/pci/controller/pcie-rockchip.c
@@ -66,8 +66,10 @@ 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, limited 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];
@@ -147,12 +149,8 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
 		goto err_exit_phy;
 	}
 
-	if (rockchip->link_gen == 2)
-		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
-				    PCIE_CLIENT_CONFIG);
-	else
-		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
-				    PCIE_CLIENT_CONFIG);
+	rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
+			    PCIE_CLIENT_CONFIG);
 
 	regs = PCIE_CLIENT_ARI_ENABLE |
 	       PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
index 3e82a69b9c006..b5da15601b585 100644
--- a/drivers/pci/controller/pcie-rockchip.h
+++ b/drivers/pci/controller/pcie-rockchip.h
@@ -42,7 +42,6 @@
 #define   PCIE_CLIENT_MODE_RC			HWORD_SET_BIT(0x0040)
 #define   PCIE_CLIENT_MODE_EP			HWORD_CLR_BIT(0x0040)
 #define   PCIE_CLIENT_GEN_SEL_1			HWORD_CLR_BIT(0x0080)
-#define   PCIE_CLIENT_GEN_SEL_2			HWORD_SET_BIT(0x0080)
 #define PCIE_CLIENT_LEGACY_INT_CTRL	(PCIE_CLIENT_BASE + 0x0c)
 #define   PCIE_CLIENT_INT_IN_ASSERT		HWORD_SET_BIT(0x0002)
 #define   PCIE_CLIENT_INT_IN_DEASSERT		HWORD_CLR_BIT(0x0002)
@@ -197,8 +196,6 @@
 	(((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY)
 #define PCIE_LINK_UP(x) \
 	(((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP)
-#define PCIE_LINK_IS_GEN2(x) \
-	(((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G)
 
 #define RC_REGION_0_ADDR_TRANS_H		0x00000000
 #define RC_REGION_0_ADDR_TRANS_L		0x00000000
-- 
2.54.0



From dsimic at manjaro.org  Tue Jun 16 12:06:53 2026
From: dsimic at manjaro.org (Dragan Simic)
Date: Tue, 16 Jun 2026 21:06:53 +0200
Subject: =?utf-8?q?Re=3A?= [PATCH v7 1/3] =?utf-8?q?PCI=3A?=
 =?utf-8?q?_rockchip-ep=3A?= do not attempt =?utf-8?q?5=2E0?= GT/s 
 retraining
In-Reply-To: <d994f8fb3481bbb8f3972f117334a6e8aea383fb.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com> <d994f8fb3481bbb8f3972f117334a6e8aea383fb.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <ee80e2c7-8327-0000-5986-e909f0a41df1@manjaro.org>

Hello Geraldo,

Thanks for the v6 and v7 of this series.

On Tuesday, June 16, 2026 17:25 CEST, Geraldo Nascimento <geraldogabriel at gmail.com> wrote:
> Drop the 5.0 GT/s Link Speed retraining code block from Rockchip PCIe
> EP driver. The reason is that Shawn Lin from Rockchip has reiterated
> that there may be danger of "catastrophic failure" in using their PCIe
> with 5.0 GT/s speeds.
> 
> While Rockchip has done so informally without issuing a proper errata,
> and the particulars are thus unknown, this may cause data loss or
> worse.
> 
> This change is corroborated by RK3399 official datasheet [1], which
> states 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
> 
> 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>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip-ep.c | 13 -------------
>  1 file changed, 13 deletions(-)
> 
> diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
> index 799461335762e..9ebc227a1ef84 100644
> --- a/drivers/pci/controller/pcie-rockchip-ep.c
> +++ b/drivers/pci/controller/pcie-rockchip-ep.c
> @@ -553,19 +553,6 @@ static void rockchip_pcie_ep_link_training(struct work_struct *work)
>  	if (ret)
>  		goto again;
>  
> -	/*
> -	 * Check the current speed: if gen2 speed was requested and we are not
> -	 * at gen2 speed yet, retrain again for gen2.
> -	 */
> -	val = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
> -	if (!PCIE_LINK_IS_GEN2(val) && rockchip->link_gen == 2) {
> -		/* Enable retrain for gen2 */
> -		rockchip_pcie_ep_retrain_link(rockchip);
> -		readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
> -				   val, PCIE_LINK_IS_GEN2(val), 50,
> -				   LINK_TRAIN_TIMEOUT);
> -	}
> -
>  	/* Check again that the link is up */
>  	if (!rockchip_pcie_ep_link_up(rockchip))
>  		goto again;

Looking good to me, so please feel free to include

Reviewed-by: Dragan Simic <dsimic at manjaro.org>



From dsimic at manjaro.org  Tue Jun 16 12:08:17 2026
From: dsimic at manjaro.org (Dragan Simic)
Date: Tue, 16 Jun 2026 21:08:17 +0200
Subject: =?utf-8?q?Re=3A?= [PATCH v7 2/3] =?utf-8?q?PCI=3A?=
 =?utf-8?q?_rockchip-host=3A?= do not attempt =?utf-8?q?5=2E0?= GT/s 
 retraining
In-Reply-To: <68f6353e3a2ea4914de36c42b6906e41282adad3.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com> <68f6353e3a2ea4914de36c42b6906e41282adad3.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <583cf740-1687-2c0c-71d0-b3f8425c17ce@manjaro.org>

Hello Geraldo,

Thanks for the v6 and v7 of this series.


On Tuesday, June 16, 2026 17:25 CEST, Geraldo Nascimento <geraldogabriel at gmail.com> wrote:
> Drop the 5.0 GT/s Link Speed retraining from Rockchip PCIe Root
> Complex Mode Operation, so called host driver.
> 
> The reason is that Shawn Lin from Rockchip has reiterated that there
> may be danger of "catastrophic failure" in using their PCIe with
> 5.0GT/s speeds.
> 
> While Rockchip has done so informally without issuing a proper errata,
> and the particulars are thus unknown, this may cause data loss or
> worse.
> 
> This change is corroborated by RK3399 official datasheet [1], which
> states 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
> 
> 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>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip-host.c | 20 --------------------
>  1 file changed, 20 deletions(-)
> 
> diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
> index ee1822ca01db3..1374a2c92b563 100644
> --- a/drivers/pci/controller/pcie-rockchip-host.c
> +++ b/drivers/pci/controller/pcie-rockchip-host.c
> @@ -328,26 +328,6 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
>  		goto err_power_off_phy;
>  	}
>  
> -	if (rockchip->link_gen == 2) {
> -		/*
> -		 * Enable retrain for gen2. This should be configured only after
> -		 * gen1 finished.
> -		 */
> -		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
> -		status &= ~PCI_EXP_LNKCTL2_TLS;
> -		status |= PCI_EXP_LNKCTL2_TLS_5_0GT;
> -		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL2);
> -		status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
> -		status |= PCI_EXP_LNKCTL_RL;
> -		rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_CR + PCI_EXP_LNKCTL);
> -
> -		err = readl_poll_timeout(rockchip->apb_base + PCIE_CORE_CTRL,
> -					 status, PCIE_LINK_IS_GEN2(status), 20,
> -					 500 * USEC_PER_MSEC);
> -		if (err)
> -			dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n");
> -	}
> -
>  	/* Check the final link width from negotiated lane counter from MGMT */
>  	status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL);
>  	status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >>

Looking good to me, so please feel free to include

Reviewed-by: Dragan Simic <dsimic at manjaro.org>



From dsimic at manjaro.org  Tue Jun 16 12:10:08 2026
From: dsimic at manjaro.org (Dragan Simic)
Date: Tue, 16 Jun 2026 21:10:08 +0200
Subject: =?utf-8?q?Re=3A?= [PATCH v7 3/3] =?utf-8?q?PCI=3A?==?utf-8?q?_rockchip=3A?= 
 drive at =?utf-8?q?2=2E5?==?utf-8?q?_GT/s=2C?= error other speeds
In-Reply-To: <7421df7a7b7778ee99363cccfdfabbfa8aa6ab5e.1781622998.git.geraldogabriel@gmail.com>
References: <cover.1781622998.git.geraldogabriel@gmail.com> <7421df7a7b7778ee99363cccfdfabbfa8aa6ab5e.1781622998.git.geraldogabriel@gmail.com>
Message-ID: <153da5a0-7d58-4e0e-6700-432e401c9048@manjaro.org>

Hello Geraldo,

Thanks for the v6 and v7 of this series.

On Tuesday, June 16, 2026 17:26 CEST, Geraldo Nascimento <geraldogabriel at gmail.com> wrote:
> Configure the core to be driven at 2.5 GT/s Link Speed and ignore
> any other speed with a warning. Also drop the 5.0 GT/s Link Speed
> defines from Rockchip PCIe header.
> 
> The reason is that Shawn Lin from Rockchip has reiterated that there
> may be danger of "catastrophic failure" in using their PCIe with
> 5.0 GT/s speeds.
> 
> While Rockchip has done so informally without issuing a proper errata,
> and the particulars are thus unknown, this may cause data loss or
> worse.
> 
> This change is corroborated by RK3399 official datasheet [1], which
> states 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>
> Signed-off-by: Geraldo Nascimento <geraldogabriel at gmail.com>
> ---
>  drivers/pci/controller/pcie-rockchip.c | 14 ++++++--------
>  drivers/pci/controller/pcie-rockchip.h |  3 ---
>  2 files changed, 6 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> index 0f88da3788054..456dcfd676ed7 100644
> --- a/drivers/pci/controller/pcie-rockchip.c
> +++ b/drivers/pci/controller/pcie-rockchip.c
> @@ -66,8 +66,10 @@ 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, limited 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];
> @@ -147,12 +149,8 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
>  		goto err_exit_phy;
>  	}
>  
> -	if (rockchip->link_gen == 2)
> -		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
> -				    PCIE_CLIENT_CONFIG);
> -	else
> -		rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
> -				    PCIE_CLIENT_CONFIG);
> +	rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1,
> +			    PCIE_CLIENT_CONFIG);
>  
>  	regs = PCIE_CLIENT_ARI_ENABLE |
>  	       PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes);
> diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
> index 3e82a69b9c006..b5da15601b585 100644
> --- a/drivers/pci/controller/pcie-rockchip.h
> +++ b/drivers/pci/controller/pcie-rockchip.h
> @@ -42,7 +42,6 @@
>  #define   PCIE_CLIENT_MODE_RC			HWORD_SET_BIT(0x0040)
>  #define   PCIE_CLIENT_MODE_EP			HWORD_CLR_BIT(0x0040)
>  #define   PCIE_CLIENT_GEN_SEL_1			HWORD_CLR_BIT(0x0080)
> -#define   PCIE_CLIENT_GEN_SEL_2			HWORD_SET_BIT(0x0080)
>  #define PCIE_CLIENT_LEGACY_INT_CTRL	(PCIE_CLIENT_BASE + 0x0c)
>  #define   PCIE_CLIENT_INT_IN_ASSERT		HWORD_SET_BIT(0x0002)
>  #define   PCIE_CLIENT_INT_IN_DEASSERT		HWORD_CLR_BIT(0x0002)
> @@ -197,8 +196,6 @@
>  	(((x) & PCIE_CORE_PL_CONF_LS_MASK) == PCIE_CORE_PL_CONF_LS_READY)
>  #define PCIE_LINK_UP(x) \
>  	(((x) & PCIE_CLIENT_LINK_STATUS_MASK) == PCIE_CLIENT_LINK_STATUS_UP)
> -#define PCIE_LINK_IS_GEN2(x) \
> -	(((x) & PCIE_CORE_PL_CONF_SPEED_MASK) == PCIE_CORE_PL_CONF_SPEED_5G)
>  
>  #define RC_REGION_0_ADDR_TRANS_H		0x00000000
>  #define RC_REGION_0_ADDR_TRANS_L		0x00000000

Looking good to me, so please feel free to include

Reviewed-by: Dragan Simic <dsimic at manjaro.org>



From vicencb at gmail.com  Tue Jun 16 16:05:27 2026
From: vicencb at gmail.com (Vicente Bergas)
Date: Wed, 17 Jun 2026 01:05:27 +0200
Subject: [REGRESSION][BISECTED] No display on rk3399-gru-kevin
Message-ID: <CAAMcf8CXfvzvEUyoASmp=6efRDNszyPJuFg0OU63Z7gT+oVQ8A@mail.gmail.com>

Hello,
there are two issues that result on a black screen on the rk3399-gru-kevin.

The first one is due to:
c8079f83e0bf312645050c17d9c87deb707369c1
gpio: rockchip: convert to dynamic GPIO base allocation

Reverting this does not fix the problem as there is a second one:
51eb548ade20158b4f4f8693a95b1f31a2480e8e
drm/bridge: analogix_dp: Apply DP helper API drm_dp_channel_eq_ok()

That second one depends on:
d84b087c7662dd65cd51b228219987c31b1cee02
drm/bridge: analogix_dp: Apply DP helper APIs to get adjusted voltages
and pre-emphasises

Reverting all three commits from v7.1 make the display work again.

Please, can this be resolved?

Regards,
  Vicente.


From michael.bommarito at gmail.com  Tue Jun 16 19:18:57 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:18:57 -0400
Subject: [PATCH v3 0/9] media: bound stateless HEVC/AV1 tile counts
Message-ID: <20260617021906.2746743-1-michael.bommarito@gmail.com>

The stateless HEVC and AV1 controls carry tile counts that several SoC
decoder drivers consume as loop bounds and array indices when laying out
fixed-size hardware descriptor buffers. std_validate_compound() does not
bound them, so a crafted HEVC PPS or AV1 frame control can drive
out-of-bounds writes and an AV1 divide-by-zero in the rkvdec, hantro,
rockchip and mediatek decoders.

  1-2  reject out-of-range HEVC and AV1 tile counts in
       std_validate_compound() (one patch per codec). For AV1 the per-
       dimension bound is V4L2_AV1_MAX_TILE_{COLS,ROWS} and the total is
       V4L2_AV1_MAX_TILE_COUNT.
  3    add <media/v4l2-hevc.h> with bounded tile-count helpers.
  4-5  use the helpers in rkvdec and hantro instead of open-coding the
       clamp; rkvdec also bails before indexing the hardware
       parameter-set table with an out-of-range HEVC PPS id.
  6    guard the rockchip VPU981 AV1 divisor against tile_cols == 0 and
       keep the descriptor writes inside the AV1_MAX_TILES buffer.
  7    reject a rockchip AV1 frame whose tile_cols * tile_rows exceeds the
       submitted tile group entry count or the AV1_MAX_TILES descriptor
       capacity, which set_tile_info() would otherwise read past or leave
       under-described while programming the larger geometry.
  8    bound the mediatek AV1 tile-start copy.
  9    KUnit coverage for the tile-count validation.

Changes since v2:
  - Split the combined HEVC+AV1 validation into one patch per codec, each
    with a single Fixes tag (Benjamin Gaignard).
  - Move the AV1 total-tile bound into validate_av1_tile_info() using the
    uAPI V4L2_AV1_MAX_TILE_COUNT, instead of clamping tile_cols/tile_rows
    in the rockchip driver, which would have corrupted the values written
    to the hardware registers (Benjamin Gaignard's NACK on v2 4/6).
  - Add <media/v4l2-hevc.h> with shared bounded tile-count helpers so
    rkvdec and hantro no longer duplicate the clamp (Benjamin Gaignard).
  - New patch 7: reject a rockchip AV1 frame that claims more tiles than
    the submitted tile group entry array holds (set_tile_info() indexes
    it by tile_cols * tile_rows) or more than AV1_MAX_TILES (the hardware
    descriptor buffer), which would otherwise leave the hardware
    programmed for more tiles than the buffer describes. mediatek already
    guards the entry count; rockchip now guards both.

checkpatch --strict: 0 errors on all nine. Patches 3 and 9 each carry one
"added file ... does MAINTAINERS need updating?" warning for the new
<media/v4l2-hevc.h> and the KUnit test file; both already fall under the
existing include/media/ and drivers/media/v4l2-core/ MAINTAINERS entries,
so no MAINTAINERS change is needed. (checkpatch's SPDX sub-check did not
run in my environment -- spdxcheck.py needs python3-ply -- but the SPDX
headers are present on both new files.)

The tile-count validation is exercised with KUnit (patch 9): in-range
HEVC/AV1 counts pass, out-of-range per-dimension counts and an AV1 grid
whose product exceeds V4L2_AV1_MAX_TILE_COUNT are rejected, and the
zero-initialised AV1 frame control that v4l2-compliance and existing
userspace submit still passes.

v2: https://lore.kernel.org/all/20260614155609.3107600-1-michael.bommarito at gmail.com/

Michael Bommarito (9):
  media: v4l2-ctrls: validate HEVC tile counts
  media: v4l2-ctrls: validate AV1 tile counts
  media: hevc: add bounded tile-count helpers
  media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
  media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer
    capacity
  media: verisilicon: rockchip: guard VPU981 AV1 divisor and tile buffer
  media: verisilicon: rockchip: reject AV1 frames exceeding the tile
    capacity
  media: mediatek: vcodec: bound AV1 tile-start copy to the array
    capacity
  media: v4l2-ctrls: add KUnit tests for compound control tile
    validation

 .../vcodec/decoder/vdec/vdec_av1_req_lat_if.c |   5 +-
 .../rockchip/rkvdec/rkvdec-hevc-common.c      |  14 +-
 .../platform/rockchip/rkvdec/rkvdec-hevc.c    |   7 +-
 .../rockchip/rkvdec/rkvdec-vdpu381-hevc.c     |   2 +
 .../platform/verisilicon/hantro_g2_hevc_dec.c |   6 +-
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  |  57 +++++--
 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 145 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |  36 +++++
 include/media/v4l2-hevc.h                     |  41 +++++
 10 files changed, 306 insertions(+), 19 deletions(-)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c
 create mode 100644 include/media/v4l2-hevc.h


base-commit: e24a98d6884a6e4203a77a94f070a59fcab95208
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:18:58 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:18:58 -0400
Subject: [PATCH v3 1/9] media: v4l2-ctrls: validate HEVC tile counts
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-2-michael.bommarito@gmail.com>

The stateless HEVC decoders read num_tile_columns_minus1 + 1 entries from
column_width_minus1[] and num_tile_rows_minus1 + 1 from row_height_minus1[]
and use them as tile-loop bounds, but std_validate_compound() does not
bound these u8 counts. Reject a V4L2_CTRL_TYPE_HEVC_PPS with tiling
enabled whose tile counts exceed the uAPI array capacity, mirroring the
existing compound-control range checks.

Fixes: 256fa3920874 ("media: v4l: Add definitions for HEVC stateless decoding")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6b375720e395c..6d478e1a5ef22 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -1242,6 +1242,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
 
 			p_hevc_pps->flags &=
 				~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+		} else {
+			/*
+			 * These count the entries the stateless HEVC drivers
+			 * read from column_width_minus1[] / row_height_minus1[]
+			 * and use as tile-loop bounds.
+			 */
+			if (p_hevc_pps->num_tile_columns_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->column_width_minus1))
+				return -EINVAL;
+			if (p_hevc_pps->num_tile_rows_minus1 >=
+			    ARRAY_SIZE(p_hevc_pps->row_height_minus1))
+				return -EINVAL;
 		}
 
 		if (p_hevc_pps->flags &
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:18:59 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:18:59 -0400
Subject: [PATCH v3 2/9] media: v4l2-ctrls: validate AV1 tile counts
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-3-michael.bommarito@gmail.com>

The stateless AV1 decoders use tile_info.tile_cols and tile_rows as loop
bounds and as indices into the mi_*_starts[] and *_in_sbs_minus_1[]
arrays, as the divisor for context_update_tile_id, and their product
bounds the per-tile descriptor buffers, but std_validate_compound() does
not bound these u8 fields. Reject a V4L2_CTRL_TYPE_AV1_FRAME whose
tile_cols or tile_rows exceeds V4L2_AV1_MAX_TILE_COLS / _ROWS, or whose
product exceeds V4L2_AV1_MAX_TILE_COUNT. A zero tile count is left to the
consuming driver so the zero-initialised control that existing userspace
submits is still accepted.

Fixes: 9de30f579980 ("media: Add AV1 uAPI")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 drivers/media/v4l2-core/v4l2-ctrls-core.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6d478e1a5ef22..fb20ad13dfec7 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -790,10 +790,30 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
 	return 0;
 }
 
+static int validate_av1_tile_info(struct v4l2_av1_tile_info *t)
+{
+	/*
+	 * tile_cols and tile_rows index the per-tile descriptor arrays and
+	 * bound the tile loops in the stateless AV1 drivers; the product
+	 * bounds the total tile descriptor count.
+	 */
+	if (t->tile_cols > V4L2_AV1_MAX_TILE_COLS ||
+	    t->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
+		return -EINVAL;
+
+	if ((u32)t->tile_cols * t->tile_rows > V4L2_AV1_MAX_TILE_COUNT)
+		return -EINVAL;
+
+	return 0;
+}
+
 static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
 {
 	int ret = 0;
 
+	ret = validate_av1_tile_info(&f->tile_info);
+	if (ret)
+		return ret;
 	ret = validate_av1_quantization(&f->quantization);
 	if (ret)
 		return ret;
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:00 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:00 -0400
Subject: [PATCH v3 3/9] media: hevc: add bounded tile-count helpers
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-4-michael.bommarito@gmail.com>

The stateless HEVC decoders compute the number of tile columns and rows
from num_tile_columns_minus1 / num_tile_rows_minus1 and clamp it to the
column_width_minus1[] / row_height_minus1[] capacity before using it as a
loop bound. Add shared helpers in a new <media/v4l2-hevc.h> so the rkvdec
and hantro drivers do not each open-code the min_t() clamp.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 include/media/v4l2-hevc.h | 41 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 include/media/v4l2-hevc.h

diff --git a/include/media/v4l2-hevc.h b/include/media/v4l2-hevc.h
new file mode 100644
index 0000000000000..973c96be16be4
--- /dev/null
+++ b/include/media/v4l2-hevc.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Helper functions for HEVC stateless codecs.
+ */
+
+#ifndef _MEDIA_V4L2_HEVC_H
+#define _MEDIA_V4L2_HEVC_H
+
+#include <linux/minmax.h>
+#include <media/v4l2-ctrls.h>
+
+/**
+ * v4l2_hevc_pps_num_tile_columns - number of HEVC tile columns, bounded
+ * @pps: the V4L2 HEVC PPS control
+ *
+ * Return the number of tile columns (num_tile_columns_minus1 + 1) clamped to
+ * the capacity of column_width_minus1[]. The control validation already
+ * rejects out-of-range counts; this keeps the consuming drivers bounded too.
+ */
+static inline unsigned int
+v4l2_hevc_pps_num_tile_columns(const struct v4l2_ctrl_hevc_pps *pps)
+{
+	return min_t(unsigned int, pps->num_tile_columns_minus1 + 1,
+		     ARRAY_SIZE(pps->column_width_minus1));
+}
+
+/**
+ * v4l2_hevc_pps_num_tile_rows - number of HEVC tile rows, bounded
+ * @pps: the V4L2 HEVC PPS control
+ *
+ * Return the number of tile rows (num_tile_rows_minus1 + 1) clamped to the
+ * capacity of row_height_minus1[].
+ */
+static inline unsigned int
+v4l2_hevc_pps_num_tile_rows(const struct v4l2_ctrl_hevc_pps *pps)
+{
+	return min_t(unsigned int, pps->num_tile_rows_minus1 + 1,
+		     ARRAY_SIZE(pps->row_height_minus1));
+}
+
+#endif /* _MEDIA_V4L2_HEVC_H */
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:01 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:01 -0400
Subject: [PATCH v3 4/9] media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-5-michael.bommarito@gmail.com>

compute_tiles_uniform() and compute_tiles_non_uniform() loop over
num_tile_columns_minus1 + 1 / num_tile_rows_minus1 + 1 entries, and
assemble_hw_pps() writes one COLUMN_WIDTH / ROW_HEIGHT register per tile
and indexes priv_tbl->param_set[] by pic_parameter_set_id, all taken from
the untrusted PPS. Use the bounded v4l2_hevc_pps_num_tile_columns() /
v4l2_hevc_pps_num_tile_rows() helpers for the tile loops, and bail out of
assemble_hw_pps() before indexing priv_tbl->param_set[] with an
out-of-range pic_parameter_set_id, so the writes stay within the hardware
tables.

Fixes: 3595375c2301 ("media: rkvdec: Add HEVC backend")
Fixes: c9a59dc2acc7 ("media: rkvdec: Add HEVC support for the VDPU381 variant")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 .../platform/rockchip/rkvdec/rkvdec-hevc-common.c  | 14 ++++++++++----
 .../media/platform/rockchip/rkvdec/rkvdec-hevc.c   |  7 +++++--
 .../platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c |  2 ++
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 3119f3bc9f98b..753aef3aee51e 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -16,6 +16,7 @@
  */
 
 #include <linux/v4l2-common.h>
+#include <media/v4l2-hevc.h>
 #include <media/v4l2-mem2mem.h>
 
 #include "rkvdec.h"
@@ -37,15 +38,17 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
 			   s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
+	unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+	for (i = 0; i < num_cols; 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++)
+	for (i = 0; i < num_rows; i++)
 		row_height[i] = ((i + 1) * pic_in_cts_height) /
 				(pps->num_tile_rows_minus1 + 1) -
 				(i * pic_in_cts_height) /
@@ -57,17 +60,20 @@ 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)
 {
 	const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+	unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
+	unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
 	s32 sum = 0;
 	int i;
 
-	for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+	/* The last tile entry is written after the loop, so iterate one less. */
+	for (i = 0; i < num_cols - 1; 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++) {
+	for (i = 0; i < num_rows - 1; i++) {
 		row_height[i] = pps->row_height_minus1[i] + 1;
 		sum += row_height[i];
 	}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index ac8b825d080a2..568746dae9a61 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -12,6 +12,7 @@
  *	Jeffy Chen <jeffy.chen at rock-chips.com>
  */
 
+#include <media/v4l2-hevc.h>
 #include <media/v4l2-mem2mem.h>
 
 #include "rkvdec.h"
@@ -156,6 +157,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
@@ -274,9 +277,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 
 	if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
 		/* Userspace also provide column width and row height for uniform spacing */
-		for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+		for (i = 0; i < v4l2_hevc_pps_num_tile_columns(pps); i++)
 			WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i));
-		for (i = 0; i <= pps->num_tile_rows_minus1; i++)
+		for (i = 0; i < v4l2_hevc_pps_num_tile_rows(pps); i++)
 			WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i));
 	} else {
 		WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index fe6414a175510..6dafa1dd28507 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
 	 * packet unit). so the driver copy SPS/PPS information to the exact PPS
 	 * packet unit for HW accessing.
 	 */
+	if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+		return;
 	hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
 	memset(hw_ps, 0, sizeof(*hw_ps));
 
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:02 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:02 -0400
Subject: [PATCH v3 5/9] media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer capacity
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-6-michael.bommarito@gmail.com>

prepare_tile_info_buffer() writes one entry per tile into the tile_sizes
DMA buffer, sized for a grid equal to the PPS uAPI array capacity. Use the
bounded v4l2_hevc_pps_num_tile_columns() / v4l2_hevc_pps_num_tile_rows()
helpers so the loops stay inside the buffer.

Fixes: cb5dd5a0fa51 ("media: hantro: Introduce G2/HEVC decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
index e8c2e83379def..e7a7c7a42467a 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
@@ -5,6 +5,8 @@
  * Copyright (C) 2020 Safran Passenger Innovations LLC
  */
 
+#include <media/v4l2-hevc.h>
+
 #include "hantro_hw.h"
 #include "hantro_g2_regs.h"
 
@@ -15,8 +17,8 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
 	const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
 	const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
 	u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu);
-	unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1;
-	unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+	unsigned int num_tile_rows = v4l2_hevc_pps_num_tile_rows(pps);
+	unsigned int num_tile_cols = v4l2_hevc_pps_num_tile_columns(pps);
 	unsigned int pic_width_in_ctbs, pic_height_in_ctbs;
 	unsigned int max_log2_ctb_size, ctb_size;
 	bool tiles_enabled, uniform_spacing;
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:03 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:03 -0400
Subject: [PATCH v3 6/9] media: verisilicon: rockchip: guard VPU981 AV1 divisor and tile buffer
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-7-michael.bommarito@gmail.com>

rockchip_vpu981_av1_dec_set_tile_info() divides context_update_tile_id by
tile_info->tile_cols and writes one descriptor per tile into the tile_info
DMA buffer, which holds AV1_MAX_TILES entries; tile_cols and tile_rows
come from the bitstream. Guard the division against a zero tile_cols by
initialising the context-update values to zero and computing them only
when tile_cols is non-zero, and stop the descriptor writes once the
tile_info buffer is full. The tile geometry written to the hardware
registers is left unmodified; the per-dimension and total tile bounds are
enforced by the control validation.

Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 32 +++++++++++++++----
 1 file changed, 26 insertions(+), 6 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 e4e21ad373233..fd00dbd79fe46 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -578,16 +578,30 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
 	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
 	const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
 	    ctrls->tile_group_entry;
-	int context_update_y =
-	    tile_info->context_update_tile_id / tile_info->tile_cols;
-	int context_update_x =
-	    tile_info->context_update_tile_id % tile_info->tile_cols;
-	int context_update_tile_id =
-	    context_update_x * tile_info->tile_rows + context_update_y;
+	int context_update_y = 0;
+	int context_update_x = 0;
+	int context_update_tile_id = 0;
 	u8 *dst = av1_dec->tile_info.cpu;
+	u8 *dst_end = dst + av1_dec->tile_info.size;
 	struct hantro_dev *vpu = ctx->dev;
 	int tile0, tile1;
 
+	/*
+	 * tile_cols and tile_rows are bounded by the V4L2 control validation
+	 * (V4L2_AV1_MAX_TILE_{COLS,ROWS} and V4L2_AV1_MAX_TILE_COUNT). Guard
+	 * the divisor here, and keep the descriptor writes within the
+	 * AV1_MAX_TILES tile_info buffer below; the register values use the
+	 * unmodified tile geometry.
+	 */
+	if (tile_info->tile_cols) {
+		context_update_y =
+		    tile_info->context_update_tile_id / tile_info->tile_cols;
+		context_update_x =
+		    tile_info->context_update_tile_id % tile_info->tile_cols;
+		context_update_tile_id =
+		    context_update_x * tile_info->tile_rows + context_update_y;
+	}
+
 	memset(dst, 0, av1_dec->tile_info.size);
 
 	for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
@@ -598,6 +612,10 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
 			    tile_info->height_in_sbs_minus_1[tile1] + 1;
 			u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
 
+			/* Stop once the tile_info descriptor buffer is full. */
+			if (dst + 16 > dst_end)
+				break;
+
 			/* tile size in SB units (width,height) */
 			*dst++ = x0;
 			*dst++ = 0;
@@ -622,6 +640,8 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
 			*dst++ = (end >> 16) & 255;
 			*dst++ = (end >> 24) & 255;
 		}
+		if (dst + 16 > dst_end)
+			break;
 	}
 
 	hantro_reg_write(vpu, &av1_multicore_expect_context_update, !!(context_update_x == 0));
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:04 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:04 -0400
Subject: [PATCH v3 7/9] media: verisilicon: rockchip: reject AV1 frames exceeding the tile capacity
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-8-michael.bommarito@gmail.com>

rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group entry
array by tile1 * tile_cols + tile0, reading up to tile_cols * tile_rows
entries, lays out one descriptor per tile in the AV1_MAX_TILES tile_info
buffer, and programs the real tile_cols / tile_rows into the hardware.

The tile group entry control is a dynamic array sized to the number of
entries userspace submitted, independent of tile_cols / tile_rows, so a
frame that claims more tiles than entries reads past the array. A frame
that claims more than AV1_MAX_TILES tiles also leaves the hardware
programmed for more tiles than the descriptor buffer holds.

Reject both in prepare_run(): tile_cols * tile_rows must not exceed the
submitted entry count or AV1_MAX_TILES. The entry count is read via
v4l2_ctrl_find() (ctrl->elems). This mirrors the bound the mediatek AV1
decoder already enforces.

Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 25 ++++++++++++++++---
 1 file changed, 22 insertions(+), 3 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 fd00dbd79fe46..00aa566a4ccdb 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -431,20 +431,39 @@ static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx)
 {
 	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
 	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+	const struct v4l2_av1_tile_info *tile_info;
+	struct v4l2_ctrl *tge;
+	u32 num_tiles;
 
 	ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
 	if (WARN_ON(!ctrls->sequence))
 		return -EINVAL;
 
-	ctrls->tile_group_entry =
-	    hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
-	if (WARN_ON(!ctrls->tile_group_entry))
+	tge = v4l2_ctrl_find(&ctx->ctrl_handler,
+			     V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
+	if (WARN_ON(!tge))
 		return -EINVAL;
+	ctrls->tile_group_entry = tge->p_cur.p;
 
 	ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
 	if (WARN_ON(!ctrls->frame))
 		return -EINVAL;
 
+	/*
+	 * rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group
+	 * entry array by tile1 * tile_cols + tile0, so it reads up to
+	 * tile_cols * tile_rows entries, and lays out one descriptor per tile
+	 * in the AV1_MAX_TILES tile_info buffer while programming the real
+	 * tile geometry into the hardware. Reject a frame that claims more
+	 * tiles than userspace submitted, or more than the hardware tile
+	 * buffer holds, so the read stays in bounds and the programmed
+	 * geometry matches the descriptors written.
+	 */
+	tile_info = &ctrls->frame->tile_info;
+	num_tiles = (u32)tile_info->tile_cols * tile_info->tile_rows;
+	if (num_tiles > tge->elems || num_tiles > AV1_MAX_TILES)
+		return -EINVAL;
+
 	ctrls->film_grain =
 	    hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
 
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:05 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:05 -0400
Subject: [PATCH v3 8/9] media: mediatek: vcodec: bound AV1 tile-start copy to the array capacity
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-9-michael.bommarito@gmail.com>

vdec_av1_slice_setup_tile() copies tile_cols + 1 / tile_rows + 1 entries
into mi_col_starts[] / mi_row_starts[] from the bitstream tile_info. Bound
the copy to the array capacity.

Fixes: 0934d3759615 ("media: mediatek: vcodec: separate decoder and encoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 .../mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c       | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 2d622e85f8271..49d9b4a72387e 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame,
 	tile->uniform_tile_spacing_flag =
 		BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING);
 
-	for (i = 0; i < tile->tile_cols + 1; i++)
+	/* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */
+	for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++)
 		tile->mi_col_starts[i] =
 			ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 
-	for (i = 0; i < tile->tile_rows + 1; i++)
+	for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++)
 		tile->mi_row_starts[i] =
 			ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
 }
-- 
2.53.0



From michael.bommarito at gmail.com  Tue Jun 16 19:19:06 2026
From: michael.bommarito at gmail.com (Michael Bommarito)
Date: Tue, 16 Jun 2026 22:19:06 -0400
Subject: [PATCH v3 9/9] media: v4l2-ctrls: add KUnit tests for compound control tile validation
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
References: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Message-ID: <20260617021906.2746743-10-michael.bommarito@gmail.com>

Add KUnit coverage for the HEVC and AV1 tile-count checks in
std_validate_compound(): in-range counts pass, out-of-range per-dimension
counts and an AV1 grid whose product exceeds V4L2_AV1_MAX_TILE_COUNT are
rejected, and the zero-initialised AV1 frame control that userspace
submits still passes.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito at gmail.com>
---
 drivers/media/v4l2-core/Kconfig               |  12 ++
 .../media/v4l2-core/v4l2-ctrls-core-test.c    | 145 ++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ctrls-core.c     |   4 +
 3 files changed, 161 insertions(+)
 create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c

diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index d50ccac9733cc..52c00dfe9322f 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -3,6 +3,18 @@
 # Generic video config states
 #
 
+config V4L2_CTRLS_KUNIT_TEST
+	bool "KUnit tests for V4L2 compound control validation" if !KUNIT_ALL_TESTS
+	depends on VIDEO_DEV && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  This builds KUnit tests for the stateless-codec compound control
+	  validation in std_validate_compound(). They check that out-of-range
+	  HEVC and AV1 tile counts are rejected before the stateless decoders
+	  consume them as loop bounds and array indices.
+
+	  If unsure, say N.
+
 config VIDEO_V4L2_I2C
 	bool
 	depends on I2C && VIDEO_DEV
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core-test.c b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
new file mode 100644
index 0000000000000..c0141f3defa82
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for HEVC/AV1 tile-count validation in std_validate_compound().
+ * #included at the end of v4l2-ctrls-core.c to reach the static helper.
+ */
+
+#include <kunit/test.h>
+
+static int call_validate_compound(enum v4l2_ctrl_type type, void *payload,
+				  u32 elem_size)
+{
+	struct v4l2_ctrl ctrl = {
+		.type = type,
+		.elem_size = elem_size,
+	};
+	union v4l2_ctrl_ptr ptr = { .p = payload };
+
+	return std_validate_compound(&ctrl, 0, ptr);
+}
+
+/* HEVC PPS: num_tile_columns_minus1 / num_tile_rows_minus1 bounds. */
+static void v4l2_ctrls_hevc_pps_tile_cols(struct kunit *test)
+{
+	struct v4l2_ctrl_hevc_pps *pps;
+
+	pps = kunit_kzalloc(test, sizeof(*pps), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, pps);
+
+	pps->flags = V4L2_HEVC_PPS_FLAG_TILES_ENABLED;
+
+	/* In range: count == array capacity (minus1 == capacity - 1). */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1) - 1;
+	pps->num_tile_rows_minus1 = ARRAY_SIZE(pps->row_height_minus1) - 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			0);
+
+	/* Out of range: one past the column array. */
+	pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1);
+	pps->num_tile_rows_minus1 = 0;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	pps->num_tile_columns_minus1 = 0xff;
+	pps->num_tile_rows_minus1 = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+					       sizeof(*pps)),
+			-EINVAL);
+}
+
+/* AV1 frame: tile_cols / tile_rows upper bounds. */
+static void v4l2_ctrls_av1_frame_tile(struct kunit *test)
+{
+	struct v4l2_ctrl_av1_frame *f;
+
+	f = kunit_kzalloc(test, sizeof(*f), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, f);
+
+	/*
+	 * Benign control: a zero-initialised frame (tile_cols == 0) must
+	 * still pass. Userspace and v4l2-compliance set the zeroed default,
+	 * and the divisor that a zero tile_cols would feed is guarded in the
+	 * consuming driver rather than rejected here.
+	 */
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/* In range: a 1x1 tiling. */
+	f->tile_info.tile_cols = 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/*
+	 * In range: total tiles == V4L2_AV1_MAX_TILE_COUNT with each
+	 * dimension at or below its per-dimension maximum (64 * 8 == 512).
+	 */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_COUNT / V4L2_AV1_MAX_TILE_COLS;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			0);
+
+	/*
+	 * Out of range: each dimension is legal on its own but the product
+	 * exceeds V4L2_AV1_MAX_TILE_COUNT (64 * 64 == 4096 > 512), which would
+	 * overflow the per-tile descriptor buffers.
+	 */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: tile_cols past the array. */
+	f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS + 1;
+	f->tile_info.tile_rows = 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: maximal attacker value. */
+	f->tile_info.tile_cols = 0xff;
+	f->tile_info.tile_rows = 0xff;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+
+	/* Out of range: tile_rows past the array. */
+	f->tile_info.tile_cols = 1;
+	f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS + 1;
+	KUNIT_EXPECT_EQ(test,
+			call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+					       sizeof(*f)),
+			-EINVAL);
+}
+
+static struct kunit_case v4l2_ctrls_test_cases[] = {
+	KUNIT_CASE(v4l2_ctrls_hevc_pps_tile_cols),
+	KUNIT_CASE(v4l2_ctrls_av1_frame_tile),
+	{}
+};
+
+static struct kunit_suite v4l2_ctrls_test_suite = {
+	.name = "v4l2-ctrls-compound",
+	.test_cases = v4l2_ctrls_test_cases,
+};
+
+kunit_test_suite(v4l2_ctrls_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for V4L2 stateless-codec compound control validation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index fb20ad13dfec7..1409b06eee0a8 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -2860,3 +2860,7 @@ int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
 	return hdl->error;
 }
 EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
+
+#if IS_ENABLED(CONFIG_V4L2_CTRLS_KUNIT_TEST)
+#include "v4l2-ctrls-core-test.c"
+#endif
-- 
2.53.0



From damon.ding at rock-chips.com  Wed Jun 17 00:30:22 2026
From: damon.ding at rock-chips.com (Damon Ding)
Date: Wed, 17 Jun 2026 15:30:22 +0800
Subject: [REGRESSION][BISECTED] No display on rk3399-gru-kevin
In-Reply-To: <CAAMcf8CXfvzvEUyoASmp=6efRDNszyPJuFg0OU63Z7gT+oVQ8A@mail.gmail.com>
References: <CAAMcf8CXfvzvEUyoASmp=6efRDNszyPJuFg0OU63Z7gT+oVQ8A@mail.gmail.com>
Message-ID: <5799c8e2-fc95-4a53-98d7-0b6caacc05af@rock-chips.com>

Hi Vicente,

On 6/17/2026 7:05 AM, Vicente Bergas wrote:
> Hello,
> there are two issues that result on a black screen on the rk3399-gru-kevin.
> 
> The first one is due to:
> c8079f83e0bf312645050c17d9c87deb707369c1
> gpio: rockchip: convert to dynamic GPIO base allocation
> 
> Reverting this does not fix the problem as there is a second one:
> 51eb548ade20158b4f4f8693a95b1f31a2480e8e
> drm/bridge: analogix_dp: Apply DP helper API drm_dp_channel_eq_ok()
> 
> That second one depends on:
> d84b087c7662dd65cd51b228219987c31b1cee02
> drm/bridge: analogix_dp: Apply DP helper APIs to get adjusted voltages
> and pre-emphasises
> 
> Reverting all three commits from v7.1 make the display work again.
> 
> Please, can this be resolved?
> 

These two issues appear to come from entirely distinct subsystems. Could 
you share the related error logs so I can analyze them further?

Additionally, I will set up an RK3399 EVB1 environment locally to 
reproduce and verify this issue later.

Best regards,
Damon



From heiko at sntech.de  Wed Jun 17 01:45:54 2026
From: heiko at sntech.de (Heiko =?UTF-8?B?U3TDvGJuZXI=?=)
Date: Wed, 17 Jun 2026 10:45:54 +0200
Subject: [REGRESSION][BISECTED] No display on rk3399-gru-kevin
In-Reply-To: <CAAMcf8CXfvzvEUyoASmp=6efRDNszyPJuFg0OU63Z7gT+oVQ8A@mail.gmail.com>
References: <CAAMcf8CXfvzvEUyoASmp=6efRDNszyPJuFg0OU63Z7gT+oVQ8A@mail.gmail.com>
Message-ID: <14488973.RDIVbhacDa@diego>

Hi Vicente,

Am Mittwoch, 17. Juni 2026, 01:05:27 Mitteleurop?ische Sommerzeit schrieb Vicente Bergas:
> Hello,
> there are two issues that result on a black screen on the rk3399-gru-kevin.
> 
> The first one is due to:
> c8079f83e0bf312645050c17d9c87deb707369c1
> gpio: rockchip: convert to dynamic GPIO base allocation

can you check that your kernel contains
"gpio: rockchip: Fix GPIO regression after conversion to dynamic base allocation"
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=5cd9c6d332f46d1de8b68117fe2a3f1b08ee80ff


> Reverting this does not fix the problem as there is a second one:
> 51eb548ade20158b4f4f8693a95b1f31a2480e8e
> drm/bridge: analogix_dp: Apply DP helper API drm_dp_channel_eq_ok()
> 
> That second one depends on:
> d84b087c7662dd65cd51b228219987c31b1cee02
> drm/bridge: analogix_dp: Apply DP helper APIs to get adjusted voltages
> and pre-emphasises
> 
> Reverting all three commits from v7.1 make the display work again.
> 
> Please, can this be resolved?

and as Damon wrote, please provide logs, so we can see the actual problem


Thanks
Heiko




