mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
drm/amd/display: Register DCN as a PMFW DF C-state client on DCN42
[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 <nicholas.kazlauskas@amd.com> Signed-off-by: Leo Chen <leo.chen@amd.com> Signed-off-by: Wayne Lin <wayne.lin@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
a63f63f473
commit
53845307d5
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -6543,6 +6543,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user