Commit 70f0b051 authored by Ovidiu Bunea's avatar Ovidiu Bunea Committed by Alex Deucher
Browse files

drm/amd/display: Correct sequences and delays for DCN35 PG & RCG



[why]
The current PG & RCG programming in driver has some gaps and incorrect
sequences.

[how]
Added delays after ungating clocks to allow ramp up, increased polling
to allow more time for power up, and removed the incorrect sequences.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarCharlene Liu <charlene.liu@amd.com>
Signed-off-by: default avatarOvidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: default avatarWayne Lin <wayne.lin@amd.com>
Tested-by: default avatarDan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 1bde5584)
Cc: stable@vger.kernel.org
parent f5c32370
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1145,6 +1145,7 @@ struct dc_debug_options {
	bool enable_hblank_borrow;
	bool force_subvp_df_throttle;
	uint32_t acpi_transition_bitmasks[MAX_PIPES];
	bool enable_pg_cntl_debug_logs;
};


+39 −35
Original line number Diff line number Diff line
@@ -133,30 +133,34 @@ enum dsc_clk_source {
};


static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool enable)
static void dccg35_set_dsc_clk_rcg(struct dccg *dccg, int inst, bool allow_rcg)
{
	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);

	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && enable)
	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dsc && allow_rcg)
		return;

	switch (inst) {
	case 0:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 1:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 2:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 3:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	default:
		BREAK_TO_DEBUGGER();
		return;
	}

	/* Wait for clock to ramp */
	if (!allow_rcg)
		udelay(10);
}

static void dccg35_set_symclk32_se_rcg(
@@ -385,35 +389,34 @@ static void dccg35_set_dtbclk_p_rcg(struct dccg *dccg, int inst, bool enable)
	}
}

static void dccg35_set_dppclk_rcg(struct dccg *dccg,
												int inst, bool enable)
static void dccg35_set_dppclk_rcg(struct dccg *dccg, int inst, bool allow_rcg)
{

	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);


	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && enable)
	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && allow_rcg)
		return;

	switch (inst) {
	case 0:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 1:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 2:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	case 3:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable ? 0 : 1);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, allow_rcg ? 0 : 1);
		break;
	default:
	BREAK_TO_DEBUGGER();
		break;
	}
	//DC_LOG_DEBUG("%s: inst(%d) DPPCLK rcg_disable: %d\n", __func__, inst, enable ? 0 : 1);

	/* Wait for clock to ramp */
	if (!allow_rcg)
		udelay(10);
}

static void dccg35_set_dpstreamclk_rcg(
@@ -1177,32 +1180,34 @@ static void dccg35_update_dpp_dto(struct dccg *dccg, int dpp_inst,
}

static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg,
		 uint32_t dpp_inst, uint32_t enable)
		 uint32_t dpp_inst, uint32_t disallow_rcg)
{
	struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);

	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp)
	if (!dccg->ctx->dc->debug.root_clock_optimization.bits.dpp && !disallow_rcg)
		return;


	switch (dpp_inst) {
	case 0:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, enable);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, disallow_rcg);
		break;
	case 1:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, enable);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, disallow_rcg);
		break;
	case 2:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, enable);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, disallow_rcg);
		break;
	case 3:
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, enable);
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, disallow_rcg);
		break;
	default:
		break;
	}
	//DC_LOG_DEBUG("%s: dpp_inst(%d) rcg: %d\n", __func__, dpp_inst, enable);

	/* Wait for clock to ramp */
	if (disallow_rcg)
		udelay(10);
}

static void dccg35_get_pixel_rate_div(
@@ -1782,7 +1787,6 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
	//Disable DTO
	switch (inst) {
	case 0:
		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, 1);

		REG_UPDATE_2(DSCCLK0_DTO_PARAM,
@@ -1791,7 +1795,6 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
		REG_UPDATE(DSCCLK_DTO_CTRL,	DSCCLK0_EN, 1);
		break;
	case 1:
		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, 1);

		REG_UPDATE_2(DSCCLK1_DTO_PARAM,
@@ -1800,7 +1803,6 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
		break;
	case 2:
		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, 1);

		REG_UPDATE_2(DSCCLK2_DTO_PARAM,
@@ -1809,7 +1811,6 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
		REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
		break;
	case 3:
		if (dccg->ctx->dc->debug.root_clock_optimization.bits.dsc)
		REG_UPDATE(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, 1);

		REG_UPDATE_2(DSCCLK3_DTO_PARAM,
@@ -1821,6 +1822,9 @@ static void dccg35_enable_dscclk(struct dccg *dccg, int inst)
		BREAK_TO_DEBUGGER();
		return;
	}

	/* Wait for clock to ramp */
	udelay(10);
}

static void dccg35_disable_dscclk(struct dccg *dccg,
@@ -1864,6 +1868,9 @@ static void dccg35_disable_dscclk(struct dccg *dccg,
	default:
		return;
	}

	/* Wait for clock ramp */
	udelay(10);
}

static void dccg35_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
@@ -2349,11 +2356,8 @@ static void dccg35_disable_symclk_se_cb(

void dccg35_root_gate_disable_control(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating)
{

	if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) {
	dccg35_set_dppclk_root_clock_gating(dccg, pipe_idx, disable_clock_gating);
}
}

static const struct dccg_funcs dccg35_funcs_new = {
	.update_dpp_dto = dccg35_update_dpp_dto_cb,
+20 −95
Original line number Diff line number Diff line
@@ -113,6 +113,14 @@ static void enable_memory_low_power(struct dc *dc)
}
#endif

static void print_pg_status(struct dc *dc, const char *debug_func, const char *debug_log)
{
	if (dc->debug.enable_pg_cntl_debug_logs && dc->res_pool->pg_cntl) {
		if (dc->res_pool->pg_cntl->funcs->print_pg_status)
			dc->res_pool->pg_cntl->funcs->print_pg_status(dc->res_pool->pg_cntl, debug_func, debug_log);
	}
}

void dcn35_set_dmu_fgcg(struct dce_hwseq *hws, bool enable)
{
	REG_UPDATE_3(DMU_CLK_CNTL,
@@ -137,6 +145,8 @@ void dcn35_init_hw(struct dc *dc)
	uint32_t user_level = MAX_BACKLIGHT_LEVEL;
	int i;

	print_pg_status(dc, __func__, ": start");

	if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks)
		dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);

@@ -200,10 +210,7 @@ void dcn35_init_hw(struct dc *dc)

	/* we want to turn off all dp displays before doing detection */
	dc->link_srv->blank_all_dp_displays(dc);
/*
	if (hws->funcs.enable_power_gating_plane)
		hws->funcs.enable_power_gating_plane(dc->hwseq, true);
*/

	if (res_pool->hubbub && res_pool->hubbub->funcs->dchubbub_init)
		res_pool->hubbub->funcs->dchubbub_init(dc->res_pool->hubbub);
	/* If taking control over from VBIOS, we may want to optimize our first
@@ -236,6 +243,8 @@ void dcn35_init_hw(struct dc *dc)
		}

		hws->funcs.init_pipes(dc, dc->current_state);
		print_pg_status(dc, __func__, ": after init_pipes");

		if (dc->res_pool->hubbub->funcs->allow_self_refresh_control &&
			!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter)
			dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
@@ -312,6 +321,7 @@ void dcn35_init_hw(struct dc *dc)
		if (dc->res_pool->pg_cntl->funcs->init_pg_status)
			dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl);
	}
	print_pg_status(dc, __func__, ": after init_pg_status");
}

static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
@@ -500,97 +510,6 @@ void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_
	}
}

void dcn35_dsc_pg_control(
		struct dce_hwseq *hws,
		unsigned int dsc_inst,
		bool power_on)
{
	uint32_t power_gate = power_on ? 0 : 1;
	uint32_t pwr_status = power_on ? 0 : 2;
	uint32_t org_ip_request_cntl = 0;

	if (hws->ctx->dc->debug.disable_dsc_power_gate)
		return;
	if (hws->ctx->dc->debug.ignore_pg)
		return;
	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
	if (org_ip_request_cntl == 0)
		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);

	switch (dsc_inst) {
	case 0: /* DSC0 */
		REG_UPDATE(DOMAIN16_PG_CONFIG,
				DOMAIN_POWER_GATE, power_gate);

		REG_WAIT(DOMAIN16_PG_STATUS,
				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
				1, 1000);
		break;
	case 1: /* DSC1 */
		REG_UPDATE(DOMAIN17_PG_CONFIG,
				DOMAIN_POWER_GATE, power_gate);

		REG_WAIT(DOMAIN17_PG_STATUS,
				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
				1, 1000);
		break;
	case 2: /* DSC2 */
		REG_UPDATE(DOMAIN18_PG_CONFIG,
				DOMAIN_POWER_GATE, power_gate);

		REG_WAIT(DOMAIN18_PG_STATUS,
				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
				1, 1000);
		break;
	case 3: /* DSC3 */
		REG_UPDATE(DOMAIN19_PG_CONFIG,
				DOMAIN_POWER_GATE, power_gate);

		REG_WAIT(DOMAIN19_PG_STATUS,
				DOMAIN_PGFSM_PWR_STATUS, pwr_status,
				1, 1000);
		break;
	default:
		BREAK_TO_DEBUGGER();
		break;
	}

	if (org_ip_request_cntl == 0)
		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
}

void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable)
{
	bool force_on = true; /* disable power gating */
	uint32_t org_ip_request_cntl = 0;

	if (hws->ctx->dc->debug.disable_hubp_power_gate)
		return;
	if (hws->ctx->dc->debug.ignore_pg)
		return;
	REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
	if (org_ip_request_cntl == 0)
		REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
	/* DCHUBP0/1/2/3/4/5 */
	REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	/* DPP0/1/2/3/4/5 */
	REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);

	force_on = true; /* disable power gating */
	if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)
		force_on = false;

	/* DCS0/1/2/3/4 */
	REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
	REG_UPDATE(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);


}

/* In headless boot cases, DIG may be turned
 * on which causes HW/SW discrepancies.
 * To avoid this, power down hardware on boot
@@ -1453,6 +1372,8 @@ void dcn35_prepare_bandwidth(
	}

	dcn20_prepare_bandwidth(dc, context);

	print_pg_status(dc, __func__, ": after rcg and power up");
}

void dcn35_optimize_bandwidth(
@@ -1461,6 +1382,8 @@ void dcn35_optimize_bandwidth(
{
	struct pg_block_update pg_update_state;

	print_pg_status(dc, __func__, ": before rcg and power up");

	dcn20_optimize_bandwidth(dc, context);

	if (dc->hwss.calc_blocks_to_gate) {
@@ -1472,6 +1395,8 @@ void dcn35_optimize_bandwidth(
		if (dc->hwss.root_clock_control)
			dc->hwss.root_clock_control(dc, &pg_update_state, false);
	}

	print_pg_status(dc, __func__, ": after rcg and power up");
}

void dcn35_set_drr(struct pipe_ctx **pipe_ctx,
+0 −3
Original line number Diff line number Diff line
@@ -115,7 +115,6 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
	.exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
	.update_visual_confirm_color = dcn10_update_visual_confirm_color,
	.apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
	.update_dsc_pg = dcn32_update_dsc_pg,
	.calc_blocks_to_gate = dcn35_calc_blocks_to_gate,
	.calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate,
	.hw_block_power_up = dcn35_hw_block_power_up,
@@ -150,7 +149,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
	.plane_atomic_disable = dcn35_plane_atomic_disable,
	//.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/
	//.hubp_pg_control = dcn35_hubp_pg_control,
	.enable_power_gating_plane = dcn35_enable_power_gating_plane,
	.dpp_root_clock_control = dcn35_dpp_root_clock_control,
	.dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
	.physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
@@ -165,7 +163,6 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
	.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
	.resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio,
	.is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy,
	.dsc_pg_control = dcn35_dsc_pg_control,
	.dsc_pg_status = dcn32_dsc_pg_status,
	.enable_plane = dcn35_enable_plane,
	.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
+0 −3
Original line number Diff line number Diff line
@@ -114,7 +114,6 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
	.exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
	.update_visual_confirm_color = dcn10_update_visual_confirm_color,
	.apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
	.update_dsc_pg = dcn32_update_dsc_pg,
	.calc_blocks_to_gate = dcn351_calc_blocks_to_gate,
	.calc_blocks_to_ungate = dcn351_calc_blocks_to_ungate,
	.hw_block_power_up = dcn351_hw_block_power_up,
@@ -145,7 +144,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
	.plane_atomic_disable = dcn35_plane_atomic_disable,
	//.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/
	//.hubp_pg_control = dcn35_hubp_pg_control,
	.enable_power_gating_plane = dcn35_enable_power_gating_plane,
	.dpp_root_clock_control = dcn35_dpp_root_clock_control,
	.dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
	.physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
@@ -159,7 +157,6 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
	.setup_hpo_hw_control = dcn35_setup_hpo_hw_control,
	.calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values,
	.is_dp_dig_pixel_rate_div_policy = dcn35_is_dp_dig_pixel_rate_div_policy,
	.dsc_pg_control = dcn35_dsc_pg_control,
	.dsc_pg_status = dcn32_dsc_pg_status,
	.enable_plane = dcn35_enable_plane,
	.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
Loading