From dc145f286d3bec74573dc398424110ef4ccc87a7 Mon Sep 17 00:00:00 2001
From: David Zhang <dingchen.zhang@amd.com>
Date: Wed, 4 May 2022 12:30:24 -0400
Subject: drm/amd/display: update cursor position to DMUB FW
Git-commit: 1b0da5a3e90d3920f6967e4303fdeaaec6f62208
Patch-mainline: v6.0-rc1
References: jsc#PED-1166 jsc#PED-1168 jsc#PED-1170 jsc#PED-1218 jsc#PED-1220 jsc#PED-1222 jsc#PED-1223 jsc#PED-1225 jsc#PED-2849

[why]
To involve the cursor position into dirty rectangle calculation.

[how]
- separate plane and cursor update by different DMUB command
- send the cursor information while cursor updating, when updating
  cursor position/attribute, store cursor pos/attr to hubp, and
  notify dmub FW to exit psr before program cursor registers

Signed-off-by: David Zhang <dingchen.zhang@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 .../gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c |   2 +
 .../amd/display/dc/dcn10/dcn10_hw_sequencer.c | 131 ++++++++++++++++++
 .../gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c |   2 +
 drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h  |   1 +
 4 files changed, 136 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
index 3a7f76e2c598..564e061ccb58 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
@@ -1188,6 +1188,8 @@ void hubp1_cursor_set_position(
 	uint32_t dst_x_offset;
 	uint32_t cur_en = pos->enable ? 1 : 0;
 
+	hubp->curs_pos = *pos;
+
 	/*
 	 * Guard aganst cursor_set_position() from being called with invalid
 	 * attributes
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index e3a62873c0e7..351a923fbf73 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -51,6 +51,8 @@
 #include "link_hwss.h"
 #include "dpcd_defs.h"
 #include "dsc.h"
+#include "dce/dmub_psr.h"
+#include "dc_dmub_srv.h"
 #include "dce/dmub_hw_lock_mgr.h"
 #include "dc_trace.h"
 #include "dce/dmub_outbox.h"
@@ -3328,6 +3330,115 @@ static bool dcn10_can_pipe_disable_cursor(struct pipe_ctx *pipe_ctx)
 	return false;
 }
 
+static void dcn10_dmub_update_cursor_data(
+		struct pipe_ctx *pipe_ctx,
+		struct hubp *hubp,
+		const struct dc_cursor_mi_param *param,
+		const struct dc_cursor_position *cur_pos,
+		const struct dc_cursor_attributes *cur_attr)
+{
+	union dmub_rb_cmd cmd;
+	struct dmub_cmd_update_cursor_info_data *update_cursor_info;
+	const struct dc_cursor_position *pos;
+	const struct dc_cursor_attributes *attr;
+	int src_x_offset = 0;
+	int src_y_offset = 0;
+	int x_hotspot = 0;
+	int cursor_height = 0;
+	int cursor_width = 0;
+	uint32_t cur_en = 0;
+	unsigned int panel_inst = 0;
+
+	struct dc_debug_options *debug = &hubp->ctx->dc->debug;
+
+	if (!debug->enable_sw_cntl_psr && pipe_ctx->stream->link->psr_settings.psr_version != DC_PSR_VERSION_SU_1)
+		return;
+
+	if (pipe_ctx->stream->link->psr_settings.psr_version == DC_PSR_VERSION_UNSUPPORTED ||
+		pipe_ctx->plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+		return;
+
+	/**
+	 * if cur_pos == NULL means the caller is from cursor_set_attribute
+	 * then driver use previous cursor position data
+	 * if cur_attr == NULL means the caller is from cursor_set_position
+	 * then driver use previous cursor attribute
+	 * if cur_pos or cur_attr is not NULL then update it
+	 */
+	if (cur_pos != NULL)
+		pos = cur_pos;
+	else
+		pos = &hubp->curs_pos;
+
+	if (cur_attr != NULL)
+		attr = cur_attr;
+	else
+		attr = &hubp->curs_attr;
+
+	if (!dc_get_edp_link_panel_inst(hubp->ctx->dc, pipe_ctx->stream->link, &panel_inst))
+		return;
+
+	src_x_offset = pos->x - pos->x_hotspot - param->viewport.x;
+	src_y_offset = pos->y - pos->y_hotspot - param->viewport.y;
+	x_hotspot = pos->x_hotspot;
+	cursor_height = (int)attr->height;
+	cursor_width = (int)attr->width;
+	cur_en = pos->enable ? 1:0;
+
+	// Rotated cursor width/height and hotspots tweaks for offset calculation
+	if (param->rotation == ROTATION_ANGLE_90 || param->rotation == ROTATION_ANGLE_270) {
+		swap(cursor_height, cursor_width);
+		if (param->rotation == ROTATION_ANGLE_90) {
+			src_x_offset = pos->x - pos->y_hotspot - param->viewport.x;
+			src_y_offset = pos->y - pos->x_hotspot - param->viewport.y;
+		}
+	} else if (param->rotation == ROTATION_ANGLE_180) {
+		src_x_offset = pos->x - param->viewport.x;
+		src_y_offset = pos->y - param->viewport.y;
+	}
+
+	if (param->mirror) {
+		x_hotspot = param->viewport.width - x_hotspot;
+		src_x_offset = param->viewport.x + param->viewport.width - src_x_offset;
+	}
+
+	if (src_x_offset >= (int)param->viewport.width)
+		cur_en = 0;  /* not visible beyond right edge*/
+
+	if (src_x_offset + cursor_width <= 0)
+		cur_en = 0;  /* not visible beyond left edge*/
+
+	if (src_y_offset >= (int)param->viewport.height)
+		cur_en = 0;  /* not visible beyond bottom edge*/
+
+	if (src_y_offset + cursor_height <= 0)
+		cur_en = 0;  /* not visible beyond top edge*/
+
+	// Cursor bitmaps have different hotspot values
+	// There's a possibility that the above logic returns a negative value, so we clamp them to 0
+	if (src_x_offset < 0)
+		src_x_offset = 0;
+	if (src_y_offset < 0)
+		src_y_offset = 0;
+
+	memset(&cmd, 0x0, sizeof(cmd));
+	cmd.update_cursor_info.header.type = DMUB_CMD__UPDATE_CURSOR_INFO;
+	cmd.update_cursor_info.header.payload_bytes =
+			sizeof(cmd.update_cursor_info.update_cursor_info_data);
+	update_cursor_info = &cmd.update_cursor_info.update_cursor_info_data;
+	update_cursor_info->cursor_rect.x = src_x_offset + param->viewport.x;
+	update_cursor_info->cursor_rect.y = src_y_offset + param->viewport.y;
+	update_cursor_info->cursor_rect.width = attr->width;
+	update_cursor_info->cursor_rect.height = attr->height;
+	update_cursor_info->enable = cur_en;
+	update_cursor_info->pipe_idx = pipe_ctx->pipe_idx;
+	update_cursor_info->cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
+	update_cursor_info->panel_inst = panel_inst;
+	dc_dmub_srv_cmd_queue(pipe_ctx->stream->ctx->dmub_srv, &cmd);
+	dc_dmub_srv_cmd_execute(pipe_ctx->stream->ctx->dmub_srv);
+	dc_dmub_srv_wait_idle(pipe_ctx->stream->ctx->dmub_srv);
+}
+
 void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
 {
 	struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
@@ -3526,6 +3637,7 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
 			pipe_ctx->plane_res.scl_data.viewport.height - pos_cpy.y;
 	}
 
+	dcn10_dmub_update_cursor_data(pipe_ctx, hubp, &param, &pos_cpy, NULL);
 	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);
 }
@@ -3533,6 +3645,25 @@ void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
 void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
 {
 	struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
+	struct dc_cursor_mi_param param = { 0 };
+
+	/**
+	 * If enter PSR without cursor attribute update
+	 * the cursor attribute of dmub_restore_plane
+	 * are initial value. call dmub to exit PSR and
+	 * restore plane then update cursor attribute to
+	 * avoid override with initial value
+	 */
+	if (pipe_ctx->plane_state != NULL) {
+		param.pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
+		param.ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clocks.dchub_ref_clock_inKhz;
+		param.viewport = pipe_ctx->plane_res.scl_data.viewport;
+		param.h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz;
+		param.v_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.vert;
+		param.rotation = pipe_ctx->plane_state->rotation;
+		param.mirror = pipe_ctx->plane_state->horizontal_mirror;
+		dcn10_dmub_update_cursor_data(pipe_ctx, pipe_ctx->plane_res.hubp, &param, NULL, attributes);
+	}
 
 	pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
 			pipe_ctx->plane_res.hubp, attributes);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
index a665af19f201..9570c2118ccc 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
@@ -967,6 +967,8 @@ void hubp2_cursor_set_position(
 	uint32_t dst_x_offset;
 	uint32_t cur_en = pos->enable ? 1 : 0;
 
+	hubp->curs_pos = *pos;
+
 	/*
 	 * Guard aganst cursor_set_position() from being called with invalid
 	 * attributes
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
index b2cdb6bfc9b8..906818e792dd 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -63,6 +63,7 @@ struct hubp {
 	int opp_id;
 	int mpcc_id;
 	struct dc_cursor_attributes curs_attr;
+	struct dc_cursor_position curs_pos;
 	bool power_gated;
 };
 
-- 
2.38.1

