--- /dev/null
+From 1ff6631baeb1f5d69be192732d0157a06b43f20a Mon Sep 17 00:00:00 2001
+From: Fangzhi Zuo <jerry.zuo@amd.com>
+Date: Fri, 10 May 2024 15:23:02 -0400
+Subject: drm/amd/display: Prevent IPX From Link Detect and Set Mode
+
+From: Fangzhi Zuo <jerry.zuo@amd.com>
+
+commit 1ff6631baeb1f5d69be192732d0157a06b43f20a upstream.
+
+IPX involvment proven to affect LT, causing link loss. Need to prevent
+IPX enabled in LT process in which link detect and set mode are main
+procedures that have LT taken place.
+
+Reviewed-by: Roman Li <roman.li@amd.com>
+Acked-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
+Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: Kevin Holm <kevin@holm.dev>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -2943,6 +2943,7 @@ static int dm_resume(void *handle)
+
+ commit_params.streams = dc_state->streams;
+ commit_params.stream_count = dc_state->stream_count;
++ dc_exit_ips_for_hw_access(dm->dc);
+ WARN_ON(!dc_commit_streams(dm->dc, &commit_params));
+
+ dm_gpureset_commit_state(dm->cached_dc_state, dm);
+@@ -3015,6 +3016,7 @@ static int dm_resume(void *handle)
+ emulated_link_detect(aconnector->dc_link);
+ } else {
+ mutex_lock(&dm->dc_lock);
++ dc_exit_ips_for_hw_access(dm->dc);
+ dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
+ mutex_unlock(&dm->dc_lock);
+ }
+@@ -3351,6 +3353,7 @@ static void handle_hpd_irq_helper(struct
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ struct amdgpu_device *adev = drm_to_adev(dev);
+ struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
++ struct dc *dc = aconnector->dc_link->ctx->dc;
+ bool ret = false;
+
+ if (adev->dm.disable_hpd_irq)
+@@ -3385,6 +3388,7 @@ static void handle_hpd_irq_helper(struct
+ drm_kms_helper_connector_hotplug_event(connector);
+ } else {
+ mutex_lock(&adev->dm.dc_lock);
++ dc_exit_ips_for_hw_access(dc);
+ ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
+ mutex_unlock(&adev->dm.dc_lock);
+ if (ret) {
+@@ -3444,6 +3448,7 @@ static void handle_hpd_rx_irq(void *para
+ bool has_left_work = false;
+ int idx = dc_link->link_index;
+ struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx];
++ struct dc *dc = aconnector->dc_link->ctx->dc;
+
+ memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
+
+@@ -3533,6 +3538,7 @@ out:
+ bool ret = false;
+
+ mutex_lock(&adev->dm.dc_lock);
++ dc_exit_ips_for_hw_access(dc);
+ ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX);
+ mutex_unlock(&adev->dm.dc_lock);
+
+@@ -4639,6 +4645,7 @@ static int amdgpu_dm_initialize_drm_devi
+ bool ret = false;
+
+ mutex_lock(&dm->dc_lock);
++ dc_exit_ips_for_hw_access(dm->dc);
+ ret = dc_link_detect(link, DETECT_REASON_BOOT);
+ mutex_unlock(&dm->dc_lock);
+
+@@ -8947,6 +8954,7 @@ static void amdgpu_dm_commit_streams(str
+
+ memset(&position, 0, sizeof(position));
+ mutex_lock(&dm->dc_lock);
++ dc_exit_ips_for_hw_access(dm->dc);
+ dc_stream_program_cursor_position(dm_old_crtc_state->stream, &position);
+ mutex_unlock(&dm->dc_lock);
+ }
+@@ -9016,6 +9024,7 @@ static void amdgpu_dm_commit_streams(str
+
+ dm_enable_per_frame_crtc_master_sync(dc_state);
+ mutex_lock(&dm->dc_lock);
++ dc_exit_ips_for_hw_access(dm->dc);
+ WARN_ON(!dc_commit_streams(dm->dc, ¶ms));
+
+ /* Allow idle optimization when vblank count is 0 for display off */
+@@ -9381,6 +9390,7 @@ static void amdgpu_dm_atomic_commit_tail
+
+
+ mutex_lock(&dm->dc_lock);
++ dc_exit_ips_for_hw_access(dm->dc);
+ dc_update_planes_and_stream(dm->dc,
+ dummy_updates,
+ status->plane_count,
--- /dev/null
+From f63f86b5affcc2abd1162f11824b9386fc06ac94 Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Fri, 15 Mar 2024 11:19:15 -0400
+Subject: drm/amd/display: Separate setting and programming of cursor
+
+From: Harry Wentland <harry.wentland@amd.com>
+
+commit f63f86b5affcc2abd1162f11824b9386fc06ac94 upstream.
+
+We're seeing issues when user-space tries to do an atomic update of
+the primary surface, as well as the cursor. These two updates are
+separate calls into DC and don't currently act as an atomic update.
+This might lead to cursor updates being locked out and cursors
+stuttering.
+
+In order to solve this problem we want to separate the setting
+and programming of cursor attributes and position. That's what
+we're doing in this patch. The subsequent patch will then be
+able to use the cursor setters in independent cursor updates,
+as well as in atomic commits.
+
+Reviewed-by: Agustin Gutierrez <agustin.gutierrez@amd.com>
+Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: Kevin Holm <kevin@holm.dev>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 6 -
+ drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 89 ++++++++++------
+ drivers/gpu/drm/amd/display/dc/dc_stream.h | 8 +
+ drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c | 2
+ 5 files changed, 73 insertions(+), 34 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -8947,7 +8947,7 @@ static void amdgpu_dm_commit_streams(str
+
+ memset(&position, 0, sizeof(position));
+ mutex_lock(&dm->dc_lock);
+- dc_stream_set_cursor_position(dm_old_crtc_state->stream, &position);
++ dc_stream_program_cursor_position(dm_old_crtc_state->stream, &position);
+ mutex_unlock(&dm->dc_lock);
+ }
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+@@ -1254,7 +1254,7 @@ void amdgpu_dm_plane_handle_cursor_updat
+ /* turn off cursor */
+ if (crtc_state && crtc_state->stream) {
+ mutex_lock(&adev->dm.dc_lock);
+- dc_stream_set_cursor_position(crtc_state->stream,
++ dc_stream_program_cursor_position(crtc_state->stream,
+ &position);
+ mutex_unlock(&adev->dm.dc_lock);
+ }
+@@ -1284,11 +1284,11 @@ void amdgpu_dm_plane_handle_cursor_updat
+
+ if (crtc_state->stream) {
+ mutex_lock(&adev->dm.dc_lock);
+- if (!dc_stream_set_cursor_attributes(crtc_state->stream,
++ if (!dc_stream_program_cursor_attributes(crtc_state->stream,
+ &attributes))
+ DRM_ERROR("DC failed to set cursor attributes\n");
+
+- if (!dc_stream_set_cursor_position(crtc_state->stream,
++ if (!dc_stream_program_cursor_position(crtc_state->stream,
+ &position))
+ DRM_ERROR("DC failed to set cursor position\n");
+ mutex_unlock(&adev->dm.dc_lock);
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+@@ -266,7 +266,6 @@ bool dc_stream_set_cursor_attributes(
+ const struct dc_cursor_attributes *attributes)
+ {
+ struct dc *dc;
+- bool reset_idle_optimizations = false;
+
+ if (NULL == stream) {
+ dm_error("DC: dc_stream is NULL!\n");
+@@ -297,20 +296,36 @@ bool dc_stream_set_cursor_attributes(
+
+ stream->cursor_attributes = *attributes;
+
+- dc_z10_restore(dc);
+- /* disable idle optimizations while updating cursor */
+- if (dc->idle_optimizations_allowed) {
+- dc_allow_idle_optimizations(dc, false);
+- reset_idle_optimizations = true;
+- }
++ return true;
++}
+
+- program_cursor_attributes(dc, stream, attributes);
+-
+- /* re-enable idle optimizations if necessary */
+- if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
+- dc_allow_idle_optimizations(dc, true);
++bool dc_stream_program_cursor_attributes(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_attributes *attributes)
++{
++ struct dc *dc;
++ bool reset_idle_optimizations = false;
+
+- return true;
++ dc = stream ? stream->ctx->dc : NULL;
++
++ if (dc_stream_set_cursor_attributes(stream, attributes)) {
++ dc_z10_restore(dc);
++ /* disable idle optimizations while updating cursor */
++ if (dc->idle_optimizations_allowed) {
++ dc_allow_idle_optimizations(dc, false);
++ reset_idle_optimizations = true;
++ }
++
++ program_cursor_attributes(dc, stream, attributes);
++
++ /* re-enable idle optimizations if necessary */
++ if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
++ dc_allow_idle_optimizations(dc, true);
++
++ return true;
++ }
++
++ return false;
+ }
+
+ static void program_cursor_position(
+@@ -355,9 +370,6 @@ bool dc_stream_set_cursor_position(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_position *position)
+ {
+- struct dc *dc;
+- bool reset_idle_optimizations = false;
+-
+ if (NULL == stream) {
+ dm_error("DC: dc_stream is NULL!\n");
+ return false;
+@@ -368,24 +380,43 @@ bool dc_stream_set_cursor_position(
+ return false;
+ }
+
++ stream->cursor_position = *position;
++
++
++ return true;
++}
++
++bool dc_stream_program_cursor_position(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_position *position)
++{
++ struct dc *dc;
++ bool reset_idle_optimizations = false;
++ const struct dc_cursor_position *old_position;
++
++ old_position = stream ? &stream->cursor_position : NULL;
+ dc = stream->ctx->dc;
+- dc_z10_restore(dc);
+
+- /* disable idle optimizations if enabling cursor */
+- if (dc->idle_optimizations_allowed && (!stream->cursor_position.enable || dc->debug.exit_idle_opt_for_cursor_updates)
+- && position->enable) {
+- dc_allow_idle_optimizations(dc, false);
+- reset_idle_optimizations = true;
+- }
++ if (dc_stream_set_cursor_position(stream, position)) {
++ dc_z10_restore(dc);
+
+- stream->cursor_position = *position;
++ /* disable idle optimizations if enabling cursor */
++ if (dc->idle_optimizations_allowed &&
++ (!old_position->enable || dc->debug.exit_idle_opt_for_cursor_updates) &&
++ position->enable) {
++ dc_allow_idle_optimizations(dc, false);
++ reset_idle_optimizations = true;
++ }
+
+- program_cursor_position(dc, stream, position);
+- /* re-enable idle optimizations if necessary */
+- if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
+- dc_allow_idle_optimizations(dc, true);
++ program_cursor_position(dc, stream, position);
++ /* re-enable idle optimizations if necessary */
++ if (reset_idle_optimizations && !dc->debug.disable_dmub_reallow_idle)
++ dc_allow_idle_optimizations(dc, true);
+
+- return true;
++ return true;
++ }
++
++ return false;
+ }
+
+ bool dc_stream_add_writeback(struct dc *dc,
+--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
++++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
+@@ -470,10 +470,18 @@ bool dc_stream_set_cursor_attributes(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_attributes *attributes);
+
++bool dc_stream_program_cursor_attributes(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_attributes *attributes);
++
+ bool dc_stream_set_cursor_position(
+ struct dc_stream_state *stream,
+ const struct dc_cursor_position *position);
+
++bool dc_stream_program_cursor_position(
++ struct dc_stream_state *stream,
++ const struct dc_cursor_position *position);
++
+
+ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
+ struct dc_stream_state *stream,
+--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
++++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+@@ -1041,7 +1041,7 @@ bool dcn30_apply_idle_power_optimization
+
+ /* Use copied cursor, and it's okay to not switch back */
+ cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part;
+- dc_stream_set_cursor_attributes(stream, &cursor_attr);
++ dc_stream_program_cursor_attributes(stream, &cursor_attr);
+ }
+
+ /* Enable MALL */