drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
Extension
.c
Size
12971 bytes
Lines
349
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

#include "core_types.h"
#include "clk_mgr_internal.h"
#include "rv1_clk_mgr.h"
#include "dce100/dce_clk_mgr.h"
#include "dce112/dce112_clk_mgr.h"
#include "rv1_clk_mgr_vbios_smu.h"
#include "rv1_clk_mgr_clk.h"

static void rv1_init_clocks(struct clk_mgr *clk_mgr)
{
	memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
}

static int rv1_determine_dppclk_threshold(struct clk_mgr_internal *clk_mgr, struct dc_clocks *new_clocks)
{
	bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
	bool dispclk_increase = new_clocks->dispclk_khz > clk_mgr->base.clks.dispclk_khz;
	int disp_clk_threshold = new_clocks->max_supported_dppclk_khz;
	bool cur_dpp_div = clk_mgr->base.clks.dispclk_khz > clk_mgr->base.clks.dppclk_khz;

	/* increase clock, looking for div is 0 for current, request div is 1*/
	if (dispclk_increase) {
		/* already divided by 2, no need to reach target clk with 2 steps*/
		if (cur_dpp_div)
			return new_clocks->dispclk_khz;

		/* request disp clk is lower than maximum supported dpp clk,
		 * no need to reach target clk with two steps.
		 */
		if (new_clocks->dispclk_khz <= disp_clk_threshold)
			return new_clocks->dispclk_khz;

		/* target dpp clk not request divided by 2, still within threshold */
		if (!request_dpp_div)
			return new_clocks->dispclk_khz;

	} else {
		/* decrease clock, looking for current dppclk divided by 2,
		 * request dppclk not divided by 2.
		 */

		/* current dpp clk not divided by 2, no need to ramp*/
		if (!cur_dpp_div)
			return new_clocks->dispclk_khz;

		/* current disp clk is lower than current maximum dpp clk,
		 * no need to ramp
		 */
		if (clk_mgr->base.clks.dispclk_khz <= disp_clk_threshold)
			return new_clocks->dispclk_khz;

		/* request dpp clk need to be divided by 2 */
		if (request_dpp_div)
			return new_clocks->dispclk_khz;
	}

	return disp_clk_threshold;
}

static void ramp_up_dispclk_with_dpp(
		struct clk_mgr_internal *clk_mgr,
		struct dc *dc,
		struct dc_clocks *new_clocks,
		bool safe_to_lower)
{
	uint32_t i;
	int dispclk_to_dpp_threshold = rv1_determine_dppclk_threshold(clk_mgr, new_clocks);
	bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;

	/* this function is to change dispclk, dppclk and dprefclk according to
	 * bandwidth requirement. Its call stack is rv1_update_clocks -->
	 * update_clocks --> dcn10_prepare_bandwidth / dcn10_optimize_bandwidth
	 * --> prepare_bandwidth / optimize_bandwidth. before change dcn hw,
	 * prepare_bandwidth will be called first to allow enough clock,
	 * watermark for change, after end of dcn hw change, optimize_bandwidth
	 * is executed to lower clock to save power for new dcn hw settings.
	 *
	 * below is sequence of commit_planes_for_stream:
	 *
	 * step 1: prepare_bandwidth - raise clock to have enough bandwidth
	 * step 2: lock_doublebuffer_enable
	 * step 3: pipe_control_lock(true) - make dchubp register change will
	 * not take effect right way
	 * step 4: apply_ctx_for_surface - program dchubp
	 * step 5: pipe_control_lock(false) - dchubp register change take effect
	 * step 6: optimize_bandwidth --> dc_post_update_surfaces_to_stream
	 * for full_date, optimize clock to save power
	 *
	 * at end of step 1, dcn clocks (dprefclk, dispclk, dppclk) may be
	 * changed for new dchubp configuration. but real dcn hub dchubps are

Annotation

Implementation Notes