[PATCH 60/70] drm/amd/display: Register DCN as a PMFW DF C-state client on DCN42

Wayne Lin <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Leo Chen <[email protected]>

[Why]
DCN must not gate DF C-state locally via the DCHUBBUB ALLOW_SELF_REFRESH
controls: forcing a local "disallow" during MM-stutter re-entry can wedge the
fabric and hang boot. When DCN is disallowing c-state or has invalid watermarks
we should be explicit about it rather than using the watermark force selector.

[How]
Register DCN as a client of PMFW's DF C-state arbiter and signal over DALSMC
whether DCN permits DF C-state; PMFW allows DF C-state only once every client
(including DCN) has voted "allow".

- dc_clocks.cstate_allow: last DCN vote acked by PMFW
- clk_mgr_funcs::notify_cstate_disable(clk_mgr, disable)

prepare_bandwidth and headless dc_power_down_on_boot vote Allow;
hardware_release votes Disallow; init_clocks
(D0 entry) only clears the cache (cstate_allow) so the next allow re-syncs with
PMFW.

Reviewed-by: Nicholas Kazlauskas <[email protected]>
Signed-off-by: Leo Chen <[email protected]>
Signed-off-by: Wayne Lin <[email protected]>
---
 .../display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c  | 28 ++++++++++++++++++
 .../display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h  |  1 +
 .../amd/display/dc/clk_mgr/dcn42/dcn42_smu.c  | 29 ++++++++++++++++++-
 .../amd/display/dc/clk_mgr/dcn42/dcn42_smu.h  |  2 ++
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  3 ++
 drivers/gpu/drm/amd/display/dc/dc.h           |  9 ++++++
 .../amd/display/dc/hwss/dcn42/dcn42_hwseq.c   | 10 +++++++
 .../gpu/drm/amd/display/dc/inc/hw/clk_mgr.h   | 10 +++++++
 8 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
index 3baac7fa313a..c7b9bad93a93 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.c
@@ -375,6 +375,24 @@ void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base)
 	dcn42_smu_enable_pme_wa(clk_mgr);
 }
 
+void dcn42_notify_cstate_disable(struct clk_mgr *clk_mgr_base, bool disable)
+{
+	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+	bool target_allow = !disable;
+
+	DC_LOGGER_INIT(clk_mgr_base->ctx->logger);
+
+	/* Idempotent: only send when the cached vote actually changes. */
+	if (clk_mgr_base->clks.cstate_allow == target_allow)
+		return;
+
+	if (dcn42_smu_set_df_cstate_disable(clk_mgr, disable))
+		clk_mgr_base->clks.cstate_allow = target_allow;
+	else
+		DC_LOG_WARNING("%s: PMFW did not ack DfCstateDisable(%s); leaving cstate_allow=%d to retry\n",
+			__func__, disable ? "Disable" : "Allow", clk_mgr_base->clks.cstate_allow);
+}
+
 
 bool dcn42_are_clock_states_equal(struct dc_clocks *a,
 		struct dc_clocks *b)
@@ -594,6 +612,15 @@ void dcn42_init_clocks(struct clk_mgr *clk_mgr_base)
 
 	init_clk_states(clk_mgr_base);
 
+	/*
+	 * DF C-state policy
+	 * D0 entry must NOT send a PMFW message, but must unconditionally clear
+	 * the cached vote so the next allow-side transition (prepare_bandwidth
+	 * or dc_power_down_on_boot) is guaranteed to issue a fresh
+	 * DfCstateDisable(Allow) and resync DAL with PMFW.
+	 */
+	clk_mgr_base->clks.cstate_allow = false;
+
 	// to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk
 	if (dcn42_is_spll_ssc_enabled(clk_mgr_base))
 		clk_mgr_base->dp_dto_source_clock_in_khz =
@@ -1038,6 +1065,7 @@ static struct clk_mgr_funcs dcn42_funcs = {
 	.get_max_clock_khz = dcn42_get_max_clock_khz,
 	.get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist,
 	.is_smu_present = dcn42_is_smu_present,
+	.notify_cstate_disable = dcn42_notify_cstate_disable,
 };
 
 struct clk_mgr_funcs dcn42_fpga_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
index 9568ca06f00f..330242747fff 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_clk_mgr.h
@@ -67,6 +67,7 @@ unsigned int dcn42_convert_wck_ratio(uint8_t wck_ratio);
 extern struct dcn42_ss_info_table dcn42_ss_info_table;
 void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table);
 void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base);
+void dcn42_notify_cstate_disable(struct clk_mgr *clk_mgr_base, bool disable);
 void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base);
 void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base);
 void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
index 6d0012b7d6dc..5e8d979f25f0 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.c
@@ -85,7 +85,8 @@
 #define DALSMC_MSG_DispIPS2Exit                 0x11 ///< Display IPS2 exit
 
 #define DALSMC_MSG_QueryIPS2Support             0x12 ///< Return 1: support; else not supported
-#define DALSMC_Message_Count                    0x13 ///< Total number of VBIS and DAL messages
+#define DALSMC_MSG_DfCstateDisable              0x13 ///< DCN DF C-state vote (PMFW FWDEV-193711): param 0 = Allow, 1 = Disable
+#define DALSMC_Message_Count                    0x14 ///< Total number of VBIS and DAL messages
 /** @}*/
 
 
@@ -428,3 +429,29 @@ void dcn42_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
 			enable);
 	smu_print("%s: smu_set_dtbclk = %d\n", __func__, enable ? 1 : 0);
 }
+
+/*
+ * Vote DCN's DF C-state policy to PMFW. param: 0 = Allow, 1 = Disable.
+ * Returns true only when PMFW acknowledged the vote (or there is no SMU to
+ * talk to, in which case there is no DF arbiter to satisfy). On a non-OK
+ * response the caller must NOT update its cached cstate_allow so the next
+ * transition retries
+ */
+bool dcn42_smu_set_df_cstate_disable(struct clk_mgr_internal *clk_mgr, bool disable)
+{
+	int retv;
+
+	if (!clk_mgr->smu_present)
+		return true;
+
+	retv = dcn42_smu_send_msg_with_param(
+			clk_mgr,
+			DALSMC_MSG_DfCstateDisable,
+			disable ? 1 : 0);
+
+	smu_print("%s: DfCstateDisable param = %d, return = %d\n",
+		__func__, disable ? 1 : 0, retv);
+
+	/* dcn42_smu_send_msg_with_param() returns -1 on a non-OK PMFW response. */
+	return retv != -1;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
index 8ba7ff04dc05..10c67326ff7e 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn42/dcn42_smu.h
@@ -187,4 +187,6 @@ void dcn42_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *cl
 int dcn42_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr);
 int dcn42_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr);
 
+bool dcn42_smu_set_df_cstate_disable(struct clk_mgr_internal *clk_mgr, bool disable);
+
 #endif /* DAL_DC_42_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 318c3b28e918..24a01e07a44c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -6544,6 +6544,9 @@ void dc_power_down_on_boot(struct dc *dc)
 		if (dc->caps.ips_support)
 			dc_exit_ips_for_hw_access(dc);
 		dc->hwss.power_down_on_boot(dc);
+
+		if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+			dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, false);
 	}
 }
 
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index 743dde3d10ab..fcaa17b9ab1a 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -759,6 +759,15 @@ struct dc_clocks {
 	 * Elements below are not compared for the purposes of
 	 * optimization required
 	 */
+
+	/*
+	 * @cstate_allow
+	 *
+	 * DCN's DF C-state vote as last successfully acknowledged by PMFW.
+	 * false = DCN does NOT permit DF C-state;
+	 * true = DCN permits DF C-state;
+	 */
+	bool cstate_allow;
 	bool prev_p_state_change_support;
 	bool fclk_prev_p_state_change_support;
 	int num_ways;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
index 4376bf26f4ce..151a29bf0e9d 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
@@ -946,7 +946,11 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx,
 }
 void dcn42_hardware_release(struct dc *dc)
 {
+	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+		dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, true);
+
 	dcn35_hardware_release(dc);
+
 	dc_dmub_srv_release_hw(dc);
 
 }
@@ -1082,6 +1086,12 @@ void dcn42_prepare_bandwidth(
 	}
 
 	dcn401_prepare_bandwidth(dc, context);
+
+	/* valid C-state watermarks have now been committed to HW, so it
+	 * is safe to vote "allow" to PMFW.
+	 */
+	if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_cstate_disable)
+		dc->clk_mgr->funcs->notify_cstate_disable(dc->clk_mgr, false);
 }
 
 void dcn42_optimize_bandwidth(struct dc *dc, struct dc_state *context)
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
index 68dc2d4ba7ca..ec678bd249ef 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
@@ -412,6 +412,16 @@ struct clk_mgr_funcs {
 			struct clk_mgr *clk_mgr,
 			struct dc_requested_memory_qos *qos);
 
+	/**
+	 * notify_cstate_disable - Vote DCN's DF C-state policy to PMFW.
+	 * @disable: true  -> vote "disable"
+	 *           false -> vote "allow"
+	 * Sends the message only when the cached dc_clocks.cstate_allow would
+	 * change, then updates the cache on an OK response (idempotent no-op
+	 * otherwise).
+	 */
+	void (*notify_cstate_disable)(struct clk_mgr *clk_mgr, bool disable);
+
 	void (*build_clock_update_for_bls)(struct clk_mgr *clk_mgr,
 			struct dc_state *context, bool safe_to_lower,
 			struct block_sequence_state *seq_state);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.