summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOvidiu Bunea <ovidiu.bunea@amd.com>2026-05-01 19:38:13 -0400
committerAlex Deucher <alexander.deucher@amd.com>2026-06-03 13:31:08 -0400
commit6f6483dbfacd2269da68cb97db996c0f31f650f2 (patch)
tree50a42e0be28d5d64ec1642e606115b89b700e6a3
parent470d1ae31d29f90b8998c5c08ee0b267a05fe378 (diff)
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>
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c85
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/clock_source.h4
5 files changed, 83 insertions, 21 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 6d520d5b02e9..06864b8683f0 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -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);
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
index ac9eed58c415..09910333bd71 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -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
};
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
index 94128f7a18b1..9441aa6a897f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
@@ -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
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
index 1733f551248e..7f58930fc87e 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
@@ -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 =
diff --git a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
index ed2f8005d85e..6bbbb8ea7dad 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/clock_source.h
@@ -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,