drm/amd/display: gate DCE ASIC code behind CONFIG_DRM_AMD_DC_DCE

[Why&How]
Refactor to make DCE support optional.

Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Gaghik Khachatrian <gaghik.khachatrian@amd.com>
Signed-off-by: Tom Chung <chiahsuan.chung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Gaghik Khachatrian 2026-07-23 22:14:02 -04:00 committed by Alex Deucher
parent 7dcd85c224
commit cd2cfe4d15
23 changed files with 380 additions and 276 deletions

View File

@ -34,11 +34,20 @@ config DRM_AMD_DC_SI
bool "AMD DC support for Southern Islands ASICs"
depends on DRM_AMDGPU_SI
depends on DRM_AMD_DC
depends on DRM_AMD_DC_DCE
help
Choose this option to enable new AMD DC support for SI asics
by default. This includes Tahiti, Pitcairn, Cape Verde, Oland.
Hainan is not supported by AMD DC and it has no physical DCE6.
config DRM_AMD_DC_DCE
bool "AMD DC support for legacy DCE ASICs"
default y
depends on DRM_AMD_DC
help
Enable support for the legacy DCE (DCE 8/10/11/12) display engines.
Enabled by default so DC keeps support for these older ASICs.
config DEBUG_KERNEL_DC
bool "Enable kgdb break in DC"
depends on DRM_AMD_DC

View File

@ -35,7 +35,10 @@ bool dal_bios_parser_init_cmd_tbl_helper(
const struct command_table_helper **h,
enum dce_version dce)
{
switch (dce) {
if (!h)
return false;
switch (dce) {
#if defined(CONFIG_DRM_AMD_DC_SI)
case DCE_VERSION_6_0:
case DCE_VERSION_6_1:
@ -44,6 +47,7 @@ bool dal_bios_parser_init_cmd_tbl_helper(
return true;
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@ -62,6 +66,7 @@ bool dal_bios_parser_init_cmd_tbl_helper(
case DCE_VERSION_11_22:
*h = dal_cmd_tbl_helper_dce112_get_table();
return true;
#endif
default:
/* Unsupported DCE */

View File

@ -45,6 +45,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
return true;
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@ -58,6 +59,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
case DCE_VERSION_11_0:
*h = dal_cmd_tbl_helper_dce110_get_table();
return true;
#endif
case DCE_VERSION_11_2:
case DCE_VERSION_11_22:

View File

@ -29,6 +29,7 @@ AMD_DAL_CLK_MGR = $(addprefix $(AMDDALPATH)/dc/clk_mgr/,$(CLK_MGR))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR)
ifdef CONFIG_DRM_AMD_DC_DCE
###############################################################################
# DCE 100 and DCE8x
###############################################################################
@ -62,6 +63,13 @@ CLK_MGR_DCE120 = dce120_clk_mgr.o
AMD_DAL_CLK_MGR_DCE120 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dce120/,$(CLK_MGR_DCE120))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCE120)
endif # CONFIG_DRM_AMD_DC_DCE
# Shared clock helpers used by both the DCE and DCN clock managers. Built
# unconditionally (not gated on CONFIG_DRM_AMD_DC_FP) so non-FP configs that
# still build the DCE clock managers can resolve them.
AMD_DISPLAY_FILES += $(AMDDALPATH)/dc/clk_mgr/dcn10/dcn10_clk_mgr.o
ifdef CONFIG_DRM_AMD_DC_FP
###############################################################################
# DCN10

View File

@ -30,10 +30,12 @@
#include "dc_state_priv.h"
#include "link_service.h"
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce100/dce_clk_mgr.h"
#include "dce110/dce110_clk_mgr.h"
#include "dce112/dce112_clk_mgr.h"
#include "dce120/dce120_clk_mgr.h"
#endif
#include "dcn10/rv1_clk_mgr.h"
#include "dcn10/rv2_clk_mgr.h"
#include "dcn20/dcn20_clk_mgr.h"
@ -152,6 +154,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
struct hw_asic_id asic_id = ctx->asic_id;
switch (asic_id.chip_family) {
#if defined(CONFIG_DRM_AMD_DC_DCE)
case FAMILY_SI:
case FAMILY_CI:
case FAMILY_KV: {
@ -211,6 +214,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
dce120_clk_mgr_construct(ctx, clk_mgr);
return &clk_mgr->base;
}
#endif
#if defined(CONFIG_DRM_AMD_DC_FP)
case FAMILY_RV: {
struct clk_mgr_internal *clk_mgr = kzalloc_obj(*clk_mgr);

View File

@ -62,56 +62,6 @@ static const struct clk_mgr_mask disp_clk_mask = {
CLK_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK)
};
unsigned int dentist_get_divider_from_did(unsigned int did)
{
if (did < DENTIST_BASE_DID_1)
did = DENTIST_BASE_DID_1;
if (did > DENTIST_MAX_DID)
did = DENTIST_MAX_DID;
if (did < DENTIST_BASE_DID_2) {
return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
* (did - DENTIST_BASE_DID_1);
} else if (did < DENTIST_BASE_DID_3) {
return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
* (did - DENTIST_BASE_DID_2);
} else if (did < DENTIST_BASE_DID_4) {
return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
* (did - DENTIST_BASE_DID_3);
} else {
return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
* (did - DENTIST_BASE_DID_4);
}
}
/* SW will adjust DP REF Clock average value for all purposes
* (DP DTO / DP Audio DTO and DP GTC)
if clock is spread for all cases:
-if SS enabled on DP Ref clock and HW de-spreading enabled with SW
calculations for DS_INCR/DS_MODULO (this is planned to be default case)
-if SS enabled on DP Ref clock and HW de-spreading enabled with HW
calculations (not planned to be used, but average clock should still
be valid)
-if SS enabled on DP Ref clock and HW de-spreading disabled
(should not be case with CIK) then SW should program all rates
generated according to average value (case as with previous ASICs)
*/
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz)
{
if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
struct fixed31_32 ss_percentage = dc_fixpt_div_int(
dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
clk_mgr_dce->dprefclk_ss_divider), 200);
struct fixed31_32 adj_dp_ref_clk_khz;
ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
}
return dp_ref_clk_khz;
}
static int dce60_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
@ -155,13 +105,6 @@ int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
return dce_adjust_dp_ref_freq_for_ss(clk_mgr, dp_ref_clk_khz);
}
int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
return dce_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_base->dprefclk_khz);
}
/* unit: in_khz before mode set, get pixel clock from context. ASIC register
* may not be programmed yet
*/
@ -256,64 +199,6 @@ static void dce_clock_read_integrated_info(struct clk_mgr_internal *clk_mgr_dce)
clk_mgr_dce->dfs_bypass_enabled = true;
}
void dce_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce)
{
struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
int ss_info_num = bp->funcs->get_ss_entry_number(
bp, AS_SIGNAL_TYPE_GPU_PLL);
if (ss_info_num) {
struct spread_spectrum_info info = { { 0 } };
enum bp_result result = bp->funcs->get_spread_spectrum_info(
bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
* even if SS not enabled and in that case
* SSInfo.spreadSpectrumPercentage !=0 would be sign
* that SS is enabled
*/
if (result == BP_RESULT_OK &&
info.spread_spectrum_percentage != 0) {
clk_mgr_dce->ss_on_dprefclk = true;
clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
if (info.type.CENTER_MODE == 0) {
/* TODO: Currently for DP Reference clock we
* need only SS percentage for
* downspread */
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
return;
}
result = bp->funcs->get_spread_spectrum_info(
bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
/* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
* even if SS not enabled and in that case
* SSInfo.spreadSpectrumPercentage !=0 would be sign
* that SS is enabled
*/
if (result == BP_RESULT_OK &&
info.spread_spectrum_percentage != 0) {
clk_mgr_dce->ss_on_dprefclk = true;
clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
if (info.type.CENTER_MODE == 0) {
/* Currently for DP Reference clock we
* need only SS percentage for
* downspread */
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
if (clk_mgr_dce->base.ctx->dc->config.ignore_dpref_ss)
clk_mgr_dce->dprefclk_ss_percentage = 0;
}
}
}
static void dce_pplib_apply_display_requirements(
struct dc *dc,
struct dc_state *context)

View File

@ -28,9 +28,9 @@
#define _DCE_CLK_MGR_H_
#include "dc.h"
#include "dcn10/dcn10_clk_mgr.h"
/* functions shared by other dce clk mgrs */
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz);
int dce_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base);
uint32_t dce_get_max_pixel_clock_for_all_paths(struct dc_state *context);
@ -40,10 +40,6 @@ void dce_clk_mgr_construct(
struct dc_context *ctx,
struct clk_mgr_internal *clk_mgr_dce);
void dce_clock_read_ss_info(struct clk_mgr_internal *dccg_dce);
int dce12_get_dp_ref_freq_khz(struct clk_mgr *dccg);
int dce_set_clock(
struct clk_mgr *clk_mgr_base,
int requested_clk_khz);
@ -51,6 +47,4 @@ int dce_set_clock(
void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr);
unsigned int dentist_get_divider_from_did(unsigned int did);
#endif /* _DCE_CLK_MGR_H_ */

View File

@ -101,65 +101,6 @@ int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz)
return actual_clock;
}
int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
{
struct bp_set_dce_clock_parameters dce_clk_params;
struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
struct dc *dc = clk_mgr->base.ctx->dc;
struct dmcu *dmcu = dc->res_pool->dmcu;
int actual_clock = requested_clk_khz;
/* Prepare to program display clock*/
memset(&dce_clk_params, 0, sizeof(dce_clk_params));
/* Make sure requested clock isn't lower than minimum threshold*/
if (requested_clk_khz > 0)
requested_clk_khz = max(requested_clk_khz,
clk_mgr->base.dentist_vco_freq_khz / 62);
dce_clk_params.target_clock_frequency = requested_clk_khz;
dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
bp->funcs->set_dce_clock(bp, &dce_clk_params);
actual_clock = dce_clk_params.target_clock_frequency;
if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
dmcu->funcs->set_psr_wait_loop(dmcu,
actual_clock / 1000 / 7);
}
clk_mgr->dfs_bypass_disp_clk = actual_clock;
return actual_clock;
}
int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr)
{
struct bp_set_dce_clock_parameters dce_clk_params;
struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
memset(&dce_clk_params, 0, sizeof(dce_clk_params));
/*Program DP ref Clock*/
/*VBIOS will determine DPREFCLK frequency, so we don't set it*/
dce_clk_params.target_clock_frequency = 0;
dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
if (!((clk_mgr->base.ctx->asic_id.chip_family == FAMILY_AI) &&
ASICREV_IS_VEGA20_P(clk_mgr->base.ctx->asic_id.hw_internal_rev)))
dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
(dce_clk_params.pll_id ==
CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
else
dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
bp->funcs->set_dce_clock(bp, &dce_clk_params);
/* Returns the dp_refclk that was set */
return dce_clk_params.target_clock_frequency;
}
static void dce112_update_clocks(struct clk_mgr *clk_mgr_base,
struct dc_state *context,
bool safe_to_lower)

View File

@ -26,6 +26,8 @@
#ifndef DAL_DC_DCE_DCE112_CLK_MGR_H_
#define DAL_DC_DCE_DCE112_CLK_MGR_H_
/* dce112_set_dispclk and dce112_set_dprefclk are declared here. */
#include "dcn10/dcn10_clk_mgr.h"
void dce112_clk_mgr_construct(
struct dc_context *ctx,
@ -33,7 +35,5 @@ void dce112_clk_mgr_construct(
/* functions shared with other clk mgr */
int dce112_set_clock(struct clk_mgr *clk_mgr_base, int requested_clk_khz);
int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz);
int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr);
#endif /* DAL_DC_DCE_DCE112_CLK_MGR_H_ */

View File

@ -0,0 +1,181 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#include "clk_mgr_internal.h"
#include "core_types.h"
#include "dal_asic_id.h"
#include "dcn10_clk_mgr.h"
unsigned int dentist_get_divider_from_did(unsigned int did)
{
if (did < DENTIST_BASE_DID_1)
did = DENTIST_BASE_DID_1;
if (did > DENTIST_MAX_DID)
did = DENTIST_MAX_DID;
if (did < DENTIST_BASE_DID_2) {
return DENTIST_DIVIDER_RANGE_1_START + DENTIST_DIVIDER_RANGE_1_STEP
* (did - DENTIST_BASE_DID_1);
} else if (did < DENTIST_BASE_DID_3) {
return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP
* (did - DENTIST_BASE_DID_2);
} else if (did < DENTIST_BASE_DID_4) {
return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP
* (did - DENTIST_BASE_DID_3);
} else {
return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP
* (did - DENTIST_BASE_DID_4);
}
}
/* SW will adjust DP REF Clock average value for all purposes
* (DP DTO / DP Audio DTO and DP GTC)
if clock is spread for all cases:
-if SS enabled on DP Ref clock and HW de-spreading enabled with SW
calculations for DS_INCR/DS_MODULO (this is planned to be default case)
-if SS enabled on DP Ref clock and HW de-spreading enabled with HW
calculations (not planned to be used, but average clock should still
be valid)
-if SS enabled on DP Ref clock and HW de-spreading disabled
(should not be case with CIK) then SW should program all rates
generated according to average value (case as with previous ASICs)
*/
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz)
{
if (clk_mgr_dce->ss_on_dprefclk && clk_mgr_dce->dprefclk_ss_divider != 0) {
struct fixed31_32 ss_percentage = dc_fixpt_div_int(
dc_fixpt_from_fraction(clk_mgr_dce->dprefclk_ss_percentage,
clk_mgr_dce->dprefclk_ss_divider), 200);
struct fixed31_32 adj_dp_ref_clk_khz;
ss_percentage = dc_fixpt_sub(dc_fixpt_one, ss_percentage);
adj_dp_ref_clk_khz = dc_fixpt_mul_int(ss_percentage, dp_ref_clk_khz);
dp_ref_clk_khz = dc_fixpt_floor(adj_dp_ref_clk_khz);
}
return dp_ref_clk_khz;
}
int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base)
{
struct clk_mgr_internal *clk_mgr_dce = TO_CLK_MGR_INTERNAL(clk_mgr_base);
return dce_adjust_dp_ref_freq_for_ss(clk_mgr_dce, clk_mgr_base->dprefclk_khz);
}
void dce_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce)
{
struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
int ss_info_num = bp->funcs->get_ss_entry_number(
bp, AS_SIGNAL_TYPE_GPU_PLL);
if (ss_info_num) {
struct spread_spectrum_info info = { { 0 } };
enum bp_result result = bp->funcs->get_spread_spectrum_info(
bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info);
/* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
* even if SS not enabled and in that case
* SSInfo.spreadSpectrumPercentage !=0 would be sign
* that SS is enabled
*/
if (result == BP_RESULT_OK &&
info.spread_spectrum_percentage != 0) {
clk_mgr_dce->ss_on_dprefclk = true;
clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
if (info.type.CENTER_MODE == 0) {
/* TODO: Currently for DP Reference clock we
* need only SS percentage for
* downspread */
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
return;
}
result = bp->funcs->get_spread_spectrum_info(
bp, AS_SIGNAL_TYPE_DISPLAY_PORT, 0, &info);
/* Based on VBIOS, VBIOS will keep entry for DPREFCLK SS
* even if SS not enabled and in that case
* SSInfo.spreadSpectrumPercentage !=0 would be sign
* that SS is enabled
*/
if (result == BP_RESULT_OK &&
info.spread_spectrum_percentage != 0) {
clk_mgr_dce->ss_on_dprefclk = true;
clk_mgr_dce->dprefclk_ss_divider = info.spread_percentage_divider;
if (info.type.CENTER_MODE == 0) {
/* Currently for DP Reference clock we
* need only SS percentage for
* downspread */
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
if (clk_mgr_dce->base.ctx->dc->config.ignore_dpref_ss)
clk_mgr_dce->dprefclk_ss_percentage = 0;
}
}
}
int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz)
{
struct bp_set_dce_clock_parameters dce_clk_params;
struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
struct dc *dc = clk_mgr->base.ctx->dc;
struct dmcu *dmcu = dc->res_pool->dmcu;
int actual_clock;
/* Prepare to program display clock*/
memset(&dce_clk_params, 0, sizeof(dce_clk_params));
/* Make sure requested clock isn't lower than minimum threshold*/
if (requested_clk_khz > 0)
requested_clk_khz = max(requested_clk_khz,
clk_mgr->base.dentist_vco_freq_khz / 62);
dce_clk_params.target_clock_frequency = requested_clk_khz;
dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
dce_clk_params.clock_type = DCECLOCK_TYPE_DISPLAY_CLOCK;
bp->funcs->set_dce_clock(bp, &dce_clk_params);
actual_clock = dce_clk_params.target_clock_frequency;
if (dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) {
if (clk_mgr->dfs_bypass_disp_clk != actual_clock)
dmcu->funcs->set_psr_wait_loop(dmcu,
actual_clock / 1000 / 7);
}
clk_mgr->dfs_bypass_disp_clk = actual_clock;
return actual_clock;
}
int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr)
{
struct bp_set_dce_clock_parameters dce_clk_params;
struct dc_bios *bp = clk_mgr->base.ctx->dc_bios;
memset(&dce_clk_params, 0, sizeof(dce_clk_params));
/*Program DP ref Clock*/
/*VBIOS will determine DPREFCLK frequency, so we don't set it*/
dce_clk_params.target_clock_frequency = 0;
dce_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
dce_clk_params.clock_type = DCECLOCK_TYPE_DPREFCLK;
if (!((clk_mgr->base.ctx->asic_id.chip_family == FAMILY_AI) &&
ASICREV_IS_VEGA20_P(clk_mgr->base.ctx->asic_id.hw_internal_rev)))
dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK =
(dce_clk_params.pll_id ==
CLOCK_SOURCE_COMBO_DISPLAY_PLL0);
else
dce_clk_params.flags.USE_GENLOCK_AS_SOURCE_FOR_DPREFCLK = false;
bp->funcs->set_dce_clock(bp, &dce_clk_params);
/* Returns the dp_refclk that was set */
return dce_clk_params.target_clock_frequency;
}

View File

@ -0,0 +1,29 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright 2026 Advanced Micro Devices, Inc.
*/
#ifndef __DCN10_CLK_MGR_H__
#define __DCN10_CLK_MGR_H__
#include "dc.h"
struct clk_mgr_internal;
/*
* Shared clock helpers referenced by both the DCE and DCN clock managers.
*/
int dce_adjust_dp_ref_freq_for_ss(struct clk_mgr_internal *clk_mgr_dce, int dp_ref_clk_khz);
void dce_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce);
int dce12_get_dp_ref_freq_khz(struct clk_mgr *clk_mgr_base);
unsigned int dentist_get_divider_from_did(unsigned int did);
int dce112_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_clk_khz);
int dce112_set_dprefclk(struct clk_mgr_internal *clk_mgr);
#endif /* __DCN10_CLK_MGR_H__ */

View File

@ -55,11 +55,13 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce80/dce80_resource.h"
#include "dce100/dce100_resource.h"
#include "dce110/dce110_resource.h"
#include "dce112/dce112_resource.h"
#include "dce120/dce120_resource.h"
#endif
#include "dcn10/dcn10_resource.h"
#include "dcn20/dcn20_resource.h"
#include "dcn21/dcn21_resource.h"
@ -293,6 +295,7 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
init_data->num_virtual_links, dc);
break;
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
case DCE_VERSION_8_0:
res_pool = dce80_create_resource_pool(
(uint8_t)init_data->num_virtual_links, dc);
@ -324,6 +327,7 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
res_pool = dce120_create_resource_pool(
(uint8_t)init_data->num_virtual_links, dc);
break;
#endif
#if defined(CONFIG_DRM_AMD_DC_FP)
case DCN_VERSION_1_0:
@ -5301,6 +5305,81 @@ void resource_build_info_frame(struct pipe_ctx *pipe_ctx)
patch_gamut_packet_checksum(&info->gamut);
}
/*
* Physical-clock resource mapping used by the DCE and DCN resource pools.
* Unit tests provide their own stub (see dc_resource_ut_helpers.c).
*/
enum {
CLK_SRC_PLL0 = 0,
CLK_SRC_PLL1,
CLK_SRC_PLL2,
CLK_SRC_PLL3,
CLK_SRC_PLL4,
CLK_SRC_PLL5,
};
static struct clock_source *find_matching_pll(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct dc_stream_state *const stream)
{
(void)res_ctx;
switch (stream->link->link_enc->transmitter) {
case TRANSMITTER_UNIPHY_A:
return pool->clock_sources[CLK_SRC_PLL0];
case TRANSMITTER_UNIPHY_B:
return pool->clock_sources[CLK_SRC_PLL1];
case TRANSMITTER_UNIPHY_C:
return pool->clock_sources[CLK_SRC_PLL2];
case TRANSMITTER_UNIPHY_D:
return pool->clock_sources[CLK_SRC_PLL3];
case TRANSMITTER_UNIPHY_E:
return pool->clock_sources[CLK_SRC_PLL4];
case TRANSMITTER_UNIPHY_F:
return pool->clock_sources[CLK_SRC_PLL5];
default:
return NULL;
}
}
enum dc_status resource_map_phy_clock_resources(
const struct dc *dc,
struct dc_state *context,
struct dc_stream_state *stream)
{
/* acquire new resources */
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
if (dc_is_dp_signal(pipe_ctx->stream->signal)
|| dc_is_virtual_signal(pipe_ctx->stream->signal))
pipe_ctx->clock_source =
dc->res_pool->dp_clock_source;
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL)
pipe_ctx->clock_source =
dc->res_pool->dp_clock_source;
else {
if (stream && stream->link && stream->link->link_enc)
pipe_ctx->clock_source = find_matching_pll(
&context->res_ctx, dc->res_pool,
stream);
}
if (pipe_ctx->clock_source == NULL)
return DC_NO_CLOCK_SOURCE_RESOURCE;
resource_reference_clock_source(
&context->res_ctx,
dc->res_pool,
pipe_ctx->clock_source);
return DC_OK;
}
enum dc_status resource_map_clock_resources(
const struct dc *dc,
struct dc_state *context,

View File

@ -43,9 +43,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/hw_factory_dce60.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce80/hw_factory_dce80.h"
#include "dce110/hw_factory_dce110.h"
#include "dce120/hw_factory_dce120.h"
#endif
#include "dcn10/hw_factory_dcn10.h"
#include "dcn20/hw_factory_dcn20.h"
#include "dcn21/hw_factory_dcn21.h"
@ -71,6 +73,7 @@ bool dal_hw_factory_init(
dal_hw_factory_dce60_init(factory);
return true;
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@ -89,6 +92,7 @@ bool dal_hw_factory_init(
case DCE_VERSION_12_1:
dal_hw_factory_dce120_init(factory);
return true;
#endif
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_factory_dcn10_init(factory);

View File

@ -43,9 +43,11 @@
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/hw_translate_dce60.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce80/hw_translate_dce80.h"
#include "dce110/hw_translate_dce110.h"
#include "dce120/hw_translate_dce120.h"
#endif
#include "dcn10/hw_translate_dcn10.h"
#include "dcn20/hw_translate_dcn20.h"
#include "dcn21/hw_translate_dcn21.h"
@ -75,6 +77,7 @@ bool dal_hw_translate_init(
dal_hw_translate_dce60_init(translate);
return true;
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
case DCE_VERSION_8_0:
case DCE_VERSION_8_1:
case DCE_VERSION_8_3:
@ -90,6 +93,7 @@ bool dal_hw_translate_init(
case DCE_VERSION_12_1:
dal_hw_translate_dce120_init(translate);
return true;
#endif
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_translate_dcn10_init(translate);

View File

@ -36,11 +36,13 @@ endif
###############################################################################
ifdef CONFIG_DRM_AMD_DC_DCE
HWSS_DCE80 = dce80_hwseq.o
AMD_DAL_HWSS_DCE80 = $(addprefix $(AMDDALPATH)/dc/hwss/dce80/,$(HWSS_DCE80))
AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE80)
endif
###############################################################################
@ -52,11 +54,13 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE)
###############################################################################
ifdef CONFIG_DRM_AMD_DC_DCE
HWSS_DCE100 = dce100_hwseq.o
AMD_DAL_HWSS_DCE100 = $(addprefix $(AMDDALPATH)/dc/hwss/dce100/,$(HWSS_DCE100))
AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE100)
endif
###############################################################################
@ -68,6 +72,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE110)
###############################################################################
ifdef CONFIG_DRM_AMD_DC_DCE
HWSS_DCE112 = dce112_hwseq.o
AMD_DAL_HWSS_DCE112 = $(addprefix $(AMDDALPATH)/dc/hwss/dce112/,$(HWSS_DCE112))
@ -81,6 +86,7 @@ HWSS_DCE120 = dce120_hwseq.o
AMD_DAL_HWSS_DCE120 = $(addprefix $(AMDDALPATH)/dc/hwss/dce120/,$(HWSS_DCE120))
AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCE120)
endif
ifdef CONFIG_DRM_AMD_DC_FP
###############################################################################

View File

@ -3617,6 +3617,7 @@ void dce110_disable_link_output(struct dc_link *link,
dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
}
#if defined(CONFIG_DRM_AMD_DC_DCE)
static const struct hw_sequencer_funcs dce110_funcs = {
.program_gamut_remap = program_gamut_remap,
.program_output_csc = program_output_csc,
@ -3685,4 +3686,5 @@ void dce110_hw_sequencer_construct(struct dc *dc)
dc->hwss = dce110_funcs;
dc->hwseq->funcs = dce110_private_funcs;
}
#endif /* CONFIG_DRM_AMD_DC_DCE */

View File

@ -41,6 +41,7 @@ AMD_DAL_IRQ_DCE60 = $(addprefix $(AMDDALPATH)/dc/irq/dce60/,$(IRQ_DCE60))
AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE60)
endif
ifdef CONFIG_DRM_AMD_DC_DCE
###############################################################################
# DCE 8x
###############################################################################
@ -67,6 +68,7 @@ IRQ_DCE12 = irq_service_dce120.o
AMD_DAL_IRQ_DCE12 = $(addprefix $(AMDDALPATH)/dc/irq/dce120/,$(IRQ_DCE12))
AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12)
endif # CONFIG_DRM_AMD_DC_DCE
###############################################################################
# DCN 1x

View File

@ -179,27 +179,6 @@ static struct irq_source_info_funcs vupdate_irq_info_funcs = {
#define dc_underflow_int_entry(reg_num) \
[DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
bool dal_irq_service_dummy_set(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
{
(void)enable;
DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
__func__, info->src_id, info->ext_id);
return false;
}
bool dal_irq_service_dummy_ack(struct irq_service *irq_service,
const struct irq_source_info *info)
{
DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
__func__, info->src_id, info->ext_id);
return false;
}
bool dce110_vblank_set(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)

View File

@ -36,15 +36,6 @@ enum dc_irq_source to_dal_irq_source_dce110(
uint32_t src_id,
uint32_t ext_id);
bool dal_irq_service_dummy_set(
struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable);
bool dal_irq_service_dummy_ack(
struct irq_service *irq_service,
const struct irq_source_info *info);
bool dce110_vblank_set(
struct irq_service *irq_service,
const struct irq_source_info *info,

View File

@ -28,14 +28,18 @@
#include "include/irq_service_interface.h"
#include "include/logger_interface.h"
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce110/irq_service_dce110.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/irq_service_dce60.h"
#endif
#if defined(CONFIG_DRM_AMD_DC_DCE)
#include "dce80/irq_service_dce80.h"
#include "dce120/irq_service_dce120.h"
#endif
#include "dcn10/irq_service_dcn10.h"
#include "reg_helper.h"
@ -105,6 +109,30 @@ void dal_irq_service_set_generic(
dm_write_reg(irq_service->ctx, addr, value);
}
/*
* Base "non-implemented source" irq handlers referenced by irq_service.c and
* every DCN irq vtable.
*/
bool dal_irq_service_dummy_set(struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable)
{
(void)enable;
DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
__func__, info->src_id, info->ext_id);
return false;
}
bool dal_irq_service_dummy_ack(struct irq_service *irq_service,
const struct irq_source_info *info)
{
DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
__func__, info->src_id, info->ext_id);
return false;
}
bool dal_irq_service_set(
struct irq_service *irq_service,
enum dc_irq_source source,

View File

@ -90,4 +90,13 @@ bool hpd1_ack(
struct irq_service *irq_service,
const struct irq_source_info *info);
bool dal_irq_service_dummy_set(
struct irq_service *irq_service,
const struct irq_source_info *info,
bool enable);
bool dal_irq_service_dummy_ack(
struct irq_service *irq_service,
const struct irq_source_info *info);
#endif

View File

@ -37,6 +37,8 @@ endif
###############################################################################
ifdef CONFIG_DRM_AMD_DC_DCE
RESOURCE_DCE80 = dce80_resource.o
AMD_DAL_RESOURCE_DCE80 = $(addprefix $(AMDDALPATH)/dc/resource/dce80/,$(RESOURCE_DCE80))
@ -75,6 +77,8 @@ AMD_DAL_RESOURCE_DCE120 = $(addprefix $(AMDDALPATH)/dc/resource/dce120/,$(RESOUR
AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE120)
endif # CONFIG_DRM_AMD_DC_DCE
ifdef CONFIG_DRM_AMD_DC_FP
###############################################################################
# DCN

View File

@ -848,30 +848,6 @@ static void dce112_resource_destruct(struct dce110_resource_pool *pool)
}
}
static struct clock_source *find_matching_pll(
struct resource_context *res_ctx,
const struct resource_pool *pool,
const struct dc_stream_state *const stream)
{
(void)res_ctx;
switch (stream->link->link_enc->transmitter) {
case TRANSMITTER_UNIPHY_A:
return pool->clock_sources[DCE112_CLK_SRC_PLL0];
case TRANSMITTER_UNIPHY_B:
return pool->clock_sources[DCE112_CLK_SRC_PLL1];
case TRANSMITTER_UNIPHY_C:
return pool->clock_sources[DCE112_CLK_SRC_PLL2];
case TRANSMITTER_UNIPHY_D:
return pool->clock_sources[DCE112_CLK_SRC_PLL3];
case TRANSMITTER_UNIPHY_E:
return pool->clock_sources[DCE112_CLK_SRC_PLL4];
case TRANSMITTER_UNIPHY_F:
return pool->clock_sources[DCE112_CLK_SRC_PLL5];
default:
return NULL;
}
}
static enum dc_status build_mapped_resource(
const struct dc *dc,
struct dc_state *context,
@ -963,44 +939,6 @@ enum dc_status dce112_validate_bandwidth(
return result ? DC_OK : DC_FAIL_BANDWIDTH_VALIDATE;
}
enum dc_status resource_map_phy_clock_resources(
const struct dc *dc,
struct dc_state *context,
struct dc_stream_state *stream)
{
/* acquire new resources */
struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
&context->res_ctx, stream);
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
if (dc_is_dp_signal(pipe_ctx->stream->signal)
|| dc_is_virtual_signal(pipe_ctx->stream->signal))
pipe_ctx->clock_source =
dc->res_pool->dp_clock_source;
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL)
pipe_ctx->clock_source =
dc->res_pool->dp_clock_source;
else {
if (stream && stream->link && stream->link->link_enc)
pipe_ctx->clock_source = find_matching_pll(
&context->res_ctx, dc->res_pool,
stream);
}
if (pipe_ctx->clock_source == NULL)
return DC_NO_CLOCK_SOURCE_RESOURCE;
resource_reference_clock_source(
&context->res_ctx,
dc->res_pool,
pipe_ctx->clock_source);
return DC_OK;
}
static bool dce112_validate_surface_sets(
struct dc_state *context)
{