]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Update get_pixel_clk_frequency() for DCN4x DCCG DP DTO
authorOvidiu Bunea <ovidiu.bunea@amd.com>
Fri, 1 May 2026 23:38:13 +0000 (19:38 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jun 2026 17:31:08 +0000 (13:31 -0400)
[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>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/clock_source.h

index 6d520d5b02e979aab7d0dcb175c7ad614a72b396..06864b8683f0685421047f32e3382a3d1f54366c 100644 (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);
 
index ac9eed58c41570061300214bae04e79781b26264..09910333bd71071b05a3e85c2c5349427f9342c5 100644 (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
 };
 
 
index 94128f7a18b18a69fd6e227ef0701d86721faa36..9441aa6a897f772238095494c2361df835d6b3ea 100644 (file)
        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
index 1733f551248e441842905c8dca7c5499ee2d2010..7f58930fc87e62e8a9a54da3d47730eedbaf06fb 100644 (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 =
index ed2f8005d85e325ae2de84a29052856f8d25e024..6bbbb8ea7dadfc996b62ac647da71a848503d342 100644 (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,