Skip to contentSkip to conversation

DC Patches Feb. 25, 2025

PATCH New Wayne Lin 1 participant 28 messages Feb 25, 2025

Subsystems (5)
lore
Share & tools
lore

Wayne Lin

author
#0 lore raw

cover DC Patches Feb. 25, 2025

This DC patchset brings improvements in multiple areas. In summary, we highlight:
- Various cleanups to amdgpu dm
- Add DP tunneling IRQ handler
- Fix display corruption for dcn35
- Fix dmcub reset problem
- Adjust BW determination for PCON
- DIO encoder refactor
- Fix performance with SubVP under gaming

---

Alex Hung (1):
drm/amd/display: Check NULL connector before it is used

Aric Cyr (1):
drm/amd/display: Request HW cursor on DCN3.2 with SubVP

Ausef Yousof (1):
drm/amd/display: wait for outstanding hw updates

Cruise Hung (1):
drm/amd/display: Add tunneling IRQ handler

Dillon Varone (2):
drm/amd/display: Fix p-state type when p-state is unsupported drm/amd/display: Fix DMUB reset sequence for DCN401

George Shen (2):
drm/amd/display: Skip checking FRL_MODE bit for PCON BW determination drm/amd/display: Remove unused struct definition

Hansen Dsouza (1):
drm/amd/display: read mso dpcd caps

Leo Zeng (1):
drm/amd/display: Added visual confirm for DCC

Mario Limonciello (13):
drm/amd/display: Change amdgpu_dm_irq_suspend() to void drm/amd/display: Drop ret variable from dm_suspend() drm/amd/display: Catch failures for amdgpu_dm_commit_zero_streams() drm/amd/display: Use _free() macro for amdgpu_dm_commit_zero_streams() drm/amd/display: Use drm_err() instead of DRM_ERROR in dm_resume() drm/amd/display: Use scoped guard for dm_resume() drm/amd/display: Change amdgpu_dm_irq_resume_*() to use drm_dbg() drm/amd/display: Change amdgpu_dm_irq_resume_*() to void drm/amd/display: Use _free(kfree) for dm_gpureset_commit_state() drm/amd/display: Use scoped guard for
amdgpu_dm_update_connector_after_detect()
drm/amd/display: Use _free() macro for
amdgpu_dm_update_connector_after_detect()
drm/amd/display: Use scoped guards for handle_hpd_irq_helper() drm/amd/display: Use drm_err() for handle_hpd_irq_helper()

Nicholas Kazlauskas (2):
drm/amd/display: Revert "Increase halt timeout for DMCUB to 1s" drm/amd/display: Ensure DMCUB idle before reset on DCN31/DCN35

Peichen Huang (1):
drm/amd/display: misc for dio encoder refactor

Taimur Hassan (1):
drm/amd/display: Promote DAL to 3.2.323

 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 89 ++++++++-----------
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 14 ++-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h |  6 +-
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  3 +
 .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c  | 20 +++--
 drivers/gpu/drm/amd/display/dc/core/dc.c      | 14 +--
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 49 ++++++++++
 .../gpu/drm/amd/display/dc/core/dc_resource.c |  5 +-
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |  3 +-
 drivers/gpu/drm/amd/display/dc/dc.h           |  3 +-
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h  | 50 ++++++++---
 .../dc/dio/dcn35/dcn35_dio_link_encoder.c     | 50 ++++++++++-
 .../dc/dio/dcn35/dcn35_dio_link_encoder.h     | 23 +++++
 .../drm/amd/display/dc/dml/dcn32/dcn32_fpu.c  |  1 +
 .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c   |  3 +-
 .../amd/display/dc/hwss/dcn35/dcn35_init.c    |  1 +
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  5 ++
 .../amd/display/dc/link/hwss/link_hwss_dio.c  |  5 +-
 .../amd/display/dc/link/hwss/link_hwss_dpia.c | 40 ++++-----
 .../drm/amd/display/dc/link/link_detection.c  |  5 +-
 .../dc/link/protocols/link_dp_capability.c    | 41 +++++----
 .../dc/link/protocols/link_dp_dpia_bw.c       | 26 ++++++
 .../dc/link/protocols/link_dp_dpia_bw.h       | 10 +++
 .../dc/link/protocols/link_dp_irq_handler.c   | 43 ++++++++-
 .../dc/link/protocols/link_dp_training.c      |  3 +-
 .../dc/link/protocols/link_dp_training_dpia.c | 13 +--
 .../amd/display/dc/optc/dcn35/dcn35_optc.c    |  3 +
 .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c |  4 +-
 .../gpu/drm/amd/display/dmub/src/dmub_dcn35.c |  4 +-
 .../drm/amd/display/dmub/src/dmub_dcn401.c    | 47 ++++++----
 .../drm/amd/display/dmub/src/dmub_dcn401.h    |  3 +-
 31 files changed, 424 insertions(+), 162 deletions(-)
Signature · 1 line
2.37.3
author
#1 lore raw

PATCH 1/27 drm/amd/display: Request HW cursor on DCN3.2 with SubVP

From: Aric Cyr <[email protected]>

[why]
When SubVP is active the HW cursor size is limited to 64x64, and anything larger will force composition which is bad for gaming on DCN3.2 if the game uses a larger cursor.

[how]
If HW cursor is requested, typically by a fullscreen game, do not enable SubVP so that up to 256x256 cursor sizes are available for DCN3.2.

---
 drivers/gpu/drm/amd/display/dc/core/dc.c             | 3 ++-
 drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/core/dc.c +2 -1
index 05ad7a9af4ff..a99ce7c86781 100644
@@ -4937,7 +4937,8 @@ static bool full_update_required(struct dc *dc,
 			stream_update->lut3d_func ||
 			stream_update->pending_test_pattern ||
 			stream_update->crtc_timing_adjust ||
-			stream_update->scaler_sharpener_update))
+			stream_update->scaler_sharpener_update ||
+			stream_update->hw_cursor_req))
 		return true;
 
 	if (stream) {
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c +1 -0
index 6f490d8d7038..56dda686e299 100644
@@ -626,6 +626,7 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc,
 		 * - Not TMZ surface
 		 */
 		if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && !dcn32_is_center_timing(pipe) &&
+				!pipe->stream->hw_cursor_req &&
 				!(pipe->stream->timing.pix_clk_100hz / 10000 > DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ) &&
 				(!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) &&
 				dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE &&
Signature · 1 line
2.37.3
author
#2 lore raw

PATCH 2/27 drm/amd/display: Fix p-state type when p-state is unsupported

In reply to Wayne Lin

From: Dillon Varone <[email protected]>

[WHY&HOW]
P-state type would remain on previously used when unsupported which causes confusion in logging and visual confirm, so set back to zero when unsupported.

---
 drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c | 1 +
 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +1 -0
index 6b514fd03f16..367c6b794412 100644
@@ -564,6 +564,7 @@ void set_p_state_switch_method(
 	if (!dc->ctx || !dc->ctx->dmub_srv || !pipe_ctx || !vba)
 		return;
 
+	pipe_ctx->p_state_type = P_STATE_UNKNOWN;
 	if (vba->DRAMClockChangeSupport[vba->VoltageLevel][vba->maxMpcComb] !=
 			dm_dram_clock_change_unsupported) {
 		/* MCLK switching is supported */
Signature · 1 line
2.37.3
author
#3 lore raw

PATCH 3/27 drm/amd/display: Fix DMUB reset sequence for DCN401

In reply to Wayne Lin

From: Dillon Varone <[email protected]>

[WHY]
It should no longer use DMCUB_SOFT_RESET as it can result in the memory request path becoming desynchronized.

[HOW]
To ensure robustness in the reset sequence:
1) Extend timeout on the "halt" command sent via gpint, and check for controller to enter "wait" as a stronger guarantee that there are no requests to memory still in flight.
2) Remove usage of DMCUB_SOFT_RESET
3) Rely on PSP to reset the controller safely

---
 .../drm/amd/display/dmub/src/dmub_dcn401.c    | 47 ++++++++++++-------
 .../drm/amd/display/dmub/src/dmub_dcn401.h    |  3 +-
 2 files changed, 32 insertions(+), 18 deletions(-)
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c +30 -17
index 39a8cb6d7523..e1c4fe1c6e3e 100644
@@ -63,8 +63,10 @@ static inline void dmub_dcn401_translate_addr(const union dmub_addr *addr_in,
 void dmub_dcn401_reset(struct dmub_srv *dmub)
 {
 	union dmub_gpint_data_register cmd;
-	const uint32_t timeout = 30;
-	uint32_t in_reset, scratch, i;
+	const uint32_t timeout_us = 1 * 1000 * 1000; //1s
+	const uint32_t poll_delay_us = 1; //1us
+	uint32_t i = 0;
+	uint32_t in_reset, scratch, pwait_mode;
 
 	REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
 
@@ -75,32 +77,35 @@ void dmub_dcn401_reset(struct dmub_srv *dmub)
 
 		dmub->hw_funcs.set_gpint(dmub, cmd);
 
-		/**
-		 * Timeout covers both the ACK and the wait
-		 * for remaining work to finish.
-		 *
-		 * This is mostly bound by the PHY disable sequence.
-		 * Each register check will be greater than 1us, so
-		 * don't bother using udelay.
-		 */
-
-		for (i = 0; i < timeout; ++i) {
+		for (i = 0; i < timeout_us; i++) {
 			if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
 				break;
+
+			udelay(poll_delay_us);
 		}
 
-		for (i = 0; i < timeout; ++i) {
+		for (; i < timeout_us; i++) {
 			scratch = dmub->hw_funcs.get_gpint_response(dmub);
 			if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
 				break;
+
+			udelay(poll_delay_us);
 		}
 
-		/* Force reset in case we timed out, DMCUB is likely hung. */
+		for (; i < timeout_us; i++) {
+			REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode);
+			if (pwait_mode & (1 << 0))
+				break;
+
+			udelay(poll_delay_us);
+		}
+	}
+
+	if (i >= timeout_us) {
+		/* timeout should never occur */
+		BREAK_TO_DEBUGGER();
 	}
 
-	REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
-	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
-	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
 	REG_WRITE(DMCUB_INBOX1_RPTR, 0);
 	REG_WRITE(DMCUB_INBOX1_WPTR, 0);
 	REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
@@ -131,7 +136,10 @@ void dmub_dcn401_backdoor_load(struct dmub_srv *dmub,
 
 	dmub_dcn401_get_fb_base_offset(dmub, &fb_base, &fb_offset);
 
+	/* reset and disable DMCUB and MMHUBBUB DMUIF */
 	REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
+	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
+	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
 
 	dmub_dcn401_translate_addr(&cw0->offset, fb_base, fb_offset, &offset);
 
@@ -151,6 +159,7 @@ void dmub_dcn401_backdoor_load(struct dmub_srv *dmub,
 			DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
 			DMCUB_REGION3_CW1_ENABLE, 1);
 
+	/* release DMCUB reset only to prevent premature execution */
 	REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
 			0x20);
 }
@@ -161,7 +170,10 @@ void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub,
 {
 	union dmub_addr offset;
 
+	/* reset and disable DMCUB and MMHUBBUB DMUIF */
 	REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
+	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
+	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
 
 	offset = cw0->offset;
 
@@ -181,6 +193,7 @@ void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub,
 			DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
 			DMCUB_REGION3_CW1_ENABLE, 1);
 
+	/* release DMCUB reset only to prevent premature execution */
 	REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
 			0x20);
 }
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h +2 -1
index 4c8843b79695..31f95b27e227 100644
@@ -169,7 +169,8 @@ struct dmub_srv;
 	DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN) \
 	DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK) \
 	DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT) \
-	DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN)
+	DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN) \
+	DMUB_SF(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS)
 
 struct dmub_srv_dcn401_reg_offset {
 #define DMUB_SR(reg) uint32_t reg;
Signature · 1 line
2.37.3
author
#4 lore raw

PATCH 4/27 drm/amd/display: read mso dpcd caps

In reply to Wayne Lin

From: Hansen Dsouza <[email protected]>

[Why & How]
Read if panel support multi-sst links

---
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h          |  2 ++
 .../display/dc/link/protocols/link_dp_capability.c    | 11 +++++++++++
 2 files changed, 13 insertions(+)
drivers/gpu/drm/amd/display/dc/dc_dp_types.h +2 -0
index 8bb628ab7855..22c2173c687f 100644
@@ -1220,6 +1220,8 @@ struct dpcd_caps {
 	struct replay_info pr_info;
 	uint16_t edp_oled_emission_rate;
 	union dp_receive_port0_cap receive_port0_cap;
+	/* Indicates the number of SST links supported by MSO (Multi-Stream Output) */
+	uint8_t mso_cap_sst_links_supported;
 };
 
 union dpcd_sink_ext_caps {
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +11 -0
index 0785c030f6a6..da19f6a3b42b 100644
@@ -2100,6 +2100,17 @@ void detect_edp_sink_caps(struct dc_link *link)
 		core_link_read_dpcd(link, DP_SINK_EMISSION_RATE,
 				(uint8_t *)&link->dpcd_caps.edp_oled_emission_rate,
 				sizeof(link->dpcd_caps.edp_oled_emission_rate));
+
+	/*
+	 * Read Multi-SST (Single Stream Transport) capability
+	 * for eDP version 1.4 or higher.
+	 */
+	if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
+		core_link_read_dpcd(
+			link,
+			DP_EDP_MSO_LINK_CAPABILITIES,
+			(uint8_t *)&link->dpcd_caps.mso_cap_sst_links_supported,
+			sizeof(link->dpcd_caps.mso_cap_sst_links_supported));
 }
 
 bool dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
Signature · 1 line
2.37.3
author
#5 lore raw

PATCH 5/27 drm/amd/display: misc for dio encoder refactor

In reply to Wayne Lin

From: Peichen Huang <[email protected]>

[WHY]
These are left required changes for dio encoder refactor.

[HOW]
1. original logic is separated by config option
2. new link encoder dp enable/disable code for dcn35
3. process fec only for DP 8b10b encoding

---
 .../display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c  | 20 ++++++--
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  3 +-
 .../gpu/drm/amd/display/dc/core/dc_resource.c |  5 +-
 .../gpu/drm/amd/display/dc/core/dc_stream.c   |  3 +-
 .../dc/dio/dcn35/dcn35_dio_link_encoder.c     | 50 +++++++++++++++++--
 .../dc/dio/dcn35/dcn35_dio_link_encoder.h     | 23 +++++++++
 .../amd/display/dc/hwss/dcn31/dcn31_hwseq.c   |  3 +-
 .../amd/display/dc/link/hwss/link_hwss_dio.c  |  5 +-
 .../amd/display/dc/link/hwss/link_hwss_dpia.c | 40 +++++++--------
 .../drm/amd/display/dc/link/link_detection.c  |  5 +-
 .../dc/link/protocols/link_dp_training.c      |  3 +-
 .../dc/link/protocols/link_dp_training_dpia.c | 13 +++--
 12 files changed, 133 insertions(+), 40 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +15 -5
index df29d28d89c9..af722519a1fa 100644
@@ -201,16 +201,26 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *
 		struct pipe_ctx *pipe = safe_to_lower
 			? &context->res_ctx.pipe_ctx[i]
 			: &dc->current_state->res_ctx.pipe_ctx[i];
+		struct link_encoder *new_pipe_link_enc = new_pipe->link_res.dio_link_enc;
+		struct link_encoder *pipe_link_enc = pipe->link_res.dio_link_enc;
 		bool stream_changed_otg_dig_on = false;
 		if (pipe->top_pipe || pipe->prev_odm_pipe)
 			continue;
+
+		if (!dc->config.unify_link_enc_assignment) {
+			if (new_pipe->stream)
+				new_pipe_link_enc = new_pipe->stream->link_enc;
+			if (pipe->stream)
+				pipe_link_enc = pipe->stream->link_enc;
+		}
+
 		stream_changed_otg_dig_on = old_pipe->stream && new_pipe->stream &&
 		old_pipe->stream != new_pipe->stream &&
 		old_pipe->stream_res.tg == new_pipe->stream_res.tg &&
-		new_pipe->stream->link_enc && !new_pipe->stream->dpms_off &&
-		new_pipe->stream->link_enc->funcs->is_dig_enabled &&
-		new_pipe->stream->link_enc->funcs->is_dig_enabled(
-		new_pipe->stream->link_enc) &&
+		new_pipe_link_enc && !new_pipe->stream->dpms_off &&
+		new_pipe_link_enc->funcs->is_dig_enabled &&
+		new_pipe_link_enc->funcs->is_dig_enabled(
+		new_pipe_link_enc) &&
 		new_pipe->stream_res.stream_enc &&
 		new_pipe->stream_res.stream_enc->funcs->is_fifo_enabled &&
 		new_pipe->stream_res.stream_enc->funcs->is_fifo_enabled(new_pipe->stream_res.stream_enc);
@@ -226,7 +236,7 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *
 
 		if (!has_active_hpo && !dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe) &&
 					(pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) ||
-					!pipe->stream->link_enc) && !stream_changed_otg_dig_on)) {
+					!pipe_link_enc) && !stream_changed_otg_dig_on)) {
 
 
 			/* This w/a should not trigger when we have a dig active */
drivers/gpu/drm/amd/display/dc/core/dc.c +2 -1
index a99ce7c86781..fe59649d3e15 100644
@@ -905,7 +905,8 @@ void dc_stream_set_static_screen_params(struct dc *dc,
 static void dc_destruct(struct dc *dc)
 {
 	// reset link encoder assignment table on destruct
-	if (dc->res_pool && dc->res_pool->funcs->link_encs_assign)
+	if (dc->res_pool && dc->res_pool->funcs->link_encs_assign &&
+			!dc->config.unify_link_enc_assignment)
 		link_enc_cfg_init(dc, dc->current_state);
 
 	if (dc->current_state) {
drivers/gpu/drm/amd/display/dc/core/dc_resource.c +4 -1
index 0bd3e7c072a1..1accc04f92e9 100644
@@ -4925,7 +4925,10 @@ bool pipe_need_reprogram(
 		return true;
 
 	/* DIG link encoder resource assignment for stream changed. */
-	if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
+	if (pipe_ctx_old->stream->ctx->dc->config.unify_link_enc_assignment) {
+		if (pipe_ctx_old->link_res.dio_link_enc != pipe_ctx->link_res.dio_link_enc)
+			return true;
+	} else if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
 		bool need_reprogram = false;
 		struct dc *dc = pipe_ctx_old->stream->ctx->dc;
 		struct link_encoder *link_enc_prev =
drivers/gpu/drm/amd/display/dc/core/dc_stream.c +2 -1
index e8134c47fe0d..0478dd856d8c 100644
@@ -201,7 +201,8 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
 	dc_stream_assign_stream_id(new_stream);
 
 	/* If using dynamic encoder assignment, wait till stream committed to assign encoder. */
-	if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign)
+	if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign &&
+			!new_stream->ctx->dc->config.unify_link_enc_assignment)
 		new_stream->link_enc = NULL;
 
 	kref_init(&new_stream->refcount);
drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.c +47 -3

62 lines not on this page · raw message

drivers/gpu/drm/amd/display/dc/dio/dcn35/dcn35_dio_link_encoder.h +23 -0
index f9d4221f4b43..5712e6553fab 100644
@@ -144,6 +144,29 @@ bool dcn35_is_dig_enabled(struct link_encoder *enc);
 enum signal_type dcn35_get_dig_mode(struct link_encoder *enc);
 void dcn35_link_encoder_setup(struct link_encoder *enc, enum signal_type signal);
 
+/*
+ * Enable DP transmitter and its encoder.
+ */
+void dcn35_link_encoder_enable_dp_output(
+	struct link_encoder *enc,
+	const struct dc_link_settings *link_settings,
+	enum clock_source_id clock_source);
+
+/*
+ * Enable DP transmitter and its encoder in MST mode.
+ */
+void dcn35_link_encoder_enable_dp_mst_output(
+	struct link_encoder *enc,
+	const struct dc_link_settings *link_settings,
+	enum clock_source_id clock_source);
+
+/*
+ * Disable transmitter and its encoder.
+ */
+void dcn35_link_encoder_disable_output(
+	struct link_encoder *enc,
+	enum signal_type signal);
+
 /*
  * Enable DP transmitter and its encoder for dpia port.
  */
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +2 -1
index f698062f1e90..288e9dd9205d 100644
@@ -621,7 +621,8 @@ void dcn31_reset_hw_ctx_wrap(
 	}
 
 	/* New dc_state in the process of being applied to hardware. */
-	link_enc_cfg_set_transient_mode(dc, dc->current_state, context);
+	if (!dc->config.unify_link_enc_assignment)
+		link_enc_cfg_set_transient_mode(dc, dc->current_state, context);
 }
 
 void dcn31_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c +4 -1
index 4a3578a9586e..b68bcc9fca0a 100644
@@ -328,7 +328,10 @@ static const struct link_hwss dio_link_hwss = {
 bool can_use_dio_link_hwss(const struct dc_link *link,
 		const struct link_resource *link_res)
 {
-	return link->link_enc != NULL;
+	if (!link->dc->config.unify_link_enc_assignment)
+		return link->link_enc != NULL;
+	else
+		return link_res->dio_link_enc != NULL;
 }
 
 /**
drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dpia.c +20 -20
index 81d5085e322f..81bf3c5e1fdf 100644
@@ -90,33 +90,27 @@ static void enable_dpia_link_output(struct dc_link *link,
 		const struct dc_link_settings *link_settings)
 {
 	struct link_encoder *link_enc = link_res->dio_link_enc;
+	DC_LOGGER_INIT(link->ctx->logger);
 
 	if (!link->dc->config.unify_link_enc_assignment)
 		link_enc = link_enc_cfg_get_link_enc(link);
 
 	if (link_enc != NULL) {
-		if (link->dc->config.enable_dpia_pre_training && link_enc->funcs->enable_dpia_output) {
+		if (link->dc->config.enable_dpia_pre_training || link->dc->config.unify_link_enc_assignment) {
 			uint8_t fec_rdy = link->dc->link_srv->dp_should_enable_fec(link);
 			uint8_t digmode = dc_is_dp_sst_signal(signal) ? DIG_SST_MODE : DIG_MST_MODE;
 
-			link_enc->funcs->enable_dpia_output(
-					link_enc,
-					link_settings,
-					link->ddc_hw_inst,
-					digmode,
-					fec_rdy);
-		} else {
-			if (dc_is_dp_sst_signal(signal))
-				link_enc->funcs->enable_dp_output(
+			if (link_enc->funcs->enable_dpia_output)
+				link_enc->funcs->enable_dpia_output(
 						link_enc,
 						link_settings,
-						clock_source);
+						link->ddc_hw_inst,
+						digmode,
+						fec_rdy);
 			else
-				link_enc->funcs->enable_dp_mst_output(
-						link_enc,
-						link_settings,
-						clock_source);
-		}
+				DC_LOG_ERROR("%s: link encoder does not support enable_dpia_output\n", __func__);
+		} else
+			enable_dio_dp_link_output(link, link_res, signal, clock_source, link_settings);
 
 	}
 
@@ -129,15 +123,19 @@ static void disable_dpia_link_output(struct dc_link *link,
 		enum signal_type signal)
 {
 	struct link_encoder *link_enc = link_res->dio_link_enc;
+	DC_LOGGER_INIT(link->ctx->logger);
 
 	if (!link->dc->config.unify_link_enc_assignment)
 		link_enc = link_enc_cfg_get_link_enc(link);
 
 	if (link_enc != NULL) {
-		if (link->dc->config.enable_dpia_pre_training && link_enc->funcs->disable_dpia_output) {
+		if (link->dc->config.enable_dpia_pre_training || link->dc->config.unify_link_enc_assignment) {
 			uint8_t digmode = dc_is_dp_sst_signal(signal) ? DIG_SST_MODE : DIG_MST_MODE;
 
-			link_enc->funcs->disable_dpia_output(link_enc, link->ddc_hw_inst, digmode);
+			if (link_enc->funcs->disable_dpia_output)
+				link_enc->funcs->disable_dpia_output(link_enc, link->ddc_hw_inst, digmode);
+			else
+				DC_LOG_ERROR("%s: link encoder does not support disable_dpia_output\n", __func__);
 		} else
 			link_enc->funcs->disable_output(link_enc, signal);
 	}
@@ -166,8 +164,10 @@ static const struct link_hwss dpia_link_hwss = {
 bool can_use_dpia_link_hwss(const struct dc_link *link,
 		const struct link_resource *link_res)
 {
-	return link->is_dig_mapping_flexible &&
-			link->dc->res_pool->funcs->link_encs_assign;
+	if (!link->dc->config.unify_link_enc_assignment)
+		return link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign;
+	else
+		return link->is_dig_mapping_flexible && link_res->dio_link_enc != NULL;
 }
 
 const struct link_hwss *get_dpia_link_hwss(void)
drivers/gpu/drm/amd/display/dc/link/link_detection.c +4 -1
index 550e1a098fa2..cc9191a5c9e6 100644
@@ -816,7 +816,10 @@ static bool should_verify_link_capability_destructively(struct dc_link *link,
 {
 	bool destrictive = false;
 	struct dc_link_settings max_link_cap;
-	bool is_link_enc_unavailable = link->link_enc &&
+	bool is_link_enc_unavailable = false;
+
+	if (!link->dc->config.unify_link_enc_assignment)
+		is_link_enc_unavailable = link->link_enc &&
 			link->dc->res_pool->funcs->link_encs_assign &&
 			!link_enc_cfg_is_link_enc_avail(
 					link->ctx->dc,
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +2 -1
index 40ac17ba9479..613298d21d03 100644
@@ -1575,7 +1575,8 @@ enum link_training_result dp_perform_link_training(
 
 	/* configure link prior to entering training mode */
 	dpcd_configure_lttpr_mode(link, &lt_settings);
-	dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
+	if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING)
+		dp_set_fec_ready(link, link_res, lt_settings.should_set_fec_ready);
 	dpcd_configure_channel_coding(link, &lt_settings);
 
 	/* enter training mode:
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +8 -5
index 6e2d08cfc546..603537ffd128 100644
@@ -130,11 +130,14 @@ static enum link_training_result dpia_configure_link(
 	if (status != DC_OK && link->is_hpd_pending)
 		return LINK_TRAINING_ABORT;
 
-	if (link->preferred_training_settings.fec_enable != NULL)
-		fec_enable = *link->preferred_training_settings.fec_enable;
-	else
-		fec_enable = true;
-	status = dp_set_fec_ready(link, link_res, fec_enable);
+	if (link_dp_get_encoding_format(link_setting) == DP_8b_10b_ENCODING) {
+		if (link->preferred_training_settings.fec_enable != NULL)
+			fec_enable = *link->preferred_training_settings.fec_enable;
+		else
+			fec_enable = true;
+		status = dp_set_fec_ready(link, link_res, fec_enable);
+	}
+
 	if (status != DC_OK && link->is_hpd_pending)
 		return LINK_TRAINING_ABORT;
 
Signature · 1 line
2.37.3
author
#6 lore raw

PATCH 6/27 drm/amd/display: Skip checking FRL_MODE bit for PCON BW determination

In reply to Wayne Lin

From: George Shen <[email protected]>

[Why/How]
Certain PCON will clear the FRL_MODE bit despite supporting the link BW indicated in the other bits.

Thus, skip checking the FRL_MODE bit when interpreting the hdmi_encoded_link_bw struct.

---
 .../dc/link/protocols/link_dp_capability.c    | 30 +++++++++----------
 1 file changed, 15 insertions(+), 15 deletions(-)
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +15 -15
index da19f6a3b42b..a77410122636 100644
@@ -250,21 +250,21 @@ static uint32_t intersect_frl_link_bw_support(
 {
 	uint32_t supported_bw_in_kbps = max_supported_frl_bw_in_kbps;
 
-	// HDMI_ENCODED_LINK_BW bits are only valid if HDMI Link Configuration bit is 1 (FRL mode)
-	if (hdmi_encoded_link_bw.bits.FRL_MODE) {
-		if (hdmi_encoded_link_bw.bits.BW_48Gbps)
-			supported_bw_in_kbps = 48000000;
-		else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
-			supported_bw_in_kbps = 40000000;
-		else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
-			supported_bw_in_kbps = 32000000;
-		else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
-			supported_bw_in_kbps = 24000000;
-		else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
-			supported_bw_in_kbps = 18000000;
-		else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
-			supported_bw_in_kbps = 9000000;
-	}
+	/* Skip checking FRL_MODE bit, as certain PCON will clear
+	 * it despite supporting the link BW indicated in the other bits.
+	 */
+	if (hdmi_encoded_link_bw.bits.BW_48Gbps)
+		supported_bw_in_kbps = 48000000;
+	else if (hdmi_encoded_link_bw.bits.BW_40Gbps)
+		supported_bw_in_kbps = 40000000;
+	else if (hdmi_encoded_link_bw.bits.BW_32Gbps)
+		supported_bw_in_kbps = 32000000;
+	else if (hdmi_encoded_link_bw.bits.BW_24Gbps)
+		supported_bw_in_kbps = 24000000;
+	else if (hdmi_encoded_link_bw.bits.BW_18Gbps)
+		supported_bw_in_kbps = 18000000;
+	else if (hdmi_encoded_link_bw.bits.BW_9Gbps)
+		supported_bw_in_kbps = 9000000;
 
 	return supported_bw_in_kbps;
 }
Signature · 1 line
2.37.3
author
#7 lore raw

PATCH 7/27 drm/amd/display: Remove unused struct definition

In reply to Wayne Lin

From: George Shen <[email protected]>

[Why/How]
The struct is not and will not be used, as it is no longer relevant nor supported.

---
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 8 --------
 1 file changed, 8 deletions(-)
drivers/gpu/drm/amd/display/dc/dc_dp_types.h +0 -8
index 22c2173c687f..d988c00f5ca4 100644
@@ -410,14 +410,6 @@ union dwnstream_port_caps_byte3_hdmi {
 	uint8_t raw;
 };
 
-union hdmi_sink_encoded_link_bw_support {
-	struct {
-		uint8_t HDMI_SINK_ENCODED_LINK_BW_SUPPORT:3;
-		uint8_t RESERVED:5;
-	} bits;
-	uint8_t raw;
-};
-
 union hdmi_encoded_link_bw {
 	struct {
 		uint8_t FRL_MODE:1; // Bit 0
Signature · 1 line
2.37.3
author
#8 lore raw

PATCH 8/27 drm/amd/display: Check NULL connector before it is used

In reply to Wayne Lin

From: Alex Hung <[email protected]>

[Why & How]
amdgpu_dm_find_first_crtc_matching_connector can return NULL. It is necessary to the returned connector before passing it drm_atomic_get_new_connector_state which always assumes connector is not NULL.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 3 +++
 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +3 -0
index 0d14a0d5def3..5c956b9962dc 100644
@@ -1631,6 +1631,9 @@ int pre_validate_dsc(struct drm_atomic_state *state,
 			connector =
 				amdgpu_dm_find_first_crtc_matching_connector(state,
 									     state->crtcs[ind].ptr);
+			if (!connector)
+				continue;
+
 			drm_new_conn_state =
 				drm_atomic_get_new_connector_state(state,
 								   connector);
Signature · 1 line
2.37.3
author
#9 lore raw

PATCH 9/27 drm/amd/display: Revert "Increase halt timeout for DMCUB to 1s"

In reply to Wayne Lin

From: Nicholas Kazlauskas <[email protected]>

This reverts commit 7f4d49ac3944 ("drm/amd/display: Increase halt timeout for DMCUB to 1s")

There's two issues here:
1. Each poll is closer to 10us than 1us so it stalls for 15s on PNP.
2. We're reading the wrong scratch register to check for the HALT code.

---
 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c | 15 +++++----------
 drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c |  2 +-
 2 files changed, 6 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +5 -10
index 1fac75dfc650..3d0bba602b53 100644
@@ -83,8 +83,8 @@ static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in,
 void dmub_dcn31_reset(struct dmub_srv *dmub)
 {
 	union dmub_gpint_data_register cmd;
-	const uint32_t timeout = 1000000;
-	uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
+	const uint32_t timeout = 100;
+	uint32_t in_reset, scratch, i, pwait_mode;
 
 	REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
 
@@ -125,14 +125,9 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
 		/* Force reset in case we timed out, DMCUB is likely hung. */
 	}
 
-	REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_enabled);
-
-	if (is_enabled) {
-		REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
-		REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
-		REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
-	}
-
+	REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
+	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
 	REG_WRITE(DMCUB_INBOX1_RPTR, 0);
 	REG_WRITE(DMCUB_INBOX1_WPTR, 0);
 	REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +1 -1
index 652173b10401..e5e77bd3c31e 100644
@@ -88,7 +88,7 @@ static inline void dmub_dcn35_translate_addr(const union dmub_addr *addr_in,
 void dmub_dcn35_reset(struct dmub_srv *dmub)
 {
 	union dmub_gpint_data_register cmd;
-	const uint32_t timeout = 1000000;
+	const uint32_t timeout = 100;
 	uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
 
 	REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
Signature · 1 line
2.37.3
author
#10 lore raw

PATCH 10/27 drm/amd/display: Ensure DMCUB idle before reset on DCN31/DCN35

In reply to Wayne Lin

From: Nicholas Kazlauskas <[email protected]>

[Why]
If we soft reset before halt finishes and there are outstanding memory transactions then the memory interface may produce unexpected results, such as out of order transactions when the firmware next runs.

These can manifest as random or unexpected load/store violations.

[How]
Increase the timeout before soft reset to ensure the DMCUB has quiesced. This is effectively 1s maximum based on experimentation.

Use the enable bit check on DCN31 like we're doing on DCN35 and reorder the reset writes to follow the HW programming guide.

Ensure we're reading SCRATCH7 instead of SCRATCH8 for the HALT code. No current versions of DMCUB firmware use the SCRATCH8 boot bit to dynamically switch where the HALT code goes to maintain backwards compatibility with PSP.

---
 .../gpu/drm/amd/display/dmub/src/dmub_dcn31.c   | 17 +++++++++++------
 .../gpu/drm/amd/display/dmub/src/dmub_dcn35.c   |  4 ++--
 2 files changed, 13 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c +11 -6
index 3d0bba602b53..9796077885c9 100644
@@ -83,8 +83,8 @@ static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in,
 void dmub_dcn31_reset(struct dmub_srv *dmub)
 {
 	union dmub_gpint_data_register cmd;
-	const uint32_t timeout = 100;
-	uint32_t in_reset, scratch, i, pwait_mode;
+	const uint32_t timeout = 100000;
+	uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
 
 	REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
 
@@ -108,7 +108,7 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
 		}
 
 		for (i = 0; i < timeout; ++i) {
-			scratch = dmub->hw_funcs.get_gpint_response(dmub);
+			scratch = REG_READ(DMCUB_SCRATCH7);
 			if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
 				break;
 
@@ -125,9 +125,14 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
 		/* Force reset in case we timed out, DMCUB is likely hung. */
 	}
 
-	REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
-	REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
-	REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
+	REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_enabled);
+
+	if (is_enabled) {
+		REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
+		REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
+		REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
+	}
+
 	REG_WRITE(DMCUB_INBOX1_RPTR, 0);
 	REG_WRITE(DMCUB_INBOX1_WPTR, 0);
 	REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +2 -2
index e5e77bd3c31e..01d013a12b94 100644
@@ -88,7 +88,7 @@ static inline void dmub_dcn35_translate_addr(const union dmub_addr *addr_in,
 void dmub_dcn35_reset(struct dmub_srv *dmub)
 {
 	union dmub_gpint_data_register cmd;
-	const uint32_t timeout = 100;
+	const uint32_t timeout = 100000;
 	uint32_t in_reset, is_enabled, scratch, i, pwait_mode;
 
 	REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
@@ -113,7 +113,7 @@ void dmub_dcn35_reset(struct dmub_srv *dmub)
 		}
 
 		for (i = 0; i < timeout; ++i) {
-			scratch = dmub->hw_funcs.get_gpint_response(dmub);
+			scratch = REG_READ(DMCUB_SCRATCH7);
 			if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
 				break;
 
Signature · 1 line
2.37.3
author
#11 lore raw

PATCH 11/27 drm/amd/display: Added visual confirm for DCC

In reply to Wayne Lin

From: Leo Zeng <[email protected]>

[WHY]
We want to add a visual confirm mode for DCC and MCache for debugging purpose.

[HOW]
color pipes based on whether DCC is enabled and what MCache id is used.
black - DCC disabled
red - DCC enabled
grey - 2 different MCaches used
other colors - 1 MCache used

---
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  8 ++--
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 48 +++++++++++++++++++
 drivers/gpu/drm/amd/display/dc/dc.h           |  1 +
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  5 ++
 4 files changed, 59 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/dc/core/dc.c +5 -3
index fe59649d3e15..e71ea21401f5 100644
@@ -1202,6 +1202,8 @@ static void dc_update_visual_confirm_color(struct dc *dc, struct dc_state *conte
 			get_surface_tile_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
 		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_HW_CURSOR)
 			get_cursor_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color));
+		else if (dc->debug.visual_confirm == VISUAL_CONFIRM_DCC)
+			get_dcc_visual_confirm_color(dc, pipe_ctx, &(pipe_ctx->visual_confirm_color));
 		else {
 			if (dc->ctx->dce_version < DCN_VERSION_2_0)
 				color_space_to_black_color(
@@ -3956,6 +3958,9 @@ static void commit_planes_for_stream(struct dc *dc,
 	if (update_type == UPDATE_TYPE_FULL && dc->optimized_required)
 		hwss_process_outstanding_hw_updates(dc, dc->current_state);
 
+	if (update_type != UPDATE_TYPE_FAST && dc->res_pool->funcs->prepare_mcache_programming)
+		dc->res_pool->funcs->prepare_mcache_programming(dc, context);
+
 	for (i = 0; i < dc->res_pool->pipe_count; i++) {
 		struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
@@ -4014,9 +4019,6 @@ static void commit_planes_for_stream(struct dc *dc,
 				odm_pipe->ttu_regs.min_ttu_vblank = MAX_TTU;
 	}
 
-	if (update_type != UPDATE_TYPE_FAST && dc->res_pool->funcs->prepare_mcache_programming)
-		dc->res_pool->funcs->prepare_mcache_programming(dc, context);
-
 	if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
 		if (top_pipe_to_program &&
 			top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +48 -0

60 lines not on this page · raw message

drivers/gpu/drm/amd/display/dc/dc.h +1 -0
index f646f537a3dc..02bf6fe51a0d 100644
@@ -495,6 +495,7 @@ enum visual_confirm {
 	VISUAL_CONFIRM_FAMS2 = 19,
 	VISUAL_CONFIRM_HW_CURSOR = 20,
 	VISUAL_CONFIRM_VABC = 21,
+	VISUAL_CONFIRM_DCC = 22,
 };
 
 enum dc_psr_power_opts {
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +5 -0
index 599fa41fd75f..2b1a2a00648a 100644
@@ -517,6 +517,11 @@ void get_cursor_visual_confirm_color(
 		struct pipe_ctx *pipe_ctx,
 		struct tg_color *color);
 
+void get_dcc_visual_confirm_color(
+	struct dc *dc,
+	struct pipe_ctx *pipe_ctx,
+	struct tg_color *color);
+
 void set_p_state_switch_method(
 		struct dc *dc,
 		struct dc_state *context,
Signature · 1 line
2.37.3
author
#12 lore raw

PATCH 12/27 drm/amd/display: wait for outstanding hw updates

In reply to Wayne Lin

From: Ausef Yousof <[email protected]>

[why&how]
seeing display corruption as a result of not waiting for certain values to latch and attempting otg locking/programming before waiting for them, there is code in place for this but dcn35 does not initialize these functions.

---
 drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c | 1 +
 drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c | 3 +++
 2 files changed, 4 insertions(+)
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c +1 -0
index 6a82a865209c..7be72fd88477 100644
@@ -128,6 +128,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
 	.enable_plane = dcn20_enable_plane,
 	.update_dchubp_dpp = dcn20_update_dchubp_dpp,
 	.post_unlock_reset_opp = dcn20_post_unlock_reset_opp,
+	.wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates
 };
 
 static const struct hwseq_private_funcs dcn35_private_funcs = {
drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +3 -0
index b86fe2b094f8..eb29e852dedb 100644
@@ -493,6 +493,9 @@ static struct timing_generator_funcs dcn35_tg_funcs = {
 		.set_long_vtotal = optc35_set_long_vtotal,
 		.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
 		.read_otg_state = optc31_read_otg_state,
+		.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
+		.get_pipe_update_pending = optc3_get_pipe_update_pending,
+		.get_otg_double_buffer_pending = optc3_get_otg_update_pending,
 };
 
 void dcn35_timing_generator_init(struct optc *optc1)
Signature · 1 line
2.37.3
author
#13 lore raw

PATCH 13/27 drm/amd/display: Add tunneling IRQ handler

In reply to Wayne Lin

From: Cruise Hung <[email protected]>

USB4 DP BW Allocation uses DP_TUNNELING_IRQ to indicate the status update. The DP_TUNNELING_IRQ is defined in LINK_SERVICE_IRQ_VECTOR_ESI0. When receiving DP HPD IRQ in USB4, read the LINK_SERVICE_IRQ_VECTOR_ESI0.

---
 drivers/gpu/drm/amd/display/dc/dc_dp_types.h  | 40 +++++++++++++++--
 .../dc/link/protocols/link_dp_dpia_bw.c       | 26 +++++++++++
 .../dc/link/protocols/link_dp_dpia_bw.h       | 10 +++++
 .../dc/link/protocols/link_dp_irq_handler.c   | 43 +++++++++++++++++--
 4 files changed, 112 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/display/dc/dc_dp_types.h +36 -4
index d988c00f5ca4..1f4f11adc491 100644
@@ -300,6 +300,19 @@ union lane_align_status_updated {
 	uint8_t raw;
 };
 
+union link_service_irq_vector_esi0 {
+	struct {
+		uint8_t DP_LINK_RX_CAP_CHANGED:1;
+		uint8_t DP_LINK_STATUS_CHANGED:1;
+		uint8_t DP_LINK_STREAM_STATUS_CHANGED:1;
+		uint8_t DP_LINK_HDMI_LINK_STATUS_CHANGED:1;
+		uint8_t DP_LINK_CONNECTED_OFF_ENTRY_REQUESTED:1;
+		uint8_t DP_LINK_TUNNELING_IRQ:1;
+		uint8_t reserved:2;
+	} bits;
+	uint8_t raw;
+};
+
 union lane_adjust {
 	struct {
 		uint8_t VOLTAGE_SWING_LANE:2;
@@ -462,8 +475,10 @@ union sink_status {
 	uint8_t raw;
 };
 
-/*6-byte structure corresponding to 6 registers (200h-205h)
-read during handling of HPD-IRQ*/
+/* 7-byte structure corresponding to 6 registers (200h-205h)
+ * and LINK_SERVICE_IRQ_ESI0 (2005h) for tunneling IRQ
+ * read during handling of HPD-IRQ
+ */
 union hpd_irq_data {
 	struct {
 		union sink_count sink_cnt;/* 200h */
@@ -471,9 +486,10 @@ union hpd_irq_data {
 		union lane_status lane01_status;/* 202h */
 		union lane_status lane23_status;/* 203h */
 		union lane_align_status_updated lane_status_updated;/* 204h */
-		union sink_status sink_status;
+		union sink_status sink_status;/* 205h */
+		union link_service_irq_vector_esi0 link_service_irq_esi0;/* 2005h */
 	} bytes;
-	uint8_t raw[6];
+	uint8_t raw[7];
 };
 
 union down_stream_port_count {
@@ -1430,4 +1446,20 @@ struct dp_trace {
 #ifndef REQUESTED_BW
 #define REQUESTED_BW					0xE0031 /* 1.4a */
 #endif
+# ifndef DP_TUNNELING_BW_ALLOC_BITS_MASK
+# define DP_TUNNELING_BW_ALLOC_BITS_MASK		(0x0F << 0)
+# endif
+# ifndef DP_TUNNELING_BW_REQUEST_FAILED
+# define DP_TUNNELING_BW_REQUEST_FAILED			(1 << 0)
+# endif
+# ifndef DP_TUNNELING_BW_REQUEST_SUCCEEDED
+# define DP_TUNNELING_BW_REQUEST_SUCCEEDED		(1 << 1)
+# endif
+# ifndef DP_TUNNELING_ESTIMATED_BW_CHANGED
+# define DP_TUNNELING_ESTIMATED_BW_CHANGED		(1 << 2)
+# endif
+# ifndef DP_TUNNELING_BW_ALLOC_CAP_CHANGED
+# define DP_TUNNELING_BW_ALLOC_CAP_CHANGED		(1 << 3)
+# endif
+
 #endif /* DC_DP_TYPES_H */
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +26 -0
index 0f1c411523a2..a5541b8fc95b 100644
@@ -356,6 +356,32 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link)
 	return ret;
 }
 
+/*
+ * Handle DP BW allocation status register
+ *
+ * @link: pointer to the dc_link struct instance
+ * @status: content of DP tunneling status DPCD register
+ *
+ * return: none
+ */
+void link_dp_dpia_handle_bw_alloc_status(struct dc_link *link, uint8_t status)
+{
+	if (status & DP_TUNNELING_BW_REQUEST_SUCCEEDED) {
+		DC_LOG_DEBUG("%s: BW Allocation request succeeded on link(%d)",
+				__func__, link->link_index);
+	} else if (status & DP_TUNNELING_BW_REQUEST_FAILED) {
+		DC_LOG_DEBUG("%s: BW Allocation request failed on link(%d)  allocated/estimated BW=%d",
+				__func__, link->link_index, link->dpia_bw_alloc_config.estimated_bw);
+	} else if (status & DP_TUNNELING_ESTIMATED_BW_CHANGED) {
+		DC_LOG_DEBUG("%s: Estimated BW changed on link(%d)  new estimated BW=%d",
+				__func__, link->link_index, link->dpia_bw_alloc_config.estimated_bw);
+	}
+
+	core_link_write_dpcd(
+		link, DP_TUNNELING_STATUS,
+		&status, sizeof(status));
+}
+
 void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result)
 {
 	int bw_needed = 0;
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h +10 -0
index 3b6d8494f9d5..1b240a2f6ce0 100644
@@ -108,4 +108,14 @@ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned
  */
 int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link);
 
+/*
+ * Handle DP BW allocation status register
+ *
+ * @link: pointer to the dc_link struct instance
+ * @status: content of DP tunneling status register
+ *
+ * return: none
+ */
+void link_dp_dpia_handle_bw_alloc_status(struct dc_link *link, uint8_t status);
+
 #endif /* DC_INC_LINK_DP_DPIA_BW_H_ */
drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +40 -3

77 lines not on this page · raw message

Signature · 1 line
2.37.3
author
#14 lore raw

PATCH 14/27 drm/amd/display: Change amdgpu_dm_irq_suspend() to void

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

amdgpu_dm_irq_suspend() doesn't have any error flows and always returns zero.

Change the function to void.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 3 +--
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +1 -2
index c4a7fd453e5f..34cd39488ad0 100644
@@ -473,7 +473,7 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev)
 	unregister_all_irq_handlers(adev);
 }
 
-int amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
+void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
 {
 	int src;
 	struct list_head *hnd_list_h;
@@ -511,7 +511,6 @@ int amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
 	}
 
 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
-	return 0;
 }
 
 int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +1 -1
index 2349238a626b..c37bcd631e10 100644
@@ -90,7 +90,7 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev);
  * amdgpu_dm_irq_suspend - disable ASIC interrupt during suspend.
  *
  */
-int amdgpu_dm_irq_suspend(struct amdgpu_device *adev);
+void amdgpu_dm_irq_suspend(struct amdgpu_device *adev);
 
 /**
  * amdgpu_dm_irq_resume_early - enable HPDRX ASIC interrupts during resume.
Signature · 1 line
2.37.3
author
#15 lore raw

PATCH 15/27 drm/amd/display: Drop `ret` variable from dm_suspend()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

The ret variable in dm_suspend() doesn't get set and is just used to return 0. Drop the needless declaration.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +1 -2
index badd8fa2099c..6473622e2bf8 100644
@@ -3142,7 +3142,6 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 {
 	struct amdgpu_device *adev = ip_block->adev;
 	struct amdgpu_display_manager *dm = &adev->dm;
-	int ret = 0;
 
 	if (amdgpu_in_reset(adev)) {
 		mutex_lock(&dm->dc_lock);
@@ -3160,7 +3159,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 
 		hpd_rx_irq_work_suspend(dm);
 
-		return ret;
+		return 0;
 	}
 
 	WARN_ON(adev->dm.cached_state);
Signature · 1 line
2.37.3
author
#16 lore raw

PATCH 16/27 drm/amd/display: Catch failures for amdgpu_dm_commit_zero_streams()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

amdgpu_dm_commit_zero_streams() returns a DC error code that isn't checked. Add an explicit check to this and fail dm_suspend() if it is not DC_OK.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +7 -1
index 6473622e2bf8..fbeb3e89675b 100644
@@ -3144,6 +3144,8 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 	struct amdgpu_display_manager *dm = &adev->dm;
 
 	if (amdgpu_in_reset(adev)) {
+		enum dc_status res;
+
 		mutex_lock(&dm->dc_lock);
 
 		dc_allow_idle_optimizations(adev->dm.dc, false);
@@ -3153,7 +3155,11 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block)
 		if (dm->cached_dc_state)
 			dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false);
 
-		amdgpu_dm_commit_zero_streams(dm->dc);
+		res = amdgpu_dm_commit_zero_streams(dm->dc);
+		if (res != DC_OK) {
+			drm_err(adev_to_drm(adev), "Failed to commit zero streams: %d\n", res);
+			return -EINVAL;
+		}
 
 		amdgpu_dm_irq_suspend(adev);
 
Signature · 1 line
2.37.3
author
#17 lore raw

PATCH 17/27 drm/amd/display: Use _free() macro for amdgpu_dm_commit_zero_streams()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

All cases except a failure to create a copy of the current context will call dc_state_release() on the copied context.

Use a _free() macro to free the context and then adjust the error handling flow to drop the unnecessary use of goto statements.

---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 24 ++++++++-----------
 1 file changed, 10 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +10 -14
index fbeb3e89675b..6e218e69f039 100644
@@ -3083,10 +3083,11 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev,
 
 }
 
+DEFINE_FREE(state_release, struct dc_state *, if (_T) dc_state_release(_T))
+
 static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 {
-	struct dc_state *context = NULL;
-	enum dc_status res = DC_ERROR_UNEXPECTED;
+	struct dc_state *context __free(state_release) = NULL;
 	int i;
 	struct dc_stream_state *del_streams[MAX_PIPES];
 	int del_streams_count = 0;
@@ -3096,7 +3097,7 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 
 	context = dc_state_create_current_copy(dc);
 	if (context == NULL)
-		goto context_alloc_fail;
+		return DC_ERROR_UNEXPECTED;
 
 	/* First remove from context all streams */
 	for (i = 0; i < context->stream_count; i++) {
@@ -3107,25 +3108,20 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc)
 
 	/* Remove all planes for removed streams and then remove the streams */
 	for (i = 0; i < del_streams_count; i++) {
-		if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) {
-			res = DC_FAIL_DETACH_SURFACES;
-			goto fail;
-		}
+		enum dc_status res;
+
+		if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context))
+			return DC_FAIL_DETACH_SURFACES;
 
 		res = dc_state_remove_stream(dc, context, del_streams[i]);
 		if (res != DC_OK)
-			goto fail;
+			return res;
 	}
 
 	params.streams = context->streams;
 	params.stream_count = context->stream_count;
-	res = dc_commit_streams(dc, &params);
-
-fail:
-	dc_state_release(context);
 
-context_alloc_fail:
-	return res;
+	return dc_commit_streams(dc, &params);
 }
 
 static void hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm)
Signature · 1 line
2.37.3
author
#18 lore raw

PATCH 18/27 drm/amd/display: Use drm_err() instead of DRM_ERROR in dm_resume()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

drm_err() is helpful to show which device had the error. Adjust to using this instead for error messages.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -2
index 6e218e69f039..3bf09c17ce85 100644
@@ -3376,7 +3376,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
 
 		r = dm_dmub_hw_init(adev);
 		if (r)
-			DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r);
+			drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r);
 
 		dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0);
 		dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
@@ -3469,7 +3469,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
 
 		mutex_lock(&aconnector->hpd_lock);
 		if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
-			DRM_ERROR("KMS: Failed to detect connector\n");
+			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
 
 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
 			emulated_link_detect(aconnector->dc_link);
Signature · 1 line
2.37.3
author
#19 lore raw

PATCH 19/27 drm/amd/display: Use scoped guard for dm_resume()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

Scoped guards will release the mutex when they go out of scope. Adjust the code to use these instead.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -4
index 3bf09c17ce85..892c4d5baa50 100644
@@ -3467,17 +3467,16 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
 		if (aconnector->mst_root)
 			continue;
 
-		mutex_lock(&aconnector->hpd_lock);
+		guard(mutex)(&aconnector->hpd_lock);
 		if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
 			drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
 
 		if (aconnector->base.force && new_connection_type == dc_connection_none) {
 			emulated_link_detect(aconnector->dc_link);
 		} else {
-			mutex_lock(&dm->dc_lock);
+			guard(mutex)(&dm->dc_lock);
 			dc_exit_ips_for_hw_access(dm->dc);
 			dc_link_detect(aconnector->dc_link, DETECT_REASON_RESUMEFROMS3S4);
-			mutex_unlock(&dm->dc_lock);
 		}
 
 		if (aconnector->fake_enable && aconnector->dc_link->local_sink)
@@ -3487,7 +3486,6 @@ static int dm_resume(struct amdgpu_ip_block *ip_block)
 			dc_sink_release(aconnector->dc_sink);
 		aconnector->dc_sink = NULL;
 		amdgpu_dm_update_connector_after_detect(aconnector);
-		mutex_unlock(&aconnector->hpd_lock);
 	}
 	drm_connector_list_iter_end(&iter);
 
Signature · 1 line
2.37.3
author
#20 lore raw

PATCH 20/27 drm/amd/display: Change amdgpu_dm_irq_resume_*() to use drm_dbg()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

drm_dbg() is helpful to show which device had the debug statement. Adjust to using this instead for debug messages.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +2 -2
index 34cd39488ad0..adbbc43adde8 100644
@@ -521,7 +521,7 @@ int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
 
 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
 
-	DRM_DEBUG_KMS("DM_IRQ: early resume\n");
+	drm_dbg(adev_to_drm(adev), "DM_IRQ: early resume\n");
 
 	/* re-enable short pulse interrupts HW interrupt */
 	for (src = DC_IRQ_SOURCE_HPD1RX; src <= DC_IRQ_SOURCE_HPD6RX; src++) {
@@ -544,7 +544,7 @@ int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
 
 	DM_IRQ_TABLE_LOCK(adev, irq_table_flags);
 
-	DRM_DEBUG_KMS("DM_IRQ: resume\n");
+	drm_dbg(adev_to_drm(adev), "DM_IRQ: resume\n");
 
 	/**
 	 * Renable HW interrupt  for HPD and only since FLIP and VBLANK
Signature · 1 line
2.37.3
author
#21 lore raw

PATCH 21/27 drm/amd/display: Change amdgpu_dm_irq_resume_*() to void

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

amdgpu_dm_irq_resume_early() and amdgpu_dm_irq_resume_late() don't have any error flows. Change the return type from integer to void.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 7 ++-----
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h | 4 ++--
 2 files changed, 4 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +2 -5
index adbbc43adde8..2b63cbab0e87 100644
@@ -513,7 +513,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev)
 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
 }
 
-int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
+void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
 {
 	int src;
 	struct list_head *hnd_list_h, *hnd_list_l;
@@ -532,11 +532,9 @@ int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev)
 	}
 
 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
-
-	return 0;
 }
 
-int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
+void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
 {
 	int src;
 	struct list_head *hnd_list_h, *hnd_list_l;
@@ -558,7 +556,6 @@ int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev)
 	}
 
 	DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags);
-	return 0;
 }
 
 /*
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +2 -2
index c37bcd631e10..ba17c23b2706 100644
@@ -97,7 +97,7 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev);
  * amdgpu_dm_irq_resume - enable ASIC interrupt during resume.
  *
  */
-int amdgpu_dm_irq_resume_early(struct amdgpu_device *adev);
-int amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
+void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev);
+void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev);
 
 #endif /* __AMDGPU_DM_IRQ_H__ */
Signature · 1 line
2.37.3
author
#22 lore raw

PATCH 22/27 drm/amd/display: Use _free(kfree) for dm_gpureset_commit_state()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

Using a _free(kfree) macro drops the need for a goto statement as it will be freed when it goes out of scope.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -5
index 892c4d5baa50..153a073f93de 100644
@@ -3298,14 +3298,14 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state,
 		struct dc_scaling_info scaling_infos[MAX_SURFACES];
 		struct dc_flip_addrs flip_addrs[MAX_SURFACES];
 		struct dc_stream_update stream_update;
-	} *bundle;
+	} *bundle __free(kfree);
 	int k, m;
 
 	bundle = kzalloc(sizeof(*bundle), GFP_KERNEL);
 
 	if (!bundle) {
 		drm_err(dm->ddev, "Failed to allocate update bundle\n");
-		goto cleanup;
+		return;
 	}
 
 	for (k = 0; k < dc_state->stream_count; k++) {
@@ -3325,9 +3325,6 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state,
 					 &bundle->stream_update,
 					 bundle->surface_updates);
 	}
-
-cleanup:
-	kfree(bundle);
 }
 
 static int dm_resume(struct amdgpu_ip_block *ip_block)
Signature · 1 line
2.37.3
author
#23 lore raw

PATCH 23/27 drm/amd/display: Use scoped guard for amdgpu_dm_update_connector_after_detect()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

A scoped guard will release the mutex when it goes out of scope.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +2 -6
index 153a073f93de..e0cce4883148 100644
@@ -3673,7 +3673,7 @@ void amdgpu_dm_update_connector_after_detect(
 		 * For S3 resume with headless use eml_sink to fake stream
 		 * because on resume connector->sink is set to NULL
 		 */
-		mutex_lock(&dev->mode_config.mutex);
+		guard(mutex)(&dev->mode_config.mutex);
 
 		if (sink) {
 			if (aconnector->dc_sink) {
@@ -3698,8 +3698,6 @@ void amdgpu_dm_update_connector_after_detect(
 			}
 		}
 
-		mutex_unlock(&dev->mode_config.mutex);
-
 		if (sink)
 			dc_sink_release(sink);
 		return;
@@ -3729,7 +3727,7 @@ void amdgpu_dm_update_connector_after_detect(
 	drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
 		    aconnector->connector_id, aconnector->dc_sink, sink);
 
-	mutex_lock(&dev->mode_config.mutex);
+	guard(mutex)(&dev->mode_config.mutex);
 
 	/*
 	 * 1. Update status of the drm connector
@@ -3791,8 +3789,6 @@ void amdgpu_dm_update_connector_after_detect(
 			connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
-
 	update_subconnector_property(aconnector);
 
 	if (sink)
Signature · 1 line
2.37.3
author
#24 lore raw

PATCH 24/27 drm/amd/display: Use _free() macro for amdgpu_dm_update_connector_after_detect()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

By using a _free() macro multiple duplicated snippets of code to free the sink can be dropped. The sink will be released when leaving scope.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +4 -11
index e0cce4883148..b6fae48a9599 100644
@@ -3646,12 +3646,14 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
 	}
 }
 
+DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T))
+
 void amdgpu_dm_update_connector_after_detect(
 		struct amdgpu_dm_connector *aconnector)
 {
 	struct drm_connector *connector = &aconnector->base;
+	struct dc_sink *sink __free(sink_release) = NULL;
 	struct drm_device *dev = connector->dev;
-	struct dc_sink *sink;
 
 	/* MST handled by drm_mst framework */
 	if (aconnector->mst_mgr.mst_state == true)
@@ -3698,8 +3700,6 @@ void amdgpu_dm_update_connector_after_detect(
 			}
 		}
 
-		if (sink)
-			dc_sink_release(sink);
 		return;
 	}
 
@@ -3707,10 +3707,8 @@ void amdgpu_dm_update_connector_after_detect(
 	 * TODO: temporary guard to look for proper fix
 	 * if this sink is MST sink, we should not do anything
 	 */
-	if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
-		dc_sink_release(sink);
+	if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
 		return;
-	}
 
 	if (aconnector->dc_sink == sink) {
 		/*
@@ -3719,8 +3717,6 @@ void amdgpu_dm_update_connector_after_detect(
 		 */
 		drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n",
 				 aconnector->connector_id);
-		if (sink)
-			dc_sink_release(sink);
 		return;
 	}
 
@@ -3790,9 +3786,6 @@ void amdgpu_dm_update_connector_after_detect(
 	}
 
 	update_subconnector_property(aconnector);
-
-	if (sink)
-		dc_sink_release(sink);
 }
 
 static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
Signature · 1 line
2.37.3
author
#25 lore raw

PATCH 25/27 drm/amd/display: Use scoped guards for handle_hpd_irq_helper()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

Scoped guards will release the mutex when they go out of scope.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +5 -7
index b6fae48a9599..03b6f31fd792 100644
@@ -3805,7 +3805,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
 	 * In case of failure or MST no need to update connector status or notify the OS
 	 * since (for MST case) MST does this in its own context.
 	 */
-	mutex_lock(&aconnector->hpd_lock);
+	guard(mutex)(&aconnector->hpd_lock);
 
 	if (adev->dm.hdcp_workqueue) {
 		hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index);
@@ -3829,10 +3829,10 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
 		if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
 			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);
+		scoped_guard(mutex, &adev->dm.dc_lock) {
+			dc_exit_ips_for_hw_access(dc);
+			ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
+		}
 		if (ret) {
 			amdgpu_dm_update_connector_after_detect(aconnector);
 
@@ -3844,8 +3844,6 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
 				drm_kms_helper_connector_hotplug_event(connector);
 		}
 	}
-	mutex_unlock(&aconnector->hpd_lock);
-
 }
 
 static void handle_hpd_irq(void *param)
Signature · 1 line
2.37.3
author
#26 lore raw

PATCH 26/27 drm/amd/display: Use drm_err() for handle_hpd_irq_helper()

In reply to Wayne Lin

From: Mario Limonciello <[email protected]>

drm_err() will show which device has the error.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +1 -1
index 03b6f31fd792..73c95c3c39f9 100644
@@ -3817,7 +3817,7 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
 	aconnector->timing_changed = false;
 
 	if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type))
-		DRM_ERROR("KMS: Failed to detect connector\n");
+		drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n");
 
 	if (aconnector->base.force && new_connection_type == dc_connection_none) {
 		emulated_link_detect(aconnector->dc_link);
Signature · 1 line
2.37.3
author
#27 lore raw

PATCH 27/27 drm/amd/display: Promote DAL to 3.2.323

In reply to Wayne Lin

From: Taimur Hassan <[email protected]>

This version brings along following fixes:
- Various cleanups to amdgpu dm
- Add DP tunneling IRQ handler
- Fix display corruption for dcn35
- Fix dmcub reset problem
- Adjust BW determination for PCON
- DIO encoder refactor
- Fix performance with SubVP under gaming

---
 drivers/gpu/drm/amd/display/dc/dc.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dc.h +1 -1
index 02bf6fe51a0d..a62c4893e5ff 100644
@@ -53,7 +53,7 @@ struct aux_payload;
 struct set_config_cmd_payload;
 struct dmub_notification;
 
-#define DC_VER "3.2.322"
+#define DC_VER "3.2.323"
 
 /**
  * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC
Signature · 1 line
2.37.3