drm/amd/display: Update get_pixel_clk_frequency() for DCN4x DCCG DP DTO

[Why & How]
DCN4x ASICs have different DCCG logic for programming DP DTO. The current
get_pixel_clk_frequency_100hz() function does not account for this.

Rename the function to "get_dp_dto_frequency" to more accurately
reflect its intended behaviour. Create a new function that correctly
calculates the target pixel rate for DCN4.x DCCG design and use it.

Reviewed-by: Leo Chen <leo.chen@amd.com>
Signed-off-by: Ovidiu Bunea <ovidiu.bunea@amd.com>
Signed-off-by: Ray Wu <ray.wu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Ovidiu Bunea
2026-05-01 19:38:13 -04:00
committed by Alex Deucher
parent 470d1ae31d
commit 6f6483dbfa
5 changed files with 83 additions and 21 deletions

View File

@@ -1487,7 +1487,7 @@ static void disable_vbios_mode_if_required(
}
}
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source->funcs->get_dp_dto_frequency_100hz(
dc->res_pool->dp_clock_source,
tg_inst, &pix_clk_100hz);
@@ -2004,7 +2004,7 @@ bool dc_validate_boot_timing(const struct dc *dc,
uint32_t numOdmPipes = 1;
uint32_t id_src[4] = {0};
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source->funcs->get_dp_dto_frequency_100hz(
dc->res_pool->dp_clock_source,
tg_inst, &pix_clk_100hz);

View File

@@ -1188,15 +1188,16 @@ static bool dce110_clock_source_power_down(
return bp_result == BP_RESULT_OK;
}
static bool get_pixel_clk_frequency_100hz(
static bool get_dp_dto_frequency_100hz(
const struct clock_source *clock_source,
unsigned int inst,
unsigned int *pixel_clk_khz)
unsigned int *pixel_clk_100hz)
{
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
unsigned int clock_hz = 0;
unsigned int modulo_hz = 0;
unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
unsigned long long temp = 0;
if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
clock_hz = REG_READ(PHASE[inst]);
@@ -1207,17 +1208,18 @@ static bool get_pixel_clk_frequency_100hz(
* not be programmed equal to DPREFCLK
*/
modulo_hz = REG_READ(MODULO[inst]);
if (modulo_hz)
*pixel_clk_khz = (unsigned int)div_u64((uint64_t)clock_hz *
dp_dto_ref_khz * 10, modulo_hz);
else
*pixel_clk_khz = 0;
if (modulo_hz) {
temp = div_u64((uint64_t)clock_hz * dp_dto_ref_khz * 10, modulo_hz);
ASSERT(temp / 100 <= 0xFFFFFFFFUL);
*pixel_clk_100hz = (unsigned int)(temp / 100);
} else
*pixel_clk_100hz = 0;
} else {
/* NOTE: There is agreement with VBIOS here that MODULO is
* programmed equal to DPREFCLK, in which case PHASE will be
* equivalent to pixel clock.
*/
*pixel_clk_khz = clock_hz / 100;
*pixel_clk_100hz = clock_hz / 100;
}
return true;
}
@@ -1225,6 +1227,61 @@ static bool get_pixel_clk_frequency_100hz(
return false;
}
static bool dcn401_get_dp_dto_frequency_100hz(const struct clock_source *clock_source, unsigned int inst,
unsigned int *pixel_clk_100hz)
{
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
unsigned int phase_hz = 0;
unsigned int modulo_hz = 0;
unsigned int dp_dto_integer = 0;
unsigned long long temp = 0;
if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) {
phase_hz = REG_READ(PHASE[inst]);
modulo_hz = REG_READ(MODULO[inst]);
switch (inst) {
case 0:
REG_GET(OTG_PIXEL_RATE_DIV, DPDTO0_INT, &dp_dto_integer);
break;
case 1:
REG_GET(OTG_PIXEL_RATE_DIV, DPDTO1_INT, &dp_dto_integer);
break;
case 2:
REG_GET(OTG_PIXEL_RATE_DIV, DPDTO2_INT, &dp_dto_integer);
break;
case 3:
REG_GET(OTG_PIXEL_RATE_DIV, DPDTO3_INT, &dp_dto_integer);
break;
default:
BREAK_TO_DEBUGGER();
break;
}
/* On DCN4x, the DCCG DPDTO is directly programmed with the required pixel clock as per the following formula:
* - DPDTO INTEGER = INT(4:4:4 pixel rate / DTBCLK_P rate)
* - DPDTO PHASE = 4:4:4 pixel rate DPDTO INTEGER * DTBCLK_P rate
* - DPDTO MODULO = DTBCLK_P rate
* - target pix_clk_hz = (DPDTO INTEGER * DPDTO MODULO + DPDTO PHASE)
*/
dp_dto_integer += 1; // integer=0 represents 1x multiplier, etc.
temp = (unsigned long long)dp_dto_integer * modulo_hz + phase_hz;
if (temp / 100 > 0xFFFFFFFFUL) {
/* pixel rate 100hz should never be this high, if it is, throw an assert and return 0 */
BREAK_TO_DEBUGGER();
*pixel_clk_100hz = 0;
} else {
*pixel_clk_100hz = (unsigned int)(temp / 100);
}
return true;
}
return false;
}
/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = {
// /1.001 rates
@@ -1318,7 +1375,7 @@ static const struct clock_source_funcs dcn20_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dcn20_program_pix_clk,
.get_pix_clk_dividers = dce112_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz,
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz,
.override_dp_pix_clk = dcn20_override_dp_pix_clk
};
@@ -1405,21 +1462,21 @@ static const struct clock_source_funcs dcn3_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dcn3_program_pix_clk,
.get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
};
static const struct clock_source_funcs dcn31_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dcn31_program_pix_clk,
.get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
};
static const struct clock_source_funcs dcn401_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dcn401_program_pix_clk,
.get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
.get_dp_dto_frequency_100hz = dcn401_get_dp_dto_frequency_100hz
};
/*****************************************/
@@ -1430,13 +1487,13 @@ static const struct clock_source_funcs dce112_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dce112_program_pix_clk,
.get_pix_clk_dividers = dce112_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
};
static const struct clock_source_funcs dce110_clk_src_funcs = {
.cs_power_down = dce110_clock_source_power_down,
.program_pix_clk = dce110_program_pix_clk,
.get_pix_clk_dividers = dce110_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
.get_dp_dto_frequency_100hz = get_dp_dto_frequency_100hz
};

View File

@@ -202,7 +202,11 @@
type PLL_REF_DIV; \
type DP_DTO0_PHASE; \
type DP_DTO0_MODULO; \
type DP_DTO0_ENABLE;
type DP_DTO0_ENABLE; \
type DPDTO0_INT; \
type DPDTO1_INT; \
type DPDTO2_INT; \
type DPDTO3_INT;
#define CS_REG_FIELD_LIST_DCN32(type) \
type PIPE0_DTO_SRC_SEL;
@@ -221,6 +225,7 @@ struct dce110_clk_src_regs {
uint32_t RESYNC_CNTL;
uint32_t PIXCLK_RESYNC_CNTL;
uint32_t PLL_CNTL;
uint32_t OTG_PIXEL_RATE_DIV;
/* below are for DTO.
* todo: should probably use different struct to not waste space

View File

@@ -2423,7 +2423,7 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
grouped_pipes[i]->stream_res.tg->funcs->get_hw_timing(
grouped_pipes[i]->stream_res.tg,
&hw_crtc_timing[i]);
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source->funcs->get_dp_dto_frequency_100hz(
dc->res_pool->dp_clock_source,
grouped_pipes[i]->stream_res.tg->inst,
&pclk);
@@ -2462,7 +2462,7 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
dc->res_pool->dp_clock_source,
grouped_pipes[i]->stream_res.tg->inst,
(unsigned int)phase[i], (unsigned int)modulo[i]);
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source->funcs->get_dp_dto_frequency_100hz(
dc->res_pool->dp_clock_source,
grouped_pipes[i]->stream_res.tg->inst, &pclk);
grouped_pipes[i]->stream->timing.pix_clk_100hz =

View File

@@ -170,10 +170,10 @@ struct clock_source_funcs {
struct clock_source *,
struct pixel_clk_params *,
struct pll_settings *);
bool (*get_pixel_clk_frequency_100hz)(
bool (*get_dp_dto_frequency_100hz)(
const struct clock_source *clock_source,
unsigned int inst,
unsigned int *pixel_clk_khz);
unsigned int *pixel_clk_100hz);
bool (*override_dp_pix_clk)(
struct clock_source *clock_source,
unsigned int inst,