drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
Extension
.c
Size
27713 bytes
Lines
795
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (display_count == 0) {
			rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
			/* update power state */
			clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
		}
	}
}

static void rn_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
		struct dc_state *context, int ref_dpp_clk, bool safe_to_lower)
{
	uint32_t i;

	clk_mgr->dccg->ref_dppclk = ref_dpp_clk;

	for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) {
		int dpp_inst, dppclk_khz, prev_dppclk_khz;

		/* Loop index may not match dpp->inst if some pipes disabled,
		 * so select correct inst from res_pool
		 */
		dpp_inst = clk_mgr->base.ctx->dc->res_pool->dpps[i]->inst;
		dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;

		prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[dpp_inst];

		if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
			clk_mgr->dccg->funcs->update_dpp_dto(
							clk_mgr->dccg, dpp_inst, dppclk_khz);
	}
}


static void rn_update_clocks(struct clk_mgr *clk_mgr_base,
			struct dc_state *context,
			bool safe_to_lower)
{
	struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
	struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
	struct dc *dc = clk_mgr_base->ctx->dc;
	int display_count;
	bool update_dppclk = false;
	bool update_dispclk = false;
	bool dpp_clock_lowered = false;

	struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;

	if (dc->work_arounds.skip_clock_update)
		return;

	/*
	 * if it is safe to lower, but we are already in the lower state, we don't have to do anything
	 * also if safe to lower is false, we just go in the higher state
	 */
	if (safe_to_lower && !dc->debug.disable_48mhz_pwrdwn) {
		/* check that we're not already in lower */
		if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {

			display_count = rn_get_active_display_cnt_wa(dc, context);

			/* if we can go lower, go lower */
			if (display_count == 0) {
				rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
				/* update power state */
				clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
			}
		}
	} else {
		/* check that we're not already in D0 */
		if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
			rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_MISSION_MODE);
			/* update power state */
			clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
		}
	}

	if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
		clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
		rn_vbios_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
	}

	if (should_set_clock(safe_to_lower,
			new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
		clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
		rn_vbios_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
	}

	// workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
	// Do not adjust dppclk if dppclk is 0 to avoid unexpected result
	if (new_clocks->dppclk_khz < 100000 && new_clocks->dppclk_khz > 0)

Annotation

Implementation Notes