Commit 057fc695 authored by Jun Lei's avatar Jun Lei Committed by Alex Deucher
Browse files

drm/amd/display: support "dummy pstate"



[why]
Existing support in DC for pstate only accounts for a single latency.  This is sufficient when the
variance of latency is small, or that pstate support isn't necessary for correct ASIC functionality.

Newer ASICs violate both existing assumptions.  PState support is mandatory of correct ASIC
functionality, but not all latencies have to be supported.  Existing code supports a "full p state" which
allows memory clock to change, but is hard for DCN to support (as it requires very large buffers).
New code will now fall back to a "dummy p state" support when "full p state" cannot be support.
This easy p state support should always be allowed.

[how]
Define a new latency in socBB.  Add fallback logic to support it.  Note DML is also updated to ensure
that fallback will always work.

Signed-off-by: default avatarJun Lei <Jun.Lei@amd.com>
Reviewed-by: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0488a564
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
	}

	if (should_update_pstate_support(safe_to_lower, new_clocks->p_state_change_support, clk_mgr_base->clks.p_state_change_support)) {
		clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support;
		clk_mgr_base->clks.p_state_change_support = new_clocks->p_state_change_support;
		if (pp_smu && pp_smu->set_pstate_handshake_support)
			pp_smu->set_pstate_handshake_support(&pp_smu->pp_smu, clk_mgr_base->clks.p_state_change_support);
@@ -308,6 +309,7 @@ void dcn2_init_clocks(struct clk_mgr *clk_mgr)
	memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
	// Assumption is that boot state always supports pstate
	clk_mgr->clks.p_state_change_support = true;
	clk_mgr->clks.prev_p_state_change_support = true;
}

void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base)
+7 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ struct dc_caps {
struct dc_bug_wa {
	bool no_connect_phy_config;
	bool dedcn20_305_wa;
	struct display_mode_lib alternate_dml;
};
#endif

@@ -263,6 +264,12 @@ struct dc_clocks {
	int phyclk_khz;
	int dramclk_khz;
	bool p_state_change_support;

	/*
	 * Elements below are not compared for the purposes of
	 * optimization required
	 */
	bool prev_p_state_change_support;
};

struct dc_bw_validation_profile {
+11 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

#include "dcn20_hubbub.h"
#include "reg_helper.h"
#include "clk_mgr.h"

#define REG(reg)\
	hubbub1->regs->reg
@@ -553,6 +554,16 @@ static void hubbub2_program_watermarks(
	 */
	hubbub1_program_urgent_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);
	hubbub1_program_stutter_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);

	/*
	 * There's a special case when going from p-state support to p-state unsupported
	 * here we are going to LOWER watermarks to go to dummy p-state only, but this has
	 * to be done prepare_bandwidth, not optimize
	 */
	if (hubbub1->base.ctx->dc->clk_mgr->clks.prev_p_state_change_support == true &&
		hubbub1->base.ctx->dc->clk_mgr->clks.p_state_change_support == false)
		safe_to_lower = true;

	hubbub1_program_pstate_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower);

	REG_SET(DCHUBBUB_ARB_SAT_LEVEL, 0,
+5 −5
Original line number Diff line number Diff line
@@ -1443,16 +1443,16 @@ void dcn20_prepare_bandwidth(
{
	struct hubbub *hubbub = dc->res_pool->hubbub;

	dc->clk_mgr->funcs->update_clocks(
			dc->clk_mgr,
			context,
			false);

	/* program dchubbub watermarks */
	hubbub->funcs->program_watermarks(hubbub,
					&context->bw_ctx.bw.dcn.watermarks,
					dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
					false);

	dc->clk_mgr->funcs->update_clocks(
			dc->clk_mgr,
			context,
			false);
}

void dcn20_optimize_bandwidth(
+58 −1
Original line number Diff line number Diff line
@@ -2427,7 +2427,7 @@ void dcn20_calculate_dlg_params(
	}
}

bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context,
		bool fast_validate)
{
	bool out = false;
@@ -2479,6 +2479,62 @@ validate_out:
	return out;
}


bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
		bool fast_validate)
{
	bool voltage_supported = false;
	bool full_pstate_supported = false;
	bool dummy_pstate_supported = false;
	double p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us;

	if (fast_validate)
		return dcn20_validate_bandwidth_internal(dc, context, true);


	// Best case, we support full UCLK switch latency
	voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
	full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;

	if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 ||
		(voltage_supported && full_pstate_supported)) {
		context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
		goto restore_dml_state;
	}

	// Fallback #1: Try to only support G6 temperature read latency
	context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us;

	voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
	dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;

	if (voltage_supported && dummy_pstate_supported) {
		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
		goto restore_dml_state;
	}

	// Fallback #2: Retry with "new" DCN20 to support G6 temperature read latency
	memcpy (&context->bw_ctx.dml, &dc->work_arounds.alternate_dml, sizeof (struct display_mode_lib));
	context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us;

	voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
	dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;

	if (voltage_supported && dummy_pstate_supported) {
		context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
		goto restore_dml_state;
	}

	// ERROR: fallback #2 is supposed to always work.
	ASSERT(false);

restore_dml_state:
	memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
	context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us;

	return voltage_supported;
}

struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(
		struct dc_state *state,
		const struct resource_pool *pool,
@@ -3085,6 +3141,7 @@ static bool construct(
	}

	dml_init_instance(&dc->dml, &dcn2_0_soc, &dcn2_0_ip, DML_PROJECT_NAVI10);
	dml_init_instance(&dc->work_arounds.alternate_dml, &dcn2_0_soc, &dcn2_0_ip, DML_PROJECT_NAVI10v2);

	if (!dc->debug.disable_pplib_wm_range) {
		struct pp_smu_wm_range_sets ranges = {0};
Loading