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.
- 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.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
dccg.hrn_clk_mgr.hdcn20/dcn20_clk_mgr.hdml/dcn20/dcn20_fpu.hdce100/dce_clk_mgr.hrn_clk_mgr_vbios_smu.hreg_helper.hcore_types.hdm_helpers.hatomfirmware.hclk/clk_10_0_2_offset.hclk/clk_10_0_2_sh_mask.hrenoir_ip_offset.h
Detected Declarations
function filesfunction rn_set_low_power_statefunction rn_update_clocks_update_dpp_dtofunction rn_update_clocksfunction get_vco_frequency_from_regfunction rn_dump_clk_registers_internalfunction rn_dump_clk_registersfunction rn_enable_pme_wafunction rn_init_clocksfunction build_watermark_rangesfunction rn_notify_wm_rangesfunction rn_are_clock_states_equalfunction rn_notify_link_rate_changefunction find_socclk_for_voltagefunction find_dcfclk_for_voltagefunction rn_clk_mgr_helper_populate_bw_paramsfunction rn_clk_mgr_construct
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
- Immediate include surface: `dccg.h`, `rn_clk_mgr.h`, `dcn20/dcn20_clk_mgr.h`, `dml/dcn20/dcn20_fpu.h`, `dce100/dce_clk_mgr.h`, `rn_clk_mgr_vbios_smu.h`, `reg_helper.h`, `core_types.h`.
- Detected declarations: `function files`, `function rn_set_low_power_state`, `function rn_update_clocks_update_dpp_dto`, `function rn_update_clocks`, `function get_vco_frequency_from_reg`, `function rn_dump_clk_registers_internal`, `function rn_dump_clk_registers`, `function rn_enable_pme_wa`, `function rn_init_clocks`, `function build_watermark_ranges`.
- Atlas domain: Driver Families / drivers/gpu.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.