[PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers

Andy Yan posted 1 patch 2 months, 3 weeks ago
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++---
1 file changed, 42 insertions(+), 7 deletions(-)
[PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
Posted by Andy Yan 2 months, 3 weeks ago
From: Andy Yan <andy.yan@rock-chips.com>

When there are multiple Video Ports, and only one of them is working
(for example, VP1 is working while VP0 is not), in this case, the
win_mask of VP0 is 0. However, we have already set the port mux for VP0
according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
register, there are windows will also be assigned to layers which will
map to the inactive VPs. In this situation, vp0->win_mask is zero as it
now working, it is more reliable to calculate the used layers based on
the configuration of the OVL_LAYER_SEL register.

Note: as the configuration of OVL_LAYER_SEL is take effect when the
vsync is come, so we use the value backup in vop2->old_layer_sel instead
of read OVL_LAYER_SEL directly.

Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
Reported-by: Diederik de Haas <diederik@cknow-tech.com>
Closes: https://bugs.kde.org/show_bug.cgi?id=511274
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
---

 drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++---
 1 file changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
index d22ce11a4235..f3950e8476a7 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = {
 	},
 };
 
+/*
+ * phys_id is used to identify a main window(Cluster Win/Smart Win, not
+ * include the sub win of a cluster or the multi area) that can do overlay
+ * in main overlay stage.
+ */
+static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id)
+{
+	struct vop2_win *win;
+	int i;
+
+	for (i = 0; i < vop2->data->win_size; i++) {
+		win = &vop2->win[i];
+		if (win->data->phys_id == phys_id)
+			return win;
+	}
+
+	return NULL;
+}
+
 static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
 {
 	struct vop2 *vop2 = vp->vop2;
@@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
 	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
 }
 
-static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
+static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp)
 {
-	struct vop2_video_port *vp;
-	int used_layer = 0;
+	struct vop2 *vop2 = vp->vop2;
+	struct vop2_win *win;
+	u32 layer_sel = vop2->old_layer_sel;
+	u32 used_layer = 0;
+	unsigned long win_mask = vp->win_mask;
+	unsigned long phys_id;
+	bool match;
 	int i;
 
-	for (i = 0; i < port_id; i++) {
-		vp = &vop2->vps[i];
-		used_layer += hweight32(vp->win_mask);
+	for (i = 0; i < 31; i += 4) {
+		match = false;
+		for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) {
+			win = vop2_find_win_by_phys_id(vop2, phys_id);
+			if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) {
+				match = true;
+				break;
+			}
+		}
+
+		if (!match)
+			used_layer += 1;
+		else
+			break;
 	}
 
 	return used_layer;
@@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
 	u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
 
 	if (vop2->version <= VOP_VERSION_RK3588)
-		mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
+		mixer_id = vop2_find_start_mixer_id_for_vp(vp);
 	else
 		mixer_id = 0;
 
-- 
2.43.0

base-commit: ded94ec6167e84195507237100f6278941e36fdd
branch: drm-misc-next-2025-1016
Re: [PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
Posted by Heiko Stuebner 2 months, 3 weeks ago
On Wed, 12 Nov 2025 16:50:23 +0800, Andy Yan wrote:
> When there are multiple Video Ports, and only one of them is working
> (for example, VP1 is working while VP0 is not), in this case, the
> win_mask of VP0 is 0. However, we have already set the port mux for VP0
> according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
> register, there are windows will also be assigned to layers which will
> map to the inactive VPs. In this situation, vp0->win_mask is zero as it
> now working, it is more reliable to calculate the used layers based on
> the configuration of the OVL_LAYER_SEL register.
> 
> [...]

Applied, thanks!

[1/1] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
      commit: d3fe9aa495854f8d88c69c41a4b31e69424656ad

Best regards,
-- 
Heiko Stuebner <heiko@sntech.de>
Re: [PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
Posted by Dang Huynh 2 months, 3 weeks ago
Hi Andy,

This fix works on my device. No more black box around the cursor.

Tested-by: Dang Huynh <dang.huynh@mainlining.org>

On Wed, Nov 12, 2025 at 04:50:23PM +0800, Andy Yan wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
> 
> When there are multiple Video Ports, and only one of them is working
> (for example, VP1 is working while VP0 is not), in this case, the
> win_mask of VP0 is 0. However, we have already set the port mux for VP0
> according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
> register, there are windows will also be assigned to layers which will
> map to the inactive VPs. In this situation, vp0->win_mask is zero as it
> now working, it is more reliable to calculate the used layers based on
> the configuration of the OVL_LAYER_SEL register.
> 
> Note: as the configuration of OVL_LAYER_SEL is take effect when the
> vsync is come, so we use the value backup in vop2->old_layer_sel instead
> of read OVL_LAYER_SEL directly.
> 
> Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
> Reported-by: Diederik de Haas <diederik@cknow-tech.com>
> Closes: https://bugs.kde.org/show_bug.cgi?id=511274
> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> ---
> 
>  drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++---
>  1 file changed, 42 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index d22ce11a4235..f3950e8476a7 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = {
>  	},
>  };
>  
> +/*
> + * phys_id is used to identify a main window(Cluster Win/Smart Win, not
> + * include the sub win of a cluster or the multi area) that can do overlay
> + * in main overlay stage.
> + */
> +static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id)
> +{
> +	struct vop2_win *win;
> +	int i;
> +
> +	for (i = 0; i < vop2->data->win_size; i++) {
> +		win = &vop2->win[i];
> +		if (win->data->phys_id == phys_id)
> +			return win;
> +	}
> +
> +	return NULL;
> +}
> +
>  static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
>  {
>  	struct vop2 *vop2 = vp->vop2;
> @@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
>  	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
>  }
>  
> -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
> +static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp)
>  {
> -	struct vop2_video_port *vp;
> -	int used_layer = 0;
> +	struct vop2 *vop2 = vp->vop2;
> +	struct vop2_win *win;
> +	u32 layer_sel = vop2->old_layer_sel;
> +	u32 used_layer = 0;
> +	unsigned long win_mask = vp->win_mask;
> +	unsigned long phys_id;
> +	bool match;
>  	int i;
>  
> -	for (i = 0; i < port_id; i++) {
> -		vp = &vop2->vps[i];
> -		used_layer += hweight32(vp->win_mask);
> +	for (i = 0; i < 31; i += 4) {
> +		match = false;
> +		for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) {
> +			win = vop2_find_win_by_phys_id(vop2, phys_id);
> +			if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) {
> +				match = true;
> +				break;
> +			}
> +		}
> +
> +		if (!match)
> +			used_layer += 1;
> +		else
> +			break;
>  	}
>  
>  	return used_layer;
> @@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
>  	u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
>  
>  	if (vop2->version <= VOP_VERSION_RK3588)
> -		mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
> +		mixer_id = vop2_find_start_mixer_id_for_vp(vp);
>  	else
>  		mixer_id = 0;
>  
> -- 
> 2.43.0
> 
> base-commit: ded94ec6167e84195507237100f6278941e36fdd
> branch: drm-misc-next-2025-1016
> 
> 
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
Re: [PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
Posted by Diederik de Haas 2 months, 3 weeks ago
On Thu Nov 13, 2025 at 9:11 AM CET, Dang Huynh wrote:
> Hi Andy,
>
> This fix works on my device. No more black box around the cursor.
>
> Tested-by: Dang Huynh <dang.huynh@mainlining.org>

Thanks for testing and your Tested-by tag :-D

FYI: Apparently something went wrong with delivery it as it only arrived
at LKML, but not dri-devel, linux-arm-kernel or linux-rockchip MLs.
No idea if that's problematic (for b4 f.e.) though.

'lore' has it here:
https://lore.kernel.org/all/hrg6geclph37olvqr3o5v4d4mifvl25kaemh7f2z3hwega7h2b@muf2gkfqzvvz/

Cheers,
 Diederik

> On Wed, Nov 12, 2025 at 04:50:23PM +0800, Andy Yan wrote:
>> From: Andy Yan <andy.yan@rock-chips.com>
>> 
>> When there are multiple Video Ports, and only one of them is working
>> (for example, VP1 is working while VP0 is not), in this case, the
>> win_mask of VP0 is 0. However, we have already set the port mux for VP0
>> according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
>> register, there are windows will also be assigned to layers which will
>> map to the inactive VPs. In this situation, vp0->win_mask is zero as it
>> now working, it is more reliable to calculate the used layers based on
>> the configuration of the OVL_LAYER_SEL register.
>> 
>> Note: as the configuration of OVL_LAYER_SEL is take effect when the
>> vsync is come, so we use the value backup in vop2->old_layer_sel instead
>> of read OVL_LAYER_SEL directly.
>> 
>> Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
>> Reported-by: Diederik de Haas <diederik@cknow-tech.com>
>> Closes: https://bugs.kde.org/show_bug.cgi?id=511274
>> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
>> ---
>> 
>>  drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++---
>>  1 file changed, 42 insertions(+), 7 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>> index d22ce11a4235..f3950e8476a7 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
>> @@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = {
>>  	},
>>  };
>>  
>> +/*
>> + * phys_id is used to identify a main window(Cluster Win/Smart Win, not
>> + * include the sub win of a cluster or the multi area) that can do overlay
>> + * in main overlay stage.
>> + */
>> +static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id)
>> +{
>> +	struct vop2_win *win;
>> +	int i;
>> +
>> +	for (i = 0; i < vop2->data->win_size; i++) {
>> +		win = &vop2->win[i];
>> +		if (win->data->phys_id == phys_id)
>> +			return win;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>>  static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
>>  {
>>  	struct vop2 *vop2 = vp->vop2;
>> @@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
>>  	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
>>  }
>>  
>> -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
>> +static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp)
>>  {
>> -	struct vop2_video_port *vp;
>> -	int used_layer = 0;
>> +	struct vop2 *vop2 = vp->vop2;
>> +	struct vop2_win *win;
>> +	u32 layer_sel = vop2->old_layer_sel;
>> +	u32 used_layer = 0;
>> +	unsigned long win_mask = vp->win_mask;
>> +	unsigned long phys_id;
>> +	bool match;
>>  	int i;
>>  
>> -	for (i = 0; i < port_id; i++) {
>> -		vp = &vop2->vps[i];
>> -		used_layer += hweight32(vp->win_mask);
>> +	for (i = 0; i < 31; i += 4) {
>> +		match = false;
>> +		for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) {
>> +			win = vop2_find_win_by_phys_id(vop2, phys_id);
>> +			if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) {
>> +				match = true;
>> +				break;
>> +			}
>> +		}
>> +
>> +		if (!match)
>> +			used_layer += 1;
>> +		else
>> +			break;
>>  	}
>>  
>>  	return used_layer;
>> @@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
>>  	u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
>>  
>>  	if (vop2->version <= VOP_VERSION_RK3588)
>> -		mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
>> +		mixer_id = vop2_find_start_mixer_id_for_vp(vp);
>>  	else
>>  		mixer_id = 0;
>>  
>> -- 
>> 2.43.0
>> 
>> base-commit: ded94ec6167e84195507237100f6278941e36fdd
>> branch: drm-misc-next-2025-1016
>> 
>> 
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
Re: [PATCH] drm/rockchip: vop2: Use OVL_LAYER_SEL configuration instead of use win_mask calculate used layers
Posted by Diederik de Haas 2 months, 3 weeks ago
Hi Andy,

On Wed Nov 12, 2025 at 9:50 AM CET, Andy Yan wrote:
> From: Andy Yan <andy.yan@rock-chips.com>
>
> When there are multiple Video Ports, and only one of them is working
> (for example, VP1 is working while VP0 is not), in this case, the
> win_mask of VP0 is 0. However, we have already set the port mux for VP0
> according to vp0->nlayers, and at the same time, in the OVL_LAYER_SEL
> register, there are windows will also be assigned to layers which will
> map to the inactive VPs. In this situation, vp0->win_mask is zero as it
> now working, it is more reliable to calculate the used layers based on
> the configuration of the OVL_LAYER_SEL register.

Thanks a lot for this patch!
I've tested it on my PineTab2 and the 'black box under cursor' problem
is now fixed :-) So feel free to add my

Tested-by: Diederik de Haas <diederik@cknow-tech.com>

Cheers,
  Diederik

> Note: as the configuration of OVL_LAYER_SEL is take effect when the
> vsync is come, so we use the value backup in vop2->old_layer_sel instead
> of read OVL_LAYER_SEL directly.
>
> Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568")
> Reported-by: Diederik de Haas <diederik@cknow-tech.com>
> Closes: https://bugs.kde.org/show_bug.cgi?id=511274
> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> ---
>
>  drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 49 +++++++++++++++++---
>  1 file changed, 42 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> index d22ce11a4235..f3950e8476a7 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
> @@ -1369,6 +1369,25 @@ static const struct vop2_regs_dump rk3588_regs_dump[] = {
>  	},
>  };
>  
> +/*
> + * phys_id is used to identify a main window(Cluster Win/Smart Win, not
> + * include the sub win of a cluster or the multi area) that can do overlay
> + * in main overlay stage.
> + */
> +static struct vop2_win *vop2_find_win_by_phys_id(struct vop2 *vop2, uint8_t phys_id)
> +{
> +	struct vop2_win *win;
> +	int i;
> +
> +	for (i = 0; i < vop2->data->win_size; i++) {
> +		win = &vop2->win[i];
> +		if (win->data->phys_id == phys_id)
> +			return win;
> +	}
> +
> +	return NULL;
> +}
> +
>  static unsigned long rk3568_set_intf_mux(struct vop2_video_port *vp, int id, u32 polflags)
>  {
>  	struct vop2 *vop2 = vp->vop2;
> @@ -1842,15 +1861,31 @@ static void vop2_parse_alpha(struct vop2_alpha_config *alpha_config,
>  	alpha->dst_alpha_ctrl.bits.factor_mode = ALPHA_SRC_INVERSE;
>  }
>  
> -static int vop2_find_start_mixer_id_for_vp(struct vop2 *vop2, u8 port_id)
> +static int vop2_find_start_mixer_id_for_vp(struct vop2_video_port *vp)
>  {
> -	struct vop2_video_port *vp;
> -	int used_layer = 0;
> +	struct vop2 *vop2 = vp->vop2;
> +	struct vop2_win *win;
> +	u32 layer_sel = vop2->old_layer_sel;
> +	u32 used_layer = 0;
> +	unsigned long win_mask = vp->win_mask;
> +	unsigned long phys_id;
> +	bool match;
>  	int i;
>  
> -	for (i = 0; i < port_id; i++) {
> -		vp = &vop2->vps[i];
> -		used_layer += hweight32(vp->win_mask);
> +	for (i = 0; i < 31; i += 4) {
> +		match = false;
> +		for_each_set_bit(phys_id, &win_mask, ROCKCHIP_VOP2_ESMART3) {
> +			win = vop2_find_win_by_phys_id(vop2, phys_id);
> +			if (win->data->layer_sel_id[vp->id] == ((layer_sel >> i) & 0xf)) {
> +				match = true;
> +				break;
> +			}
> +		}
> +
> +		if (!match)
> +			used_layer += 1;
> +		else
> +			break;
>  	}
>  
>  	return used_layer;
> @@ -1935,7 +1970,7 @@ static void vop2_setup_alpha(struct vop2_video_port *vp)
>  	u32 dst_global_alpha = DRM_BLEND_ALPHA_OPAQUE;
>  
>  	if (vop2->version <= VOP_VERSION_RK3588)
> -		mixer_id = vop2_find_start_mixer_id_for_vp(vop2, vp->id);
> +		mixer_id = vop2_find_start_mixer_id_for_vp(vp);
>  	else
>  		mixer_id = 0;
>