[PATCH 6.19 134/844] drm/amd/display: Fix wrong x_pos and y_pos for cursor offload

From: Sasha Levin

Date: Sat Feb 28 2026 - 12:59:00 EST


From: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx>

[ Upstream commit c02288724b98cbc018231200891d66578f83f848 ]

[Why]
The hubp401_cursor_set_position function programs a different value
than it stores for use with cursor offload.

This can cause a desync when switching between cursor programming paths.

[How]
We do the translation to destination space currently twice: once in the
HWSS layer, and then again in the HUBP layer since we never store the
translated result.

HUBP expects to program the pos->x and pos->y directly for other ASIC,
so follow that pattern here as well.

Reviewed-by: Alvin Lee <alvin.lee2@xxxxxxx>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx>
Signed-off-by: Roman Li <roman.li@xxxxxxx>
Tested-by: Dan Wheeler <daniel.wheeler@xxxxxxx>
Signed-off-by: Alex Deucher <alexander.deucher@xxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---
.../drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c | 14 ++++++--------
.../drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c | 3 +++
2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
index f01eae50d02f7..c205500290ecd 100644
--- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c
@@ -733,10 +733,8 @@ void hubp401_cursor_set_position(
const struct dc_cursor_mi_param *param)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
- int x_pos = pos->x - param->recout.x;
- int y_pos = pos->y - param->recout.y;
- int rec_x_offset = x_pos - pos->x_hotspot;
- int rec_y_offset = y_pos - pos->y_hotspot;
+ int rec_x_offset = pos->x - pos->x_hotspot;
+ int rec_y_offset = pos->y - pos->y_hotspot;
int dst_x_offset;
int x_pos_viewport = 0;
int x_hot_viewport = 0;
@@ -748,10 +746,10 @@ void hubp401_cursor_set_position(
* within preceeding ODM slices.
*/
if (param->recout.width) {
- x_pos_viewport = x_pos * param->viewport.width / param->recout.width;
+ x_pos_viewport = pos->x * param->viewport.width / param->recout.width;
x_hot_viewport = pos->x_hotspot * param->viewport.width / param->recout.width;
} else {
- ASSERT(!cur_en || x_pos == 0);
+ ASSERT(!cur_en || pos->x == 0);
ASSERT(!cur_en || pos->x_hotspot == 0);
}

@@ -790,8 +788,8 @@ void hubp401_cursor_set_position(

if (!hubp->cursor_offload) {
REG_SET_2(CURSOR_POSITION, 0,
- CURSOR_X_POSITION, x_pos,
- CURSOR_Y_POSITION, y_pos);
+ CURSOR_X_POSITION, pos->x,
+ CURSOR_Y_POSITION, pos->y);

REG_SET_2(CURSOR_HOT_SPOT, 0,
CURSOR_HOT_SPOT_X, pos->x_hotspot,
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index 5eda7648d0d2b..5ffe41a96864a 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -1215,6 +1215,9 @@ void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
if (recout_y_pos + (int)hubp->curs_attr.height <= 0)
pos_cpy.enable = false; /* not visible beyond top edge*/

+ pos_cpy.x = x_pos;
+ pos_cpy.y = y_pos;
+
hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width, hubp->curs_attr.height);
}
--
2.51.0