drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
Source file repositories/reference/linux-study-clean/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c- Extension
.c- Size
- 20963 bytes
- Lines
- 596
- 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.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
dccg.hclk_mgr_internal.hdcn30_clk_mgr_smu_msg.hdcn20/dcn20_clk_mgr.hdce100/dce_clk_mgr.hdcn30/dcn30_clk_mgr.hdml/dcn30/dcn30_fpu.hdcn30/dcn30m_clk_mgr.hreg_helper.hcore_types.hdm_helpers.hatomfirmware.hsienna_cichlid_ip_offset.hdcn/dcn_3_0_0_offset.hdcn/dcn_3_0_0_sh_mask.hnbio/nbio_7_4_offset.hdpcs/dpcs_3_0_0_offset.hdpcs/dpcs_3_0_0_sh_mask.hmmhub/mmhub_2_0_0_offset.hmmhub/mmhub_2_0_0_sh_mask.hdcn30_smu11_driver_if.h
Detected Declarations
function dcn3_init_single_clockfunction dcn3_build_wm_range_tablefunction dcn3_init_clocksfunction dcn30_get_vco_frequency_from_regfunction dcn3_update_clocksfunction dcn3_notify_wm_rangesfunction dcn3_set_hard_min_memclkfunction dcn3_set_hard_max_memclkfunction dcn3_set_max_memclkfunction dcn3_set_min_memclkfunction dcn3_get_memclk_states_from_smufunction dcn3_is_smu_presentfunction dcn3_are_clock_states_equalfunction dcn3_enable_pme_wafunction dcn30_notify_link_rate_changefunction dcn3_init_clocks_fpgafunction dcn3_clk_mgr_constructfunction dcn3_clk_mgr_destroy
Annotated Snippet
if (!clk_mgr_base->clks.p_state_change_support) {
if (dc->clk_mgr->dc_mode_softmax_enabled &&
new_clocks->dramclk_khz <= (int)(dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000))
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
(uint16_t)dc->clk_mgr->bw_params->dc_mode_softmax_memclk);
else
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK,
(uint16_t)clk_mgr_base->bw_params->clk_table.entries[
clk_mgr_base->bw_params->clk_table.num_entries - 1].memclk_mhz);
}
}
/* Always update saved value, even if new value not set due to P-State switching unsupported */
if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) {
clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz;
update_uclk = true;
}
/* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */
if (clk_mgr_base->clks.p_state_change_support &&
(update_uclk || !clk_mgr_base->clks.prev_p_state_change_support))
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, (uint16_t)khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz));
if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) {
if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz)
dpp_clock_lowered = true;
clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_PIXCLK, (uint16_t)khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz));
update_dppclk = true;
}
if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
dcn30_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, (uint16_t)khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz));
update_dispclk = true;
}
if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) {
if (dpp_clock_lowered) {
/* if clock is being lowered, increase DTO before lowering refclk */
dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
dcn20_update_clocks_update_dentist(clk_mgr, context);
} else {
/* if clock is being raised, increase refclk before lowering DTO */
if (update_dppclk || update_dispclk)
dcn20_update_clocks_update_dentist(clk_mgr, context);
/* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures
* that we do not lower dto when it is not safe to lower. We do not need to
* compare the current and new dppclk before calling this function.*/
dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
}
}
if (update_dispclk && dmcu && dmcu->funcs->is_dmcu_initialized(dmcu))
/*update dmcu for wait_loop count*/
dmcu->funcs->set_psr_wait_loop(dmcu,
clk_mgr_base->clks.dispclk_khz / 1000 / 7);
}
static void dcn3_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
{
uint8_t i;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
WatermarksExternal_t *table = (WatermarksExternal_t *) clk_mgr->wm_range_table;
if (!clk_mgr->smu_present)
return;
if (!table)
// should log failure
return;
memset(table, 0, sizeof(*table));
/* collect valid ranges, place in pmfw table */
for (i = 0; i < WM_SET_COUNT; i++)
if (clk_mgr->base.bw_params->wm_table.nv_entries[i].valid) {
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].MinClock = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.min_dcfclk;
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].MaxClock = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.max_dcfclk;
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].MinUclk = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.min_uclk;
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].MaxUclk = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.max_uclk;
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].WmSetting = i;
table->Watermarks.WatermarkRow[WM_DCEFCLK][i].Flags = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.wm_type;
}
dcn30_smu_set_dram_addr_high(clk_mgr, clk_mgr->wm_range_table_addr >> 32);
dcn30_smu_set_dram_addr_low(clk_mgr, clk_mgr->wm_range_table_addr & 0xFFFFFFFF);
dcn30_smu_transfer_wm_table_dram_2_smu(clk_mgr);
Annotation
- Immediate include surface: `dccg.h`, `clk_mgr_internal.h`, `dcn30_clk_mgr_smu_msg.h`, `dcn20/dcn20_clk_mgr.h`, `dce100/dce_clk_mgr.h`, `dcn30/dcn30_clk_mgr.h`, `dml/dcn30/dcn30_fpu.h`, `dcn30/dcn30m_clk_mgr.h`.
- Detected declarations: `function dcn3_init_single_clock`, `function dcn3_build_wm_range_table`, `function dcn3_init_clocks`, `function dcn30_get_vco_frequency_from_reg`, `function dcn3_update_clocks`, `function dcn3_notify_wm_ranges`, `function dcn3_set_hard_min_memclk`, `function dcn3_set_hard_max_memclk`, `function dcn3_set_max_memclk`, `function dcn3_set_min_memclk`.
- 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.