--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:58 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:38 -0500
+Subject: drm/amd/display: Add polling method to handle MST reply packet
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-8-mario.limonciello@amd.com>
+
+From: Wayne Lin <wayne.lin@amd.com>
+
+commit 4f6d9e38c4d244ad106eb9ebd8c0e1215e866f35 upstream.
+
+[Why]
+Specific TBT4 dock doesn't send out short HPD to notify source
+that IRQ event DOWN_REP_MSG_RDY is set. Which violates the spec
+and cause source can't send out streams to mst sinks.
+
+[How]
+To cover this misbehavior, add an additional polling method to detect
+DOWN_REP_MSG_RDY is set. HPD driven handling method is still kept.
+Just hook up our handler to drm mgr->cbs->poll_hpd_irq().
+
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Jerry Zuo <jerry.zuo@amd.com>
+Acked-by: Alan Liu <haoping.liu@amd.com>
+Signed-off-by: Wayne Lin <wayne.lin@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 117 +++---------
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 110 +++++++++++
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 11 +
+ 4 files changed, 159 insertions(+), 86 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -1325,6 +1325,15 @@ static void dm_handle_hpd_rx_offload_wor
+ if (amdgpu_in_reset(adev))
+ goto skip;
+
++ if (offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
++ offload_work->data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
++ dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, DOWN_OR_UP_MSG_RDY_EVENT);
++ spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
++ offload_work->offload_wq->is_handling_mst_msg_rdy_event = false;
++ spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
++ goto skip;
++ }
++
+ mutex_lock(&adev->dm.dc_lock);
+ if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
+ dc_link_dp_handle_automated_test(dc_link);
+@@ -3229,87 +3238,6 @@ static void handle_hpd_irq(void *param)
+
+ }
+
+-static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
+-{
+- u8 esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
+- u8 dret;
+- bool new_irq_handled = false;
+- int dpcd_addr;
+- int dpcd_bytes_to_read;
+-
+- const int max_process_count = 30;
+- int process_count = 0;
+-
+- const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link);
+-
+- if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) {
+- dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
+- /* DPCD 0x200 - 0x201 for downstream IRQ */
+- dpcd_addr = DP_SINK_COUNT;
+- } else {
+- dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
+- /* DPCD 0x2002 - 0x2005 for downstream IRQ */
+- dpcd_addr = DP_SINK_COUNT_ESI;
+- }
+-
+- dret = drm_dp_dpcd_read(
+- &aconnector->dm_dp_aux.aux,
+- dpcd_addr,
+- esi,
+- dpcd_bytes_to_read);
+-
+- while (dret == dpcd_bytes_to_read &&
+- process_count < max_process_count) {
+- u8 ack[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = {};
+- u8 retry;
+-
+- dret = 0;
+-
+- process_count++;
+-
+- DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+- /* handle HPD short pulse irq */
+- if (aconnector->mst_mgr.mst_state)
+- drm_dp_mst_hpd_irq_handle_event(&aconnector->mst_mgr,
+- esi,
+- ack,
+- &new_irq_handled);
+-
+- if (new_irq_handled) {
+- /* ACK at DPCD to notify down stream */
+- for (retry = 0; retry < 3; retry++) {
+- ssize_t wret;
+-
+- wret = drm_dp_dpcd_writeb(&aconnector->dm_dp_aux.aux,
+- dpcd_addr + 1,
+- ack[1]);
+- if (wret == 1)
+- break;
+- }
+-
+- if (retry == 3) {
+- DRM_ERROR("Failed to ack MST event.\n");
+- return;
+- }
+-
+- drm_dp_mst_hpd_irq_send_new_request(&aconnector->mst_mgr);
+- /* check if there is new irq to be handled */
+- dret = drm_dp_dpcd_read(
+- &aconnector->dm_dp_aux.aux,
+- dpcd_addr,
+- esi,
+- dpcd_bytes_to_read);
+-
+- new_irq_handled = false;
+- } else {
+- break;
+- }
+- }
+-
+- if (process_count == max_process_count)
+- DRM_DEBUG_DRIVER("Loop exceeded max iterations\n");
+-}
+-
+ static void schedule_hpd_rx_offload_work(struct hpd_rx_irq_offload_work_queue *offload_wq,
+ union hpd_irq_data hpd_irq_data)
+ {
+@@ -3371,7 +3299,23 @@ static void handle_hpd_rx_irq(void *para
+ if (dc_link_dp_allow_hpd_rx_irq(dc_link)) {
+ if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY ||
+ hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
+- dm_handle_mst_sideband_msg(aconnector);
++ bool skip = false;
++
++ /*
++ * DOWN_REP_MSG_RDY is also handled by polling method
++ * mgr->cbs->poll_hpd_irq()
++ */
++ spin_lock(&offload_wq->offload_lock);
++ skip = offload_wq->is_handling_mst_msg_rdy_event;
++
++ if (!skip)
++ offload_wq->is_handling_mst_msg_rdy_event = true;
++
++ spin_unlock(&offload_wq->offload_lock);
++
++ if (!skip)
++ schedule_hpd_rx_offload_work(offload_wq, hpd_irq_data);
++
+ goto out;
+ }
+
+@@ -3482,11 +3426,11 @@ static void register_hpd_handlers(struct
+ amdgpu_dm_irq_register_interrupt(adev, &int_params,
+ handle_hpd_rx_irq,
+ (void *) aconnector);
+-
+- if (adev->dm.hpd_rx_offload_wq)
+- adev->dm.hpd_rx_offload_wq[dc_link->link_index].aconnector =
+- aconnector;
+ }
++
++ if (adev->dm.hpd_rx_offload_wq)
++ adev->dm.hpd_rx_offload_wq[connector->index].aconnector =
++ aconnector;
+ }
+ }
+
+@@ -7082,6 +7026,7 @@ void amdgpu_dm_connector_init_helper(str
+ aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
+ aconnector->audio_inst = -1;
+ mutex_init(&aconnector->hpd_lock);
++ mutex_init(&aconnector->handle_mst_msg_ready);
+
+ /*
+ * configure support HPD hot plug connector_>polled default value is 0
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -194,6 +194,11 @@ struct hpd_rx_irq_offload_work_queue {
+ */
+ bool is_handling_link_loss;
+ /**
++ * @is_handling_mst_msg_rdy_event: Used to prevent inserting mst message
++ * ready event when we're already handling mst message ready event
++ */
++ bool is_handling_mst_msg_rdy_event;
++ /**
+ * @aconnector: The aconnector that this work queue is attached to
+ */
+ struct amdgpu_dm_connector *aconnector;
+@@ -614,6 +619,8 @@ struct amdgpu_dm_connector {
+ struct drm_dp_mst_port *port;
+ struct amdgpu_dm_connector *mst_port;
+ struct drm_dp_aux *dsc_aux;
++ struct mutex handle_mst_msg_ready;
++
+ /* TODO see if we can merge with ddc_bus or make a dm_connector */
+ struct amdgpu_i2c_adapter *i2c;
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -590,8 +590,118 @@ dm_dp_add_mst_connector(struct drm_dp_ms
+ return connector;
+ }
+
++void dm_handle_mst_sideband_msg_ready_event(
++ struct drm_dp_mst_topology_mgr *mgr,
++ enum mst_msg_ready_type msg_rdy_type)
++{
++ uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
++ uint8_t dret;
++ bool new_irq_handled = false;
++ int dpcd_addr;
++ uint8_t dpcd_bytes_to_read;
++ const uint8_t max_process_count = 30;
++ uint8_t process_count = 0;
++ u8 retry;
++ struct amdgpu_dm_connector *aconnector =
++ container_of(mgr, struct amdgpu_dm_connector, mst_mgr);
++
++
++ const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link);
++
++ if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) {
++ dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
++ /* DPCD 0x200 - 0x201 for downstream IRQ */
++ dpcd_addr = DP_SINK_COUNT;
++ } else {
++ dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
++ /* DPCD 0x2002 - 0x2005 for downstream IRQ */
++ dpcd_addr = DP_SINK_COUNT_ESI;
++ }
++
++ mutex_lock(&aconnector->handle_mst_msg_ready);
++
++ while (process_count < max_process_count) {
++ u8 ack[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = {};
++
++ process_count++;
++
++ dret = drm_dp_dpcd_read(
++ &aconnector->dm_dp_aux.aux,
++ dpcd_addr,
++ esi,
++ dpcd_bytes_to_read);
++
++ if (dret != dpcd_bytes_to_read) {
++ DRM_DEBUG_KMS("DPCD read and acked number is not as expected!");
++ break;
++ }
++
++ DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
++
++ switch (msg_rdy_type) {
++ case DOWN_REP_MSG_RDY_EVENT:
++ /* Only handle DOWN_REP_MSG_RDY case*/
++ esi[1] &= DP_DOWN_REP_MSG_RDY;
++ break;
++ case UP_REQ_MSG_RDY_EVENT:
++ /* Only handle UP_REQ_MSG_RDY case*/
++ esi[1] &= DP_UP_REQ_MSG_RDY;
++ break;
++ default:
++ /* Handle both cases*/
++ esi[1] &= (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY);
++ break;
++ }
++
++ if (!esi[1])
++ break;
++
++ /* handle MST irq */
++ if (aconnector->mst_mgr.mst_state)
++ drm_dp_mst_hpd_irq_handle_event(&aconnector->mst_mgr,
++ esi,
++ ack,
++ &new_irq_handled);
++
++ if (new_irq_handled) {
++ /* ACK at DPCD to notify down stream */
++ for (retry = 0; retry < 3; retry++) {
++ ssize_t wret;
++
++ wret = drm_dp_dpcd_writeb(&aconnector->dm_dp_aux.aux,
++ dpcd_addr + 1,
++ ack[1]);
++ if (wret == 1)
++ break;
++ }
++
++ if (retry == 3) {
++ DRM_ERROR("Failed to ack MST event.\n");
++ return;
++ }
++
++ drm_dp_mst_hpd_irq_send_new_request(&aconnector->mst_mgr);
++
++ new_irq_handled = false;
++ } else {
++ break;
++ }
++ }
++
++ mutex_unlock(&aconnector->handle_mst_msg_ready);
++
++ if (process_count == max_process_count)
++ DRM_DEBUG_DRIVER("Loop exceeded max iterations\n");
++}
++
++static void dm_handle_mst_down_rep_msg_ready(struct drm_dp_mst_topology_mgr *mgr)
++{
++ dm_handle_mst_sideband_msg_ready_event(mgr, DOWN_REP_MSG_RDY_EVENT);
++}
++
+ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
+ .add_connector = dm_dp_add_mst_connector,
++ .poll_hpd_irq = dm_handle_mst_down_rep_msg_ready,
+ };
+
+ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+@@ -49,6 +49,13 @@
+ #define PBN_FEC_OVERHEAD_MULTIPLIER_8B_10B 1031
+ #define PBN_FEC_OVERHEAD_MULTIPLIER_128B_132B 1000
+
++enum mst_msg_ready_type {
++ NONE_MSG_RDY_EVENT = 0,
++ DOWN_REP_MSG_RDY_EVENT = 1,
++ UP_REQ_MSG_RDY_EVENT = 2,
++ DOWN_OR_UP_MSG_RDY_EVENT = 3
++};
++
+ struct amdgpu_display_manager;
+ struct amdgpu_dm_connector;
+
+@@ -61,6 +68,10 @@ void amdgpu_dm_initialize_dp_connector(s
+ void
+ dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev);
+
++void dm_handle_mst_sideband_msg_ready_event(
++ struct drm_dp_mst_topology_mgr *mgr,
++ enum mst_msg_ready_type msg_rdy_type);
++
+ struct dsc_mst_fairness_vars {
+ int pbn;
+ bool dsc_enabled;
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:56 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:36 -0500
+Subject: drm/amd/display: Clean up errors & warnings in amdgpu_dm.c
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-6-mario.limonciello@amd.com>
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+commit 87279fdf5ee0ad1360765ef70389d1c4d0f81bb6 upstream.
+
+Fix the following errors & warnings reported by checkpatch:
+
+ERROR: space required before the open brace '{'
+ERROR: space required before the open parenthesis '('
+ERROR: that open brace { should be on the previous line
+ERROR: space prohibited before that ',' (ctx:WxW)
+ERROR: else should follow close brace '}'
+ERROR: open brace '{' following function definitions go on the next line
+ERROR: code indent should use tabs where possible
+
+WARNING: braces {} are not necessary for single statement blocks
+WARNING: void function return statements are not generally useful
+WARNING: Block comments use * on subsequent lines
+WARNING: Block comments use a trailing */ on a separate line
+
+Cc: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Cc: Aurabindo Pillai <aurabindo.pillai@amd.com>
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ Modified for missing
+ c5a31f178e35 ("drm/amd/display: move dp irq handler functions from dc_link_dp to link_dp_irq_handler")
+ which landed in 6.3]
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 133 ++++++++++------------
+ 1 file changed, 65 insertions(+), 68 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -408,12 +408,12 @@ static void dm_pflip_high_irq(void *inte
+
+ spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+
+- if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
+- DC_LOG_PFLIP("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
+- amdgpu_crtc->pflip_status,
+- AMDGPU_FLIP_SUBMITTED,
+- amdgpu_crtc->crtc_id,
+- amdgpu_crtc);
++ if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
++ DC_LOG_PFLIP("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p]\n",
++ amdgpu_crtc->pflip_status,
++ AMDGPU_FLIP_SUBMITTED,
++ amdgpu_crtc->crtc_id,
++ amdgpu_crtc);
+ spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
+ return;
+ }
+@@ -861,7 +861,7 @@ static int dm_set_powergating_state(void
+ }
+
+ /* Prototypes of private functions */
+-static int dm_early_init(void* handle);
++static int dm_early_init(void *handle);
+
+ /* Allocate memory for FBC compressed data */
+ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
+@@ -1260,7 +1260,7 @@ static void mmhub_read_system_context(st
+ pa_config->system_aperture.start_addr = (uint64_t)logical_addr_low << 18;
+ pa_config->system_aperture.end_addr = (uint64_t)logical_addr_high << 18;
+
+- pa_config->system_aperture.agp_base = (uint64_t)agp_base << 24 ;
++ pa_config->system_aperture.agp_base = (uint64_t)agp_base << 24;
+ pa_config->system_aperture.agp_bot = (uint64_t)agp_bot << 24;
+ pa_config->system_aperture.agp_top = (uint64_t)agp_top << 24;
+
+@@ -1343,8 +1343,7 @@ static void dm_handle_hpd_rx_offload_wor
+ DP_TEST_RESPONSE,
+ &test_response.raw,
+ sizeof(test_response));
+- }
+- else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
++ } else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
+ hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
+ dc_link_dp_allow_hpd_rx_irq(dc_link)) {
+ dc_link_dp_handle_link_loss(dc_link);
+@@ -1519,7 +1518,7 @@ static int amdgpu_dm_init(struct amdgpu_
+ mutex_init(&adev->dm.audio_lock);
+ spin_lock_init(&adev->dm.vblank_lock);
+
+- if(amdgpu_dm_irq_init(adev)) {
++ if (amdgpu_dm_irq_init(adev)) {
+ DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
+ goto error;
+ }
+@@ -1654,9 +1653,8 @@ static int amdgpu_dm_init(struct amdgpu_
+ if (amdgpu_dc_debug_mask & DC_DISABLE_STUTTER)
+ adev->dm.dc->debug.disable_stutter = true;
+
+- if (amdgpu_dc_debug_mask & DC_DISABLE_DSC) {
++ if (amdgpu_dc_debug_mask & DC_DISABLE_DSC)
+ adev->dm.dc->debug.disable_dsc = true;
+- }
+
+ if (amdgpu_dc_debug_mask & DC_DISABLE_CLOCK_GATING)
+ adev->dm.dc->debug.disable_clock_gate = true;
+@@ -1877,8 +1875,6 @@ static void amdgpu_dm_fini(struct amdgpu
+ mutex_destroy(&adev->dm.audio_lock);
+ mutex_destroy(&adev->dm.dc_lock);
+ mutex_destroy(&adev->dm.dpia_aux_lock);
+-
+- return;
+ }
+
+ static int load_dmcu_fw(struct amdgpu_device *adev)
+@@ -1887,7 +1883,7 @@ static int load_dmcu_fw(struct amdgpu_de
+ int r;
+ const struct dmcu_firmware_header_v1_0 *hdr;
+
+- switch(adev->asic_type) {
++ switch (adev->asic_type) {
+ #if defined(CONFIG_DRM_AMD_DC_SI)
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+@@ -2679,7 +2675,7 @@ static void dm_gpureset_commit_state(str
+ struct dc_scaling_info scaling_infos[MAX_SURFACES];
+ struct dc_flip_addrs flip_addrs[MAX_SURFACES];
+ struct dc_stream_update stream_update;
+- } * bundle;
++ } *bundle;
+ int k, m;
+
+ bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
+@@ -2709,8 +2705,6 @@ static void dm_gpureset_commit_state(str
+
+ cleanup:
+ kfree(bundle);
+-
+- return;
+ }
+
+ static int dm_resume(void *handle)
+@@ -2924,8 +2918,7 @@ static const struct amd_ip_funcs amdgpu_
+ .set_powergating_state = dm_set_powergating_state,
+ };
+
+-const struct amdgpu_ip_block_version dm_ip_block =
+-{
++const struct amdgpu_ip_block_version dm_ip_block = {
+ .type = AMD_IP_BLOCK_TYPE_DCE,
+ .major = 1,
+ .minor = 0,
+@@ -2982,9 +2975,12 @@ static void update_connector_ext_caps(st
+ caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
+ caps->aux_support = false;
+
+- if (caps->ext_caps->bits.oled == 1 /*||
+- caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
+- caps->ext_caps->bits.hdr_aux_backlight_control == 1*/)
++ if (caps->ext_caps->bits.oled == 1
++ /*
++ * ||
++ * caps->ext_caps->bits.sdr_aux_backlight_control == 1 ||
++ * caps->ext_caps->bits.hdr_aux_backlight_control == 1
++ */)
+ caps->aux_support = true;
+
+ if (amdgpu_backlight == 0)
+@@ -3248,6 +3244,7 @@ static void dm_handle_mst_sideband_msg(s
+ process_count < max_process_count) {
+ u8 ack[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = {};
+ u8 retry;
++
+ dret = 0;
+
+ process_count++;
+@@ -3449,7 +3446,7 @@ static void register_hpd_handlers(struct
+ aconnector = to_amdgpu_dm_connector(connector);
+ dc_link = aconnector->dc_link;
+
+- if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd) {
++ if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
+ int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
+ int_params.irq_source = dc_link->irq_source_hpd;
+
+@@ -3458,7 +3455,7 @@ static void register_hpd_handlers(struct
+ (void *) aconnector);
+ }
+
+- if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
++ if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) {
+
+ /* Also register for DP short pulse (hpd_rx). */
+ int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
+@@ -3484,7 +3481,7 @@ static int dce60_register_irq_handlers(s
+ struct dc_interrupt_params int_params = {0};
+ int r;
+ int i;
+- unsigned client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
++ unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
+
+ int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+ int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+@@ -3498,11 +3495,12 @@ static int dce60_register_irq_handlers(s
+ * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+ * coming from DC hardware.
+ * amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+- * for acknowledging and handling. */
++ * for acknowledging and handling.
++ */
+
+ /* Use VBLANK interrupt */
+ for (i = 0; i < adev->mode_info.num_crtc; i++) {
+- r = amdgpu_irq_add_id(adev, client_id, i+1 , &adev->crtc_irq);
++ r = amdgpu_irq_add_id(adev, client_id, i + 1, &adev->crtc_irq);
+ if (r) {
+ DRM_ERROR("Failed to add crtc irq id!\n");
+ return r;
+@@ -3510,7 +3508,7 @@ static int dce60_register_irq_handlers(s
+
+ int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+ int_params.irq_source =
+- dc_interrupt_to_irq_source(dc, i+1 , 0);
++ dc_interrupt_to_irq_source(dc, i + 1, 0);
+
+ c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
+
+@@ -3566,7 +3564,7 @@ static int dce110_register_irq_handlers(
+ struct dc_interrupt_params int_params = {0};
+ int r;
+ int i;
+- unsigned client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
++ unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY;
+
+ if (adev->family >= AMDGPU_FAMILY_AI)
+ client_id = SOC15_IH_CLIENTID_DCE;
+@@ -3583,7 +3581,8 @@ static int dce110_register_irq_handlers(
+ * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+ * coming from DC hardware.
+ * amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+- * for acknowledging and handling. */
++ * for acknowledging and handling.
++ */
+
+ /* Use VBLANK interrupt */
+ for (i = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0; i <= VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0; i++) {
+@@ -4032,7 +4031,7 @@ static void amdgpu_dm_update_backlight_c
+ }
+
+ static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps,
+- unsigned *min, unsigned *max)
++ unsigned int *min, unsigned int *max)
+ {
+ if (!caps)
+ return 0;
+@@ -4052,7 +4051,7 @@ static int get_brightness_range(const st
+ static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps,
+ uint32_t brightness)
+ {
+- unsigned min, max;
++ unsigned int min, max;
+
+ if (!get_brightness_range(caps, &min, &max))
+ return brightness;
+@@ -4065,7 +4064,7 @@ static u32 convert_brightness_from_user(
+ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps,
+ uint32_t brightness)
+ {
+- unsigned min, max;
++ unsigned int min, max;
+
+ if (!get_brightness_range(caps, &min, &max))
+ return brightness;
+@@ -4546,7 +4545,6 @@ fail:
+ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm)
+ {
+ drm_atomic_private_obj_fini(&dm->atomic_obj);
+- return;
+ }
+
+ /******************************************************************************
+@@ -5272,6 +5270,7 @@ static bool adjust_colour_depth_from_dis
+ {
+ enum dc_color_depth depth = timing_out->display_color_depth;
+ int normalized_clk;
++
+ do {
+ normalized_clk = timing_out->pix_clk_100hz / 10;
+ /* YCbCr 4:2:0 requires additional adjustment of 1/2 */
+@@ -5487,6 +5486,7 @@ create_fake_sink(struct amdgpu_dm_connec
+ {
+ struct dc_sink_init_data sink_init_data = { 0 };
+ struct dc_sink *sink = NULL;
++
+ sink_init_data.link = aconnector->dc_link;
+ sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
+
+@@ -5610,7 +5610,7 @@ get_highest_refresh_rate_mode(struct amd
+ return &aconnector->freesync_vid_base;
+
+ /* Find the preferred mode */
+- list_for_each_entry (m, list_head, head) {
++ list_for_each_entry(m, list_head, head) {
+ if (m->type & DRM_MODE_TYPE_PREFERRED) {
+ m_pref = m;
+ break;
+@@ -5634,7 +5634,7 @@ get_highest_refresh_rate_mode(struct amd
+ * For some monitors, preferred mode is not the mode with highest
+ * supported refresh rate.
+ */
+- list_for_each_entry (m, list_head, head) {
++ list_for_each_entry(m, list_head, head) {
+ current_refresh = drm_mode_vrefresh(m);
+
+ if (m->hdisplay == m_pref->hdisplay &&
+@@ -5905,7 +5905,7 @@ create_stream_for_sink(struct amdgpu_dm_
+ * This may not be an error, the use case is when we have no
+ * usermode calls to reset and set mode upon hotplug. In this
+ * case, we call set mode ourselves to restore the previous mode
+- * and the modelist may not be filled in in time.
++ * and the modelist may not be filled in time.
+ */
+ DRM_DEBUG_DRIVER("No preferred mode found\n");
+ } else {
+@@ -5929,9 +5929,9 @@ create_stream_for_sink(struct amdgpu_dm_
+ drm_mode_set_crtcinfo(&mode, 0);
+
+ /*
+- * If scaling is enabled and refresh rate didn't change
+- * we copy the vic and polarities of the old timings
+- */
++ * If scaling is enabled and refresh rate didn't change
++ * we copy the vic and polarities of the old timings
++ */
+ if (!scale || mode_refresh != preferred_refresh)
+ fill_stream_properties_from_drm_display_mode(
+ stream, &mode, &aconnector->base, con_state, NULL,
+@@ -6593,6 +6593,7 @@ static int dm_encoder_helper_atomic_chec
+
+ if (!state->duplicated) {
+ int max_bpc = conn_state->max_requested_bpc;
++
+ is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) &&
+ aconnector->force_yuv420_output;
+ color_depth = convert_color_depth_from_display_info(connector,
+@@ -6913,7 +6914,7 @@ static bool is_duplicate_mode(struct amd
+ {
+ struct drm_display_mode *m;
+
+- list_for_each_entry (m, &aconnector->base.probed_modes, head) {
++ list_for_each_entry(m, &aconnector->base.probed_modes, head) {
+ if (drm_mode_equal(m, mode))
+ return true;
+ }
+@@ -7216,7 +7217,6 @@ static int amdgpu_dm_connector_init(stru
+
+ link->priv = aconnector;
+
+- DRM_DEBUG_DRIVER("%s()\n", __func__);
+
+ i2c = create_i2c(link->ddc, link->link_index, &res);
+ if (!i2c) {
+@@ -7861,8 +7861,7 @@ static void amdgpu_dm_commit_planes(stru
+ * DRI3/Present extension with defined target_msc.
+ */
+ last_flip_vblank = amdgpu_get_vblank_counter_kms(pcrtc);
+- }
+- else {
++ } else {
+ /* For variable refresh rate mode only:
+ * Get vblank of last completed flip to avoid > 1 vrr
+ * flips per video frame by use of throttling, but allow
+@@ -8189,8 +8188,8 @@ static void amdgpu_dm_atomic_commit_tail
+ dc_resource_state_copy_construct_current(dm->dc, dc_state);
+ }
+
+- for_each_oldnew_crtc_in_state (state, crtc, old_crtc_state,
+- new_crtc_state, i) {
++ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
++ new_crtc_state, i) {
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+@@ -8213,9 +8212,7 @@ static void amdgpu_dm_atomic_commit_tail
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+ drm_dbg_state(state->dev,
+- "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
+- "planes_changed:%d, mode_changed:%d,active_changed:%d,"
+- "connectors_changed:%d\n",
++ "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, planes_changed:%d, mode_changed:%d,active_changed:%d,connectors_changed:%d\n",
+ acrtc->crtc_id,
+ new_crtc_state->enable,
+ new_crtc_state->active,
+@@ -8700,8 +8697,8 @@ static int do_aquire_global_lock(struct
+ &commit->flip_done, 10*HZ);
+
+ if (ret == 0)
+- DRM_ERROR("[CRTC:%d:%s] hw_done or flip_done "
+- "timed out\n", crtc->base.id, crtc->name);
++ DRM_ERROR("[CRTC:%d:%s] hw_done or flip_done timed out\n",
++ crtc->base.id, crtc->name);
+
+ drm_crtc_commit_put(commit);
+ }
+@@ -8786,7 +8783,8 @@ is_timing_unchanged_for_freesync(struct
+ return false;
+ }
+
+-static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) {
++static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
++{
+ u64 num, den, res;
+ struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
+
+@@ -8909,9 +8907,7 @@ static int dm_update_crtc_state(struct a
+ goto skip_modeset;
+
+ drm_dbg_state(state->dev,
+- "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
+- "planes_changed:%d, mode_changed:%d,active_changed:%d,"
+- "connectors_changed:%d\n",
++ "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, planes_changed:%d, mode_changed:%d,active_changed:%d,connectors_changed:%d\n",
+ acrtc->crtc_id,
+ new_crtc_state->enable,
+ new_crtc_state->active,
+@@ -8940,8 +8936,7 @@ static int dm_update_crtc_state(struct a
+ old_crtc_state)) {
+ new_crtc_state->mode_changed = false;
+ DRM_DEBUG_DRIVER(
+- "Mode change not required for front porch change, "
+- "setting mode_changed to %d",
++ "Mode change not required for front porch change, setting mode_changed to %d",
+ new_crtc_state->mode_changed);
+
+ set_freesync_fixed_config(dm_new_crtc_state);
+@@ -8953,9 +8948,8 @@ static int dm_update_crtc_state(struct a
+ struct drm_display_mode *high_mode;
+
+ high_mode = get_highest_refresh_rate_mode(aconnector, false);
+- if (!drm_mode_equal(&new_crtc_state->mode, high_mode)) {
++ if (!drm_mode_equal(&new_crtc_state->mode, high_mode))
+ set_freesync_fixed_config(dm_new_crtc_state);
+- }
+ }
+
+ ret = dm_atomic_get_state(state, &dm_state);
+@@ -9123,6 +9117,7 @@ static bool should_reset_plane(struct dr
+ */
+ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) {
+ struct amdgpu_framebuffer *old_afb, *new_afb;
++
+ if (other->type == DRM_PLANE_TYPE_CURSOR)
+ continue;
+
+@@ -9221,11 +9216,12 @@ static int dm_check_cursor_fb(struct amd
+ }
+
+ /* Core DRM takes care of checking FB modifiers, so we only need to
+- * check tiling flags when the FB doesn't have a modifier. */
++ * check tiling flags when the FB doesn't have a modifier.
++ */
+ if (!(fb->flags & DRM_MODE_FB_MODIFIERS)) {
+ if (adev->family < AMDGPU_FAMILY_AI) {
+ linear = AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_2D_TILED_THIN1 &&
+- AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 &&
++ AMDGPU_TILING_GET(afb->tiling_flags, ARRAY_MODE) != DC_ARRAY_1D_TILED_THIN1 &&
+ AMDGPU_TILING_GET(afb->tiling_flags, MICRO_TILE_MODE) == 0;
+ } else {
+ linear = AMDGPU_TILING_GET(afb->tiling_flags, SWIZZLE_MODE) == 0;
+@@ -9438,12 +9434,12 @@ static int dm_check_crtc_cursor(struct d
+ /* On DCE and DCN there is no dedicated hardware cursor plane. We get a
+ * cursor per pipe but it's going to inherit the scaling and
+ * positioning from the underlying pipe. Check the cursor plane's
+- * blending properties match the underlying planes'. */
++ * blending properties match the underlying planes'.
++ */
+
+ new_cursor_state = drm_atomic_get_new_plane_state(state, cursor);
+- if (!new_cursor_state || !new_cursor_state->fb) {
++ if (!new_cursor_state || !new_cursor_state->fb)
+ return 0;
+- }
+
+ dm_get_oriented_plane_size(new_cursor_state, &cursor_src_w, &cursor_src_h);
+ cursor_scale_w = new_cursor_state->crtc_w * 1000 / cursor_src_w;
+@@ -9489,6 +9485,7 @@ static int add_affected_mst_dsc_crtcs(st
+ struct drm_connector_state *conn_state, *old_conn_state;
+ struct amdgpu_dm_connector *aconnector = NULL;
+ int i;
++
+ for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) {
+ if (!conn_state->crtc)
+ conn_state = old_conn_state;
+@@ -9931,7 +9928,7 @@ static int amdgpu_dm_atomic_check(struct
+ }
+
+ /* Store the overall update type for use later in atomic check. */
+- for_each_new_crtc_in_state (state, crtc, new_crtc_state, i) {
++ for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+ struct dm_crtc_state *dm_new_crtc_state =
+ to_dm_crtc_state(new_crtc_state);
+
+@@ -9953,7 +9950,7 @@ fail:
+ else if (ret == -EINTR || ret == -EAGAIN || ret == -ERESTARTSYS)
+ DRM_DEBUG_DRIVER("Atomic check stopped due to signal.\n");
+ else
+- DRM_DEBUG_DRIVER("Atomic check failed with err: %d \n", ret);
++ DRM_DEBUG_DRIVER("Atomic check failed with err: %d\n", ret);
+
+ trace_amdgpu_dm_atomic_check_finish(state, ret);
+
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:54 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:37 -0500
+Subject: drm/amd/display: fix linux dp link lost handled only one time
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-7-mario.limonciello@amd.com>
+
+From: Hersen Wu <hersenxs.wu@amd.com>
+
+commit e322843e5e33e72ff218d661f3d15ff9c9f2f1b5 upstream.
+
+[Why]
+linux amdgpu defer handle link lost irq. dm add handle
+request to irq work queue for the first irq of link lost.
+if link training fails for link lost handle, link will not
+be enabled anymore.
+
+[How]
+allow adding handle request of link lost to work queue
+before running dp link training for link lost.
+
+Signed-off-by: Hersen Wu <hersenxs.wu@amd.com>
+Acked-by: Alex Hung <alex.hung@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ Modified due to not having
+ c5a31f178e352 ("drm/amd/display: move dp irq handler functions from dc_link_dp to link_dp_irq_handler")
+ until kernel 6.3-rc1.]
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 +++++++++++++++++++---
+ drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 2 -
+ drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 4 +++
+ 3 files changed, 26 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -1346,10 +1346,28 @@ static void dm_handle_hpd_rx_offload_wor
+ } else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
+ hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
+ dc_link_dp_allow_hpd_rx_irq(dc_link)) {
+- dc_link_dp_handle_link_loss(dc_link);
++ /* offload_work->data is from handle_hpd_rx_irq->
++ * schedule_hpd_rx_offload_work.this is defer handle
++ * for hpd short pulse. upon here, link status may be
++ * changed, need get latest link status from dpcd
++ * registers. if link status is good, skip run link
++ * training again.
++ */
++ union hpd_irq_data irq_data;
++
++ memset(&irq_data, 0, sizeof(irq_data));
++
++ /* before dc_link_dp_handle_link_loss, allow new link lost handle
++ * request be added to work queue if link lost at end of dc_link_
++ * dp_handle_link_loss
++ */
+ spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags);
+ offload_work->offload_wq->is_handling_link_loss = false;
+ spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags);
++
++ if ((read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) &&
++ hpd_rx_irq_check_link_loss_status(dc_link, &irq_data))
++ dc_link_dp_handle_link_loss(dc_link);
+ }
+ mutex_unlock(&adev->dm.dc_lock);
+
+@@ -3324,7 +3342,7 @@ static void handle_hpd_rx_irq(void *para
+ union hpd_irq_data hpd_irq_data;
+ bool link_loss = false;
+ bool has_left_work = false;
+- int idx = aconnector->base.index;
++ int idx = dc_link->link_index;
+ struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx];
+
+ memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
+@@ -3466,7 +3484,7 @@ static void register_hpd_handlers(struct
+ (void *) aconnector);
+
+ if (adev->dm.hpd_rx_offload_wq)
+- adev->dm.hpd_rx_offload_wq[connector->index].aconnector =
++ adev->dm.hpd_rx_offload_wq[dc_link->link_index].aconnector =
+ aconnector;
+ }
+ }
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+@@ -3115,7 +3115,7 @@ struct dc_link_settings dp_get_max_link_
+ return max_link_cap;
+ }
+
+-static enum dc_status read_hpd_rx_irq_data(
++enum dc_status read_hpd_rx_irq_data(
+ struct dc_link *link,
+ union hpd_irq_data *irq_data)
+ {
+--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
++++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+@@ -82,6 +82,10 @@ bool perform_link_training_with_retries(
+ enum signal_type signal,
+ bool do_fallback);
+
++enum dc_status read_hpd_rx_irq_data(
++ struct dc_link *link,
++ union hpd_irq_data *irq_data);
++
+ bool hpd_rx_irq_check_link_loss_status(
+ struct dc_link *link,
+ union hpd_irq_data *hpd_irq_dpcd_data);
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:52 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:33 -0500
+Subject: drm/amd/display: fix some coding style issues
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-3-mario.limonciello@amd.com>
+
+From: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+
+commit ae67558be712237109100fd14f12378adcf24356 upstream.
+
+Fix the following checkpatch checks in amdgpu_dm.c
+
+CHECK: Prefer kernel type 'u8' over 'uint8_t'
+CHECK: Prefer kernel type 'u32' over 'uint32_t'
+CHECK: Prefer kernel type 'u64' over 'uint64_t'
+CHECK: Prefer kernel type 's32' over 'int32_t'
+
+Signed-off-by: Srinivasan Shanmugam <srinivasan.shanmugam@amd.com>
+Reviewed-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ PSR-SU support was introduced in kernel 6.2 with commits like
+ 30ebe41582d1 ("drm/amd/display: add FB_DAMAGE_CLIPS support")
+ but PSR-SU isn't enabled in 6.1.y, so this block needs to be skipped
+ when backporting. ]
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 90 +++++++++++-----------
+ 1 file changed, 45 insertions(+), 45 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -211,7 +211,7 @@ static void amdgpu_dm_destroy_drm_device
+
+ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *amdgpu_dm_connector,
+- uint32_t link_index,
++ u32 link_index,
+ struct amdgpu_encoder *amdgpu_encoder);
+ static int amdgpu_dm_encoder_init(struct drm_device *dev,
+ struct amdgpu_encoder *aencoder,
+@@ -263,7 +263,7 @@ static u32 dm_vblank_get_counter(struct
+ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+ u32 *vbl, u32 *position)
+ {
+- uint32_t v_blank_start, v_blank_end, h_position, v_position;
++ u32 v_blank_start, v_blank_end, h_position, v_position;
+
+ if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
+ return -EINVAL;
+@@ -391,7 +391,7 @@ static void dm_pflip_high_irq(void *inte
+ struct amdgpu_device *adev = irq_params->adev;
+ unsigned long flags;
+ struct drm_pending_vblank_event *e;
+- uint32_t vpos, hpos, v_blank_start, v_blank_end;
++ u32 vpos, hpos, v_blank_start, v_blank_end;
+ bool vrr_active;
+
+ amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
+@@ -678,7 +678,7 @@ static void dmub_hpd_callback(struct amd
+ struct drm_connector *connector;
+ struct drm_connector_list_iter iter;
+ struct dc_link *link;
+- uint8_t link_index = 0;
++ u8 link_index = 0;
+ struct drm_device *dev;
+
+ if (adev == NULL)
+@@ -779,7 +779,7 @@ static void dm_dmub_outbox1_low_irq(void
+ struct amdgpu_device *adev = irq_params->adev;
+ struct amdgpu_display_manager *dm = &adev->dm;
+ struct dmcub_trace_buf_entry entry = { 0 };
+- uint32_t count = 0;
++ u32 count = 0;
+ struct dmub_hpd_work *dmub_hpd_wrk;
+ struct dc_link *plink = NULL;
+
+@@ -1045,7 +1045,7 @@ static int dm_dmub_hw_init(struct amdgpu
+ struct dmub_srv_hw_params hw_params;
+ enum dmub_status status;
+ const unsigned char *fw_inst_const, *fw_bss_data;
+- uint32_t i, fw_inst_const_size, fw_bss_data_size;
++ u32 i, fw_inst_const_size, fw_bss_data_size;
+ bool has_hw_support;
+
+ if (!dmub_srv)
+@@ -1206,10 +1206,10 @@ static void dm_dmub_hw_resume(struct amd
+
+ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
+ {
+- uint64_t pt_base;
+- uint32_t logical_addr_low;
+- uint32_t logical_addr_high;
+- uint32_t agp_base, agp_bot, agp_top;
++ u64 pt_base;
++ u32 logical_addr_low;
++ u32 logical_addr_high;
++ u32 agp_base, agp_bot, agp_top;
+ PHYSICAL_ADDRESS_LOC page_table_start, page_table_end, page_table_base;
+
+ memset(pa_config, 0, sizeof(*pa_config));
+@@ -2536,7 +2536,7 @@ struct amdgpu_dm_connector *
+ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
+ struct drm_crtc *crtc)
+ {
+- uint32_t i;
++ u32 i;
+ struct drm_connector_state *new_con_state;
+ struct drm_connector *connector;
+ struct drm_crtc *crtc_from_state;
+@@ -3172,8 +3172,8 @@ static void handle_hpd_irq(void *param)
+
+ static void dm_handle_mst_sideband_msg(struct amdgpu_dm_connector *aconnector)
+ {
+- uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
+- uint8_t dret;
++ u8 esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
++ u8 dret;
+ bool new_irq_handled = false;
+ int dpcd_addr;
+ int dpcd_bytes_to_read;
+@@ -3201,7 +3201,7 @@ static void dm_handle_mst_sideband_msg(s
+
+ while (dret == dpcd_bytes_to_read &&
+ process_count < max_process_count) {
+- uint8_t retry;
++ u8 retry;
+ dret = 0;
+
+ process_count++;
+@@ -3220,7 +3220,7 @@ static void dm_handle_mst_sideband_msg(s
+ dpcd_bytes_to_read - 1;
+
+ for (retry = 0; retry < 3; retry++) {
+- uint8_t wret;
++ u8 wret;
+
+ wret = drm_dp_dpcd_write(
+ &aconnector->dm_dp_aux.aux,
+@@ -4236,12 +4236,12 @@ static void amdgpu_set_panel_orientation
+ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
+ {
+ struct amdgpu_display_manager *dm = &adev->dm;
+- int32_t i;
++ s32 i;
+ struct amdgpu_dm_connector *aconnector = NULL;
+ struct amdgpu_encoder *aencoder = NULL;
+ struct amdgpu_mode_info *mode_info = &adev->mode_info;
+- uint32_t link_cnt;
+- int32_t primary_planes;
++ u32 link_cnt;
++ s32 primary_planes;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ const struct dc_plane_cap *plane;
+ bool psr_feature_enabled = false;
+@@ -4768,7 +4768,7 @@ fill_plane_color_attributes(const struct
+ static int
+ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
+ const struct drm_plane_state *plane_state,
+- const uint64_t tiling_flags,
++ const u64 tiling_flags,
+ struct dc_plane_info *plane_info,
+ struct dc_plane_address *address,
+ bool tmz_surface,
+@@ -4977,7 +4977,7 @@ static void fill_dc_dirty_rects(struct d
+ uint32_t num_clips;
+ bool bb_changed;
+ bool fb_changed;
+- uint32_t i = 0;
++ u32 i = 0;
+
+ flip_addrs->dirty_rect_count = 0;
+
+@@ -5111,7 +5111,7 @@ static enum dc_color_depth
+ convert_color_depth_from_display_info(const struct drm_connector *connector,
+ bool is_y420, int requested_bpc)
+ {
+- uint8_t bpc;
++ u8 bpc;
+
+ if (is_y420) {
+ bpc = 8;
+@@ -5655,8 +5655,8 @@ static void apply_dsc_policy_for_edp(str
+ uint32_t max_dsc_target_bpp_limit_override)
+ {
+ const struct dc_link_settings *verified_link_cap = NULL;
+- uint32_t link_bw_in_kbps;
+- uint32_t edp_min_bpp_x16, edp_max_bpp_x16;
++ u32 link_bw_in_kbps;
++ u32 edp_min_bpp_x16, edp_max_bpp_x16;
+ struct dc *dc = sink->ctx->dc;
+ struct dc_dsc_bw_range bw_range = {0};
+ struct dc_dsc_config dsc_cfg = {0};
+@@ -5713,11 +5713,11 @@ static void apply_dsc_policy_for_stream(
+ struct dsc_dec_dpcd_caps *dsc_caps)
+ {
+ struct drm_connector *drm_connector = &aconnector->base;
+- uint32_t link_bandwidth_kbps;
++ u32 link_bandwidth_kbps;
+ struct dc *dc = sink->ctx->dc;
+- uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps;
+- uint32_t dsc_max_supported_bw_in_kbps;
+- uint32_t max_dsc_target_bpp_limit_override =
++ u32 max_supported_bw_in_kbps, timing_bw_in_kbps;
++ u32 dsc_max_supported_bw_in_kbps;
++ u32 max_dsc_target_bpp_limit_override =
+ drm_connector->display_info.max_dsc_bpp;
+
+ link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
+@@ -6871,7 +6871,7 @@ static uint add_fs_modes(struct amdgpu_d
+ const struct drm_display_mode *m;
+ struct drm_display_mode *new_mode;
+ uint i;
+- uint32_t new_modes_count = 0;
++ u32 new_modes_count = 0;
+
+ /* Standard FPS values
+ *
+@@ -6885,7 +6885,7 @@ static uint add_fs_modes(struct amdgpu_d
+ * 60 - Commonly used
+ * 48,72,96,120 - Multiples of 24
+ */
+- static const uint32_t common_rates[] = {
++ static const u32 common_rates[] = {
+ 23976, 24000, 25000, 29970, 30000,
+ 48000, 50000, 60000, 72000, 96000, 120000
+ };
+@@ -6901,8 +6901,8 @@ static uint add_fs_modes(struct amdgpu_d
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(common_rates); i++) {
+- uint64_t target_vtotal, target_vtotal_diff;
+- uint64_t num, den;
++ u64 target_vtotal, target_vtotal_diff;
++ u64 num, den;
+
+ if (drm_mode_vrefresh(m) * 1000 < common_rates[i])
+ continue;
+@@ -7150,7 +7150,7 @@ create_i2c(struct ddc_service *ddc_servi
+ */
+ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *aconnector,
+- uint32_t link_index,
++ u32 link_index,
+ struct amdgpu_encoder *aencoder)
+ {
+ int res = 0;
+@@ -7641,8 +7641,8 @@ static void amdgpu_dm_commit_planes(stru
+ struct drm_crtc *pcrtc,
+ bool wait_for_vblank)
+ {
+- uint32_t i;
+- uint64_t timestamp_ns;
++ u32 i;
++ u64 timestamp_ns;
+ struct drm_plane *plane;
+ struct drm_plane_state *old_plane_state, *new_plane_state;
+ struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
+@@ -7653,7 +7653,7 @@ static void amdgpu_dm_commit_planes(stru
+ to_dm_crtc_state(drm_atomic_get_old_crtc_state(state, pcrtc));
+ int planes_count = 0, vpos, hpos;
+ unsigned long flags;
+- uint32_t target_vblank, last_flip_vblank;
++ u32 target_vblank, last_flip_vblank;
+ bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
+ bool cursor_update = false;
+ bool pflip_present = false;
+@@ -8102,7 +8102,7 @@ static void amdgpu_dm_atomic_commit_tail
+ struct amdgpu_display_manager *dm = &adev->dm;
+ struct dm_atomic_state *dm_state;
+ struct dc_state *dc_state = NULL, *dc_state_temp = NULL;
+- uint32_t i, j;
++ u32 i, j;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ unsigned long flags;
+@@ -8732,7 +8732,7 @@ is_timing_unchanged_for_freesync(struct
+ }
+
+ static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) {
+- uint64_t num, den, res;
++ u64 num, den, res;
+ struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
+
+ dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
+@@ -9908,7 +9908,7 @@ fail:
+ static bool is_dp_capable_without_timing_msa(struct dc *dc,
+ struct amdgpu_dm_connector *amdgpu_dm_connector)
+ {
+- uint8_t dpcd_data;
++ u8 dpcd_data;
+ bool capable = false;
+
+ if (amdgpu_dm_connector->dc_link &&
+@@ -9927,7 +9927,7 @@ static bool is_dp_capable_without_timing
+ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm,
+ unsigned int offset,
+ unsigned int total_length,
+- uint8_t *data,
++ u8 *data,
+ unsigned int length,
+ struct amdgpu_hdmi_vsdb_info *vsdb)
+ {
+@@ -9982,7 +9982,7 @@ static bool dm_edid_parser_send_cea(stru
+ }
+
+ static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm,
+- uint8_t *edid_ext, int len,
++ u8 *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+ int i;
+@@ -10023,7 +10023,7 @@ static bool parse_edid_cea_dmcu(struct a
+ }
+
+ static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm,
+- uint8_t *edid_ext, int len,
++ u8 *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+ int i;
+@@ -10039,7 +10039,7 @@ static bool parse_edid_cea_dmub(struct a
+ }
+
+ static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector,
+- uint8_t *edid_ext, int len,
++ u8 *edid_ext, int len,
+ struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+ struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev);
+@@ -10053,7 +10053,7 @@ static bool parse_edid_cea(struct amdgpu
+ static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector,
+ struct edid *edid, struct amdgpu_hdmi_vsdb_info *vsdb_info)
+ {
+- uint8_t *edid_ext = NULL;
++ u8 *edid_ext = NULL;
+ int i;
+ bool valid_vsdb_found = false;
+
+@@ -10229,7 +10229,7 @@ void amdgpu_dm_trigger_timing_sync(struc
+ }
+
+ void dm_write_reg_func(const struct dc_context *ctx, uint32_t address,
+- uint32_t value, const char *func_name)
++ u32 value, const char *func_name)
+ {
+ #ifdef DM_CHECK_ADDR_0
+ if (address == 0) {
+@@ -10244,7 +10244,7 @@ void dm_write_reg_func(const struct dc_c
+ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address,
+ const char *func_name)
+ {
+- uint32_t value;
++ u32 value;
+ #ifdef DM_CHECK_ADDR_0
+ if (address == 0) {
+ DC_ERR("invalid register read; address = 0\n");
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:59 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:35 -0500
+Subject: drm/amd/display: force connector state when bpc changes during compliance
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-5-mario.limonciello@amd.com>
+
+From: Qingqing Zhuo <qingqing.zhuo@amd.com>
+
+commit 028c4ccfb8127255d60f8d9edde96cacf2958082 upstream.
+
+[Why]
+During DP DSC compliance tests, bpc requested would
+change between sub-tests, which requires stream
+to be recommited.
+
+[How]
+Force connector to disconnect and reconnect whenever
+there is a bpc change in automated test.
+
+Reviewed-by: Jerry Zuo <Jerry.Zuo@amd.com>
+Acked-by: Alan Liu <HaoPing.Liu@amd.com>
+Signed-off-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
+Signed-off-by: hersen wu <hersenxs.wu@amd.com>
+Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+[ Adjustments for headers that were moved around in later commits. ]
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 55 +++++
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 125 ++++++++++++
+ drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 139 +-------------
+ drivers/gpu/drm/amd/display/dc/dm_helpers.h | 6
+ 5 files changed, 209 insertions(+), 121 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -40,6 +40,9 @@
+ #include "dc/dc_stat.h"
+ #include "amdgpu_dm_trace.h"
+ #include "dc/inc/dc_link_ddc.h"
++#include "dpcd_defs.h"
++#include "dc/inc/link_dpcd.h"
++#include "link_service_types.h"
+
+ #include "vid.h"
+ #include "amdgpu.h"
+@@ -1273,6 +1276,21 @@ static void mmhub_read_system_context(st
+
+ }
+
++static void force_connector_state(
++ struct amdgpu_dm_connector *aconnector,
++ enum drm_connector_force force_state)
++{
++ struct drm_connector *connector = &aconnector->base;
++
++ mutex_lock(&connector->dev->mode_config.mutex);
++ aconnector->base.force = force_state;
++ mutex_unlock(&connector->dev->mode_config.mutex);
++
++ mutex_lock(&aconnector->hpd_lock);
++ drm_kms_helper_connector_hotplug_event(connector);
++ mutex_unlock(&aconnector->hpd_lock);
++}
++
+ static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
+ {
+ struct hpd_rx_irq_offload_work *offload_work;
+@@ -1281,6 +1299,9 @@ static void dm_handle_hpd_rx_offload_wor
+ struct amdgpu_device *adev;
+ enum dc_connection_type new_connection_type = dc_connection_none;
+ unsigned long flags;
++ union test_response test_response;
++
++ memset(&test_response, 0, sizeof(test_response));
+
+ offload_work = container_of(work, struct hpd_rx_irq_offload_work, work);
+ aconnector = offload_work->offload_wq->aconnector;
+@@ -1305,8 +1326,24 @@ static void dm_handle_hpd_rx_offload_wor
+ goto skip;
+
+ mutex_lock(&adev->dm.dc_lock);
+- if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST)
++ if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) {
+ dc_link_dp_handle_automated_test(dc_link);
++
++ if (aconnector->timing_changed) {
++ /* force connector disconnect and reconnect */
++ force_connector_state(aconnector, DRM_FORCE_OFF);
++ msleep(100);
++ force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED);
++ }
++
++ test_response.bits.ACK = 1;
++
++ core_link_write_dpcd(
++ dc_link,
++ DP_TEST_RESPONSE,
++ &test_response.raw,
++ sizeof(test_response));
++ }
+ else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) &&
+ hpd_rx_irq_check_link_loss_status(dc_link, &offload_work->data) &&
+ dc_link_dp_allow_hpd_rx_irq(dc_link)) {
+@@ -3076,6 +3113,10 @@ void amdgpu_dm_update_connector_after_de
+ aconnector->edid);
+ }
+
++ aconnector->timing_requested = kzalloc(sizeof(struct dc_crtc_timing), GFP_KERNEL);
++ if (!aconnector->timing_requested)
++ dm_error("%s: failed to create aconnector->requested_timing\n", __func__);
++
+ drm_connector_update_edid_property(connector, aconnector->edid);
+ amdgpu_dm_update_freesync_caps(connector, aconnector->edid);
+ update_connector_ext_caps(aconnector);
+@@ -3087,6 +3128,8 @@ void amdgpu_dm_update_connector_after_de
+ dc_sink_release(aconnector->dc_sink);
+ aconnector->dc_sink = NULL;
+ aconnector->edid = NULL;
++ kfree(aconnector->timing_requested);
++ aconnector->timing_requested = NULL;
+ #ifdef CONFIG_DRM_AMD_DC_HDCP
+ /* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */
+ if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+@@ -3131,6 +3174,8 @@ static void handle_hpd_irq_helper(struct
+ if (aconnector->fake_enable)
+ aconnector->fake_enable = false;
+
++ aconnector->timing_changed = false;
++
+ if (!dc_link_detect_sink(aconnector->dc_link, &new_connection_type))
+ DRM_ERROR("KMS: Failed to detect connector\n");
+
+@@ -5896,6 +5941,14 @@ create_stream_for_sink(struct amdgpu_dm_
+ stream, &mode, &aconnector->base, con_state, old_stream,
+ requested_bpc);
+
++ if (aconnector->timing_changed) {
++ DC_LOG_DEBUG("%s: overriding timing for automated test, bpc %d, changing to %d\n",
++ __func__,
++ stream->timing.display_color_depth,
++ aconnector->timing_requested->display_color_depth);
++ stream->timing = *aconnector->timing_requested;
++ }
++
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
+ /* SST DSC determination policy */
+ update_dsc_caps(aconnector, sink, stream, &dsc_caps);
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+@@ -31,6 +31,7 @@
+ #include <drm/drm_connector.h>
+ #include <drm/drm_crtc.h>
+ #include <drm/drm_plane.h>
++#include "link_service_types.h"
+
+ /*
+ * This file contains the definition for amdgpu_display_manager
+@@ -650,6 +651,10 @@ struct amdgpu_dm_connector {
+
+ /* Record progress status of mst*/
+ uint8_t mst_status;
++
++ /* Automated testing */
++ bool timing_changed;
++ struct dc_crtc_timing *timing_requested;
+ };
+
+ static inline void amdgpu_dm_set_mst_status(uint8_t *status,
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+@@ -38,6 +38,9 @@
+ #include "amdgpu_dm.h"
+ #include "amdgpu_dm_irq.h"
+ #include "amdgpu_dm_mst_types.h"
++#include "dpcd_defs.h"
++#include "dc/inc/core_types.h"
++#include "dc_link_dp.h"
+
+ #include "dm_helpers.h"
+ #include "ddc_service_types.h"
+@@ -1056,6 +1059,128 @@ void dm_helpers_mst_enable_stream_featur
+ sizeof(new_downspread));
+ }
+
++bool dm_helpers_dp_handle_test_pattern_request(
++ struct dc_context *ctx,
++ const struct dc_link *link,
++ union link_test_pattern dpcd_test_pattern,
++ union test_misc dpcd_test_params)
++{
++ enum dp_test_pattern test_pattern;
++ enum dp_test_pattern_color_space test_pattern_color_space =
++ DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
++ enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
++ enum dc_pixel_encoding requestPixelEncoding = PIXEL_ENCODING_UNDEFINED;
++ struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
++ struct pipe_ctx *pipe_ctx = NULL;
++ struct amdgpu_dm_connector *aconnector = link->priv;
++ int i;
++
++ for (i = 0; i < MAX_PIPES; i++) {
++ if (pipes[i].stream == NULL)
++ continue;
++
++ if (pipes[i].stream->link == link && !pipes[i].top_pipe &&
++ !pipes[i].prev_odm_pipe) {
++ pipe_ctx = &pipes[i];
++ break;
++ }
++ }
++
++ if (pipe_ctx == NULL)
++ return false;
++
++ switch (dpcd_test_pattern.bits.PATTERN) {
++ case LINK_TEST_PATTERN_COLOR_RAMP:
++ test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
++ break;
++ case LINK_TEST_PATTERN_VERTICAL_BARS:
++ test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
++ break; /* black and white */
++ case LINK_TEST_PATTERN_COLOR_SQUARES:
++ test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
++ TEST_DYN_RANGE_VESA ?
++ DP_TEST_PATTERN_COLOR_SQUARES :
++ DP_TEST_PATTERN_COLOR_SQUARES_CEA);
++ break;
++ default:
++ test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
++ break;
++ }
++
++ if (dpcd_test_params.bits.CLR_FORMAT == 0)
++ test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
++ else
++ test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
++ DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
++ DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
++
++ switch (dpcd_test_params.bits.BPC) {
++ case 0: // 6 bits
++ requestColorDepth = COLOR_DEPTH_666;
++ break;
++ case 1: // 8 bits
++ requestColorDepth = COLOR_DEPTH_888;
++ break;
++ case 2: // 10 bits
++ requestColorDepth = COLOR_DEPTH_101010;
++ break;
++ case 3: // 12 bits
++ requestColorDepth = COLOR_DEPTH_121212;
++ break;
++ default:
++ break;
++ }
++
++ switch (dpcd_test_params.bits.CLR_FORMAT) {
++ case 0:
++ requestPixelEncoding = PIXEL_ENCODING_RGB;
++ break;
++ case 1:
++ requestPixelEncoding = PIXEL_ENCODING_YCBCR422;
++ break;
++ case 2:
++ requestPixelEncoding = PIXEL_ENCODING_YCBCR444;
++ break;
++ default:
++ requestPixelEncoding = PIXEL_ENCODING_RGB;
++ break;
++ }
++
++ if ((requestColorDepth != COLOR_DEPTH_UNDEFINED
++ && pipe_ctx->stream->timing.display_color_depth != requestColorDepth)
++ || (requestPixelEncoding != PIXEL_ENCODING_UNDEFINED
++ && pipe_ctx->stream->timing.pixel_encoding != requestPixelEncoding)) {
++ DC_LOG_DEBUG("%s: original bpc %d pix encoding %d, changing to %d %d\n",
++ __func__,
++ pipe_ctx->stream->timing.display_color_depth,
++ pipe_ctx->stream->timing.pixel_encoding,
++ requestColorDepth,
++ requestPixelEncoding);
++ pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
++ pipe_ctx->stream->timing.pixel_encoding = requestPixelEncoding;
++
++ dp_update_dsc_config(pipe_ctx);
++
++ aconnector->timing_changed = true;
++ /* store current timing */
++ if (aconnector->timing_requested)
++ *aconnector->timing_requested = pipe_ctx->stream->timing;
++ else
++ DC_LOG_ERROR("%s: timing storage failed\n", __func__);
++
++ }
++
++ dc_link_dp_set_test_pattern(
++ (struct dc_link *) link,
++ test_pattern,
++ test_pattern_color_space,
++ NULL,
++ NULL,
++ 0);
++
++ return false;
++}
++
+ void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
+ {
+ // TODO
+--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
++++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+@@ -4264,124 +4264,6 @@ static void dp_test_send_phy_test_patter
+ test_pattern_size);
+ }
+
+-static void dp_test_send_link_test_pattern(struct dc_link *link)
+-{
+- union link_test_pattern dpcd_test_pattern;
+- union test_misc dpcd_test_params;
+- enum dp_test_pattern test_pattern;
+- enum dp_test_pattern_color_space test_pattern_color_space =
+- DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED;
+- enum dc_color_depth requestColorDepth = COLOR_DEPTH_UNDEFINED;
+- struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
+- struct pipe_ctx *pipe_ctx = NULL;
+- int i;
+-
+- memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
+- memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
+-
+- for (i = 0; i < MAX_PIPES; i++) {
+- if (pipes[i].stream == NULL)
+- continue;
+-
+- if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
+- pipe_ctx = &pipes[i];
+- break;
+- }
+- }
+-
+- if (pipe_ctx == NULL)
+- return;
+-
+- /* get link test pattern and pattern parameters */
+- core_link_read_dpcd(
+- link,
+- DP_TEST_PATTERN,
+- &dpcd_test_pattern.raw,
+- sizeof(dpcd_test_pattern));
+- core_link_read_dpcd(
+- link,
+- DP_TEST_MISC0,
+- &dpcd_test_params.raw,
+- sizeof(dpcd_test_params));
+-
+- switch (dpcd_test_pattern.bits.PATTERN) {
+- case LINK_TEST_PATTERN_COLOR_RAMP:
+- test_pattern = DP_TEST_PATTERN_COLOR_RAMP;
+- break;
+- case LINK_TEST_PATTERN_VERTICAL_BARS:
+- test_pattern = DP_TEST_PATTERN_VERTICAL_BARS;
+- break; /* black and white */
+- case LINK_TEST_PATTERN_COLOR_SQUARES:
+- test_pattern = (dpcd_test_params.bits.DYN_RANGE ==
+- TEST_DYN_RANGE_VESA ?
+- DP_TEST_PATTERN_COLOR_SQUARES :
+- DP_TEST_PATTERN_COLOR_SQUARES_CEA);
+- break;
+- default:
+- test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
+- break;
+- }
+-
+- if (dpcd_test_params.bits.CLR_FORMAT == 0)
+- test_pattern_color_space = DP_TEST_PATTERN_COLOR_SPACE_RGB;
+- else
+- test_pattern_color_space = dpcd_test_params.bits.YCBCR_COEFS ?
+- DP_TEST_PATTERN_COLOR_SPACE_YCBCR709 :
+- DP_TEST_PATTERN_COLOR_SPACE_YCBCR601;
+-
+- switch (dpcd_test_params.bits.BPC) {
+- case 0: // 6 bits
+- requestColorDepth = COLOR_DEPTH_666;
+- break;
+- case 1: // 8 bits
+- requestColorDepth = COLOR_DEPTH_888;
+- break;
+- case 2: // 10 bits
+- requestColorDepth = COLOR_DEPTH_101010;
+- break;
+- case 3: // 12 bits
+- requestColorDepth = COLOR_DEPTH_121212;
+- break;
+- default:
+- break;
+- }
+-
+- switch (dpcd_test_params.bits.CLR_FORMAT) {
+- case 0:
+- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
+- break;
+- case 1:
+- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR422;
+- break;
+- case 2:
+- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_YCBCR444;
+- break;
+- default:
+- pipe_ctx->stream->timing.pixel_encoding = PIXEL_ENCODING_RGB;
+- break;
+- }
+-
+-
+- if (requestColorDepth != COLOR_DEPTH_UNDEFINED
+- && pipe_ctx->stream->timing.display_color_depth != requestColorDepth) {
+- DC_LOG_DEBUG("%s: original bpc %d, changing to %d\n",
+- __func__,
+- pipe_ctx->stream->timing.display_color_depth,
+- requestColorDepth);
+- pipe_ctx->stream->timing.display_color_depth = requestColorDepth;
+- }
+-
+- dp_update_dsc_config(pipe_ctx);
+-
+- dc_link_dp_set_test_pattern(
+- link,
+- test_pattern,
+- test_pattern_color_space,
+- NULL,
+- NULL,
+- 0);
+-}
+-
+ static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
+ {
+ union audio_test_mode dpcd_test_mode = {0};
+@@ -4494,8 +4376,25 @@ void dc_link_dp_handle_automated_test(st
+ test_response.bits.ACK = 0;
+ }
+ if (test_request.bits.LINK_TEST_PATTRN) {
+- dp_test_send_link_test_pattern(link);
+- test_response.bits.ACK = 1;
++ union test_misc dpcd_test_params;
++ union link_test_pattern dpcd_test_pattern;
++
++ memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
++ memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
++
++ /* get link test pattern and pattern parameters */
++ core_link_read_dpcd(
++ link,
++ DP_TEST_PATTERN,
++ &dpcd_test_pattern.raw,
++ sizeof(dpcd_test_pattern));
++ core_link_read_dpcd(
++ link,
++ DP_TEST_MISC0,
++ &dpcd_test_params.raw,
++ sizeof(dpcd_test_params));
++ test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link,
++ dpcd_test_pattern, dpcd_test_params) ? 1 : 0;
+ }
+
+ if (test_request.bits.AUDIO_TEST_PATTERN) {
+--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
++++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+@@ -156,6 +156,12 @@ enum dc_edid_status dm_helpers_read_loca
+ struct dc_link *link,
+ struct dc_sink *sink);
+
++bool dm_helpers_dp_handle_test_pattern_request(
++ struct dc_context *ctx,
++ const struct dc_link *link,
++ union link_test_pattern dpcd_test_pattern,
++ union test_misc dpcd_test_params);
++
+ void dm_set_dcn_clocks(
+ struct dc_context *ctx,
+ struct dc_clocks *clks);
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:26:52 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:32 -0500
+Subject: drm/amd/display: use max_dsc_bpp in amdgpu_dm
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-2-mario.limonciello@amd.com>
+
+From: Hamza Mahfooz <hamza.mahfooz@amd.com>
+
+commit 6e5abe94c6eb9b281398e39819217e8fdd1c336f upstream.
+
+Since, the quirk is handled in the DRM core now, we can use that value
+instead of the internal value.
+
+Reviewed-by: Harry Wentland <harry.wentland@amd.com>
+Signed-off-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++----
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 11 +++++++++--
+ 2 files changed, 11 insertions(+), 6 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -5714,16 +5714,14 @@ static void apply_dsc_policy_for_stream(
+ {
+ struct drm_connector *drm_connector = &aconnector->base;
+ uint32_t link_bandwidth_kbps;
+- uint32_t max_dsc_target_bpp_limit_override = 0;
+ struct dc *dc = sink->ctx->dc;
+ uint32_t max_supported_bw_in_kbps, timing_bw_in_kbps;
+ uint32_t dsc_max_supported_bw_in_kbps;
++ uint32_t max_dsc_target_bpp_limit_override =
++ drm_connector->display_info.max_dsc_bpp;
+
+ link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link,
+ dc_link_get_link_cap(aconnector->dc_link));
+- if (stream->link && stream->link->local_sink)
+- max_dsc_target_bpp_limit_override =
+- stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
+
+ /* Set DSC policy according to dsc_clock_en */
+ dc_dsc_policy_set_enable_dsc_when_not_needed(
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+@@ -673,15 +673,18 @@ static void set_dsc_configs_from_fairnes
+ int count,
+ int k)
+ {
++ struct drm_connector *drm_connector;
+ int i;
+
+ for (i = 0; i < count; i++) {
++ drm_connector = ¶ms[i].aconnector->base;
++
+ memset(¶ms[i].timing->dsc_cfg, 0, sizeof(params[i].timing->dsc_cfg));
+ if (vars[i + k].dsc_enabled && dc_dsc_compute_config(
+ params[i].sink->ctx->dc->res_pool->dscs[0],
+ ¶ms[i].sink->dsc_caps.dsc_dec_caps,
+ params[i].sink->ctx->dc->debug.dsc_min_slice_height_override,
+- params[i].sink->edid_caps.panel_patch.max_dsc_target_bpp_limit,
++ drm_connector->display_info.max_dsc_bpp,
+ 0,
+ params[i].timing,
+ ¶ms[i].timing->dsc_cfg)) {
+@@ -723,12 +726,16 @@ static int bpp_x16_from_pbn(struct dsc_m
+ struct dc_dsc_config dsc_config;
+ u64 kbps;
+
++ struct drm_connector *drm_connector = ¶m.aconnector->base;
++ uint32_t max_dsc_target_bpp_limit_override =
++ drm_connector->display_info.max_dsc_bpp;
++
+ kbps = div_u64((u64)pbn * 994 * 8 * 54, 64);
+ dc_dsc_compute_config(
+ param.sink->ctx->dc->res_pool->dscs[0],
+ ¶m.sink->dsc_caps.dsc_dec_caps,
+ param.sink->ctx->dc->debug.dsc_min_slice_height_override,
+- param.sink->edid_caps.panel_patch.max_dsc_target_bpp_limit,
++ max_dsc_target_bpp_limit_override,
+ (int) kbps, param.timing, &dsc_config);
+
+ return dsc_config.bits_per_pixel;
--- /dev/null
+From stable-owner@vger.kernel.org Tue Jul 25 00:28:07 2023
+From: Mario Limonciello <mario.limonciello@amd.com>
+Date: Mon, 24 Jul 2023 17:26:34 -0500
+Subject: drm/dp_mst: Clear MSG_RDY flag before sending new message
+To: <stable@vger.kernel.org>
+Cc: Mario Limonciello <mario.limonciello@amd.com>
+Message-ID: <20230724222638.1477-4-mario.limonciello@amd.com>
+
+From: Wayne Lin <Wayne.Lin@amd.com>
+
+commit 72f1de49ffb90b29748284f27f1d6b829ab1de95 upstream.
+
+[Why]
+The sequence for collecting down_reply from source perspective should
+be:
+
+Request_n->repeat (get partial reply of Request_n->clear message ready
+flag to ack DPRX that the message is received) till all partial
+replies for Request_n are received->new Request_n+1.
+
+Now there is chance that drm_dp_mst_hpd_irq() will fire new down
+request in the tx queue when the down reply is incomplete. Source is
+restricted to generate interveleaved message transactions so we should
+avoid it.
+
+Also, while assembling partial reply packets, reading out DPCD DOWN_REP
+Sideband MSG buffer + clearing DOWN_REP_MSG_RDY flag should be
+wrapped up as a complete operation for reading out a reply packet.
+Kicking off a new request before clearing DOWN_REP_MSG_RDY flag might
+be risky. e.g. If the reply of the new request has overwritten the
+DPRX DOWN_REP Sideband MSG buffer before source writing one to clear
+DOWN_REP_MSG_RDY flag, source then unintentionally flushes the reply
+for the new request. Should handle the up request in the same way.
+
+[How]
+Separete drm_dp_mst_hpd_irq() into 2 steps. After acking the MST IRQ
+event, driver calls drm_dp_mst_hpd_irq_send_new_request() and might
+trigger drm_dp_mst_kick_tx() only when there is no on going message
+transaction.
+
+Changes since v1:
+* Reworked on review comments received
+-> Adjust the fix to let driver explicitly kick off new down request
+when mst irq event is handled and acked
+-> Adjust the commit message
+
+Changes since v2:
+* Adjust the commit message
+* Adjust the naming of the divided 2 functions and add a new input
+ parameter "ack".
+* Adjust code flow as per review comments.
+
+Changes since v3:
+* Update the function description of drm_dp_mst_hpd_irq_handle_event
+
+Changes since v4:
+* Change ack of drm_dp_mst_hpd_irq_handle_event() to be an array align
+ the size of esi[]
+
+Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
+Reviewed-by: Lyude Paul <lyude@redhat.com>
+Acked-by: Jani Nikula <jani.nikula@intel.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 30 ++++++------
+ drivers/gpu/drm/display/drm_dp_mst_topology.c | 54 +++++++++++++++++++---
+ drivers/gpu/drm/i915/display/intel_dp.c | 7 +-
+ drivers/gpu/drm/nouveau/dispnv50/disp.c | 12 +++-
+ include/drm/display/drm_dp_mst_helper.h | 7 ++
+ 5 files changed, 80 insertions(+), 30 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -3201,6 +3201,7 @@ static void dm_handle_mst_sideband_msg(s
+
+ while (dret == dpcd_bytes_to_read &&
+ process_count < max_process_count) {
++ u8 ack[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = {};
+ u8 retry;
+ dret = 0;
+
+@@ -3209,28 +3210,29 @@ static void dm_handle_mst_sideband_msg(s
+ DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+ /* handle HPD short pulse irq */
+ if (aconnector->mst_mgr.mst_state)
+- drm_dp_mst_hpd_irq(
+- &aconnector->mst_mgr,
+- esi,
+- &new_irq_handled);
++ drm_dp_mst_hpd_irq_handle_event(&aconnector->mst_mgr,
++ esi,
++ ack,
++ &new_irq_handled);
+
+ if (new_irq_handled) {
+ /* ACK at DPCD to notify down stream */
+- const int ack_dpcd_bytes_to_write =
+- dpcd_bytes_to_read - 1;
+-
+ for (retry = 0; retry < 3; retry++) {
+- u8 wret;
++ ssize_t wret;
+
+- wret = drm_dp_dpcd_write(
+- &aconnector->dm_dp_aux.aux,
+- dpcd_addr + 1,
+- &esi[1],
+- ack_dpcd_bytes_to_write);
+- if (wret == ack_dpcd_bytes_to_write)
++ wret = drm_dp_dpcd_writeb(&aconnector->dm_dp_aux.aux,
++ dpcd_addr + 1,
++ ack[1]);
++ if (wret == 1)
+ break;
+ }
+
++ if (retry == 3) {
++ DRM_ERROR("Failed to ack MST event.\n");
++ return;
++ }
++
++ drm_dp_mst_hpd_irq_send_new_request(&aconnector->mst_mgr);
+ /* check if there is new irq to be handled */
+ dret = drm_dp_dpcd_read(
+ &aconnector->dm_dp_aux.aux,
+--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
+@@ -4053,17 +4053,28 @@ out:
+ }
+
+ /**
+- * drm_dp_mst_hpd_irq() - MST hotplug IRQ notify
++ * drm_dp_mst_hpd_irq_handle_event() - MST hotplug IRQ handle MST event
+ * @mgr: manager to notify irq for.
+ * @esi: 4 bytes from SINK_COUNT_ESI
++ * @ack: 4 bytes used to ack events starting from SINK_COUNT_ESI
+ * @handled: whether the hpd interrupt was consumed or not
+ *
+- * This should be called from the driver when it detects a short IRQ,
++ * This should be called from the driver when it detects a HPD IRQ,
+ * along with the value of the DEVICE_SERVICE_IRQ_VECTOR_ESI0. The
+- * topology manager will process the sideband messages received as a result
+- * of this.
++ * topology manager will process the sideband messages received
++ * as indicated in the DEVICE_SERVICE_IRQ_VECTOR_ESI0 and set the
++ * corresponding flags that Driver has to ack the DP receiver later.
++ *
++ * Note that driver shall also call
++ * drm_dp_mst_hpd_irq_send_new_request() if the 'handled' is set
++ * after calling this function, to try to kick off a new request in
++ * the queue if the previous message transaction is completed.
++ *
++ * See also:
++ * drm_dp_mst_hpd_irq_send_new_request()
+ */
+-int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled)
++int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr, const u8 *esi,
++ u8 *ack, bool *handled)
+ {
+ int ret = 0;
+ int sc;
+@@ -4078,18 +4089,47 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst
+ if (esi[1] & DP_DOWN_REP_MSG_RDY) {
+ ret = drm_dp_mst_handle_down_rep(mgr);
+ *handled = true;
++ ack[1] |= DP_DOWN_REP_MSG_RDY;
+ }
+
+ if (esi[1] & DP_UP_REQ_MSG_RDY) {
+ ret |= drm_dp_mst_handle_up_req(mgr);
+ *handled = true;
++ ack[1] |= DP_UP_REQ_MSG_RDY;
+ }
+
+- drm_dp_mst_kick_tx(mgr);
+ return ret;
+ }
+-EXPORT_SYMBOL(drm_dp_mst_hpd_irq);
++EXPORT_SYMBOL(drm_dp_mst_hpd_irq_handle_event);
++
++/**
++ * drm_dp_mst_hpd_irq_send_new_request() - MST hotplug IRQ kick off new request
++ * @mgr: manager to notify irq for.
++ *
++ * This should be called from the driver when mst irq event is handled
++ * and acked. Note that new down request should only be sent when
++ * previous message transaction is completed. Source is not supposed to generate
++ * interleaved message transactions.
++ */
++void drm_dp_mst_hpd_irq_send_new_request(struct drm_dp_mst_topology_mgr *mgr)
++{
++ struct drm_dp_sideband_msg_tx *txmsg;
++ bool kick = true;
+
++ mutex_lock(&mgr->qlock);
++ txmsg = list_first_entry_or_null(&mgr->tx_msg_downq,
++ struct drm_dp_sideband_msg_tx, next);
++ /* If last transaction is not completed yet*/
++ if (!txmsg ||
++ txmsg->state == DRM_DP_SIDEBAND_TX_START_SEND ||
++ txmsg->state == DRM_DP_SIDEBAND_TX_SENT)
++ kick = false;
++ mutex_unlock(&mgr->qlock);
++
++ if (kick)
++ drm_dp_mst_kick_tx(mgr);
++}
++EXPORT_SYMBOL(drm_dp_mst_hpd_irq_send_new_request);
+ /**
+ * drm_dp_mst_detect_port() - get connection status for an MST port
+ * @connector: DRM connector for this port
+--- a/drivers/gpu/drm/i915/display/intel_dp.c
++++ b/drivers/gpu/drm/i915/display/intel_dp.c
+@@ -3804,9 +3804,7 @@ intel_dp_mst_hpd_irq(struct intel_dp *in
+ {
+ bool handled = false;
+
+- drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
+- if (handled)
+- ack[1] |= esi[1] & (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY);
++ drm_dp_mst_hpd_irq_handle_event(&intel_dp->mst_mgr, esi, ack, &handled);
+
+ if (esi[1] & DP_CP_IRQ) {
+ intel_hdcp_handle_cp_irq(intel_dp->attached_connector);
+@@ -3881,6 +3879,9 @@ intel_dp_check_mst_status(struct intel_d
+
+ if (!intel_dp_ack_sink_irq_esi(intel_dp, ack))
+ drm_dbg_kms(&i915->drm, "Failed to ack ESI\n");
++
++ if (ack[1] & (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY))
++ drm_dp_mst_hpd_irq_send_new_request(&intel_dp->mst_mgr);
+ }
+
+ return link_ok;
+--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
++++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
+@@ -1473,22 +1473,26 @@ nv50_mstm_service(struct nouveau_drm *dr
+ u8 esi[8] = {};
+
+ while (handled) {
++ u8 ack[8] = {};
++
+ rc = drm_dp_dpcd_read(aux, DP_SINK_COUNT_ESI, esi, 8);
+ if (rc != 8) {
+ ret = false;
+ break;
+ }
+
+- drm_dp_mst_hpd_irq(&mstm->mgr, esi, &handled);
++ drm_dp_mst_hpd_irq_handle_event(&mstm->mgr, esi, ack, &handled);
+ if (!handled)
+ break;
+
+- rc = drm_dp_dpcd_write(aux, DP_SINK_COUNT_ESI + 1, &esi[1],
+- 3);
+- if (rc != 3) {
++ rc = drm_dp_dpcd_writeb(aux, DP_SINK_COUNT_ESI + 1, ack[1]);
++
++ if (rc != 1) {
+ ret = false;
+ break;
+ }
++
++ drm_dp_mst_hpd_irq_send_new_request(&mstm->mgr);
+ }
+
+ if (!ret)
+--- a/include/drm/display/drm_dp_mst_helper.h
++++ b/include/drm/display/drm_dp_mst_helper.h
+@@ -815,8 +815,11 @@ void drm_dp_mst_topology_mgr_destroy(str
+ bool drm_dp_read_mst_cap(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
+ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool mst_state);
+
+-int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handled);
+-
++int drm_dp_mst_hpd_irq_handle_event(struct drm_dp_mst_topology_mgr *mgr,
++ const u8 *esi,
++ u8 *ack,
++ bool *handled);
++void drm_dp_mst_hpd_irq_send_new_request(struct drm_dp_mst_topology_mgr *mgr);
+
+ int
+ drm_dp_mst_detect_port(struct drm_connector *connector,
selftests-bpf-make-test_align-selftest-more-robust.patch
selftests-bpf-workaround-verification-failure-for-fexit_bpf2bpf-func_replace_return_code.patch
selftests-bpf-fix-sk_assign-on-s390x.patch
+drm-amd-display-use-max_dsc_bpp-in-amdgpu_dm.patch
+drm-amd-display-fix-some-coding-style-issues.patch
+drm-dp_mst-clear-msg_rdy-flag-before-sending-new-message.patch
+drm-amd-display-force-connector-state-when-bpc-changes-during-compliance.patch
+drm-amd-display-clean-up-errors-warnings-in-amdgpu_dm.c.patch
+drm-amd-display-fix-linux-dp-link-lost-handled-only-one-time.patch
+drm-amd-display-add-polling-method-to-handle-mst-reply-packet.patch