drm/amd/display: Keep VBios pixel rate div setting until next mode set
authoryi-lchen <yi-lchen@amd.com>
Mon, 29 Apr 2024 06:28:36 +0000 (14:28 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 5 Jun 2024 15:04:50 +0000 (11:04 -0400)
[why]
Vbios & Driver have difference pixel rate div policy.
When enabling fast boot & performing blank & unblank w/o timing setting,
pixel clock & pixel rate dividor are not match.
It would cause too high pixel reate and eDP would be black screen.

[How]
We would keep pixel rate div setting by Vbios until next timing setting.

Reviewed-by: Jun Lei <jun.lei@amd.com>
Acked-by: Zaeem Mohamed <zaeem.mohamed@amd.com>
Signed-off-by: yi-lchen <yi-lchen@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
20 files changed:
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dccg/dcn314/dcn314_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn32/dcn32_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn35/dcn35_dccg.c
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_stream_encoder.c
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h

index beca40f8694f913221f87c91230667e60c80e465..dc236264d9b33ce26bbaa69b25f16d5841f91dc2 100644 (file)
@@ -3969,6 +3969,12 @@ enum dc_status dc_validate_with_context(struct dc *dc,
 
        res = dc_validate_global_state(dc, context, fast_validate);
 
+       /* calculate pixel rate divider after deciding pxiel clock & odm combine  */
+       if ((dc->hwss.calculate_pix_rate_divider) && (res == DC_OK)) {
+               for (i = 0; i < add_streams_count; i++)
+                       dc->hwss.calculate_pix_rate_divider(dc, context, add_streams[i]);
+       }
+
 fail:
        if (res != DC_OK)
                DC_LOG_WARNING("%s:resource validation failed, dc_status:%d\n",
index 17a1174b8d80203eaf8b1dce224847ce051cedd9..8f6edd8e9bebb3a0631a3da4bdf27fed5819ce2b 100644 (file)
@@ -58,8 +58,8 @@ static void dccg314_trigger_dio_fifo_resync(
 static void dccg314_get_pixel_rate_div(
                struct dccg *dccg,
                uint32_t otg_inst,
-               enum pixel_rate_div *k1,
-               enum pixel_rate_div *k2)
+               uint32_t *k1,
+               uint32_t *k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
        uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;
@@ -93,8 +93,8 @@ static void dccg314_get_pixel_rate_div(
                return;
        }
 
-       *k1 = (enum pixel_rate_div)val_k1;
-       *k2 = (enum pixel_rate_div)val_k2;
+       *k1 = val_k1;
+       *k2 = val_k2;
 }
 
 static void dccg314_set_pixel_rate_div(
@@ -104,7 +104,8 @@ static void dccg314_set_pixel_rate_div(
                enum pixel_rate_div k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k1 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k2 = PIXEL_RATE_DIV_NA;
 
        // Don't program 0xF into the register field. Not valid since
        // K1 / K2 field is only 1 / 2 bits wide
@@ -373,6 +374,7 @@ static const struct dccg_funcs dccg314_funcs = {
        .disable_dsc = dccg31_disable_dscclk,
        .enable_dsc = dccg31_enable_dscclk,
        .set_pixel_rate_div = dccg314_set_pixel_rate_div,
+       .get_pixel_rate_div = dccg314_get_pixel_rate_div,
        .trigger_dio_fifo_resync = dccg314_trigger_dio_fifo_resync,
        .set_valid_pixel_rate = dccg314_set_valid_pixel_rate,
        .set_dtbclk_p_src = dccg314_set_dtbclk_p_src
index 56385cede113ed918104519e392ef1d6f3c5f962..21a6ca5ca19276d1d189d8b8da96cb63e603fae5 100644 (file)
@@ -58,8 +58,8 @@ static void dccg32_trigger_dio_fifo_resync(
 static void dccg32_get_pixel_rate_div(
                struct dccg *dccg,
                uint32_t otg_inst,
-               enum pixel_rate_div *k1,
-               enum pixel_rate_div *k2)
+               uint32_t *k1,
+               uint32_t *k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
        uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;
@@ -93,8 +93,8 @@ static void dccg32_get_pixel_rate_div(
                return;
        }
 
-       *k1 = (enum pixel_rate_div)val_k1;
-       *k2 = (enum pixel_rate_div)val_k2;
+       *k1 = val_k1;
+       *k2 = val_k2;
 }
 
 static void dccg32_set_pixel_rate_div(
@@ -104,7 +104,8 @@ static void dccg32_set_pixel_rate_div(
                enum pixel_rate_div k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k1 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k2 = PIXEL_RATE_DIV_NA;
 
        // Don't program 0xF into the register field. Not valid since
        // K1 / K2 field is only 1 / 2 bits wide
@@ -343,6 +344,7 @@ static const struct dccg_funcs dccg32_funcs = {
        .otg_add_pixel = dccg32_otg_add_pixel,
        .otg_drop_pixel = dccg32_otg_drop_pixel,
        .set_pixel_rate_div = dccg32_set_pixel_rate_div,
+       .get_pixel_rate_div = dccg32_get_pixel_rate_div,
        .trigger_dio_fifo_resync = dccg32_trigger_dio_fifo_resync,
        .set_dtbclk_p_src = dccg32_set_dtbclk_p_src,
 };
index 1fc3aa2b507b2fa85a1523a6d5a8648294debf7c..68cd3258f4a97a9175aafa7fe22f2cc2618f858e 100644 (file)
@@ -146,8 +146,8 @@ static void dccg35_set_dppclk_root_clock_gating(struct dccg *dccg,
 static void dccg35_get_pixel_rate_div(
                struct dccg *dccg,
                uint32_t otg_inst,
-               enum pixel_rate_div *k1,
-               enum pixel_rate_div *k2)
+               uint32_t *k1,
+               uint32_t *k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
        uint32_t val_k1 = PIXEL_RATE_DIV_NA, val_k2 = PIXEL_RATE_DIV_NA;
@@ -181,8 +181,8 @@ static void dccg35_get_pixel_rate_div(
                return;
        }
 
-       *k1 = (enum pixel_rate_div)val_k1;
-       *k2 = (enum pixel_rate_div)val_k2;
+       *k1 = val_k1;
+       *k2 = val_k2;
 }
 
 static void dccg35_set_pixel_rate_div(
@@ -192,7 +192,9 @@ static void dccg35_set_pixel_rate_div(
                enum pixel_rate_div k2)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       enum pixel_rate_div cur_k1 = PIXEL_RATE_DIV_NA, cur_k2 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k1 = PIXEL_RATE_DIV_NA;
+       uint32_t cur_k2 = PIXEL_RATE_DIV_NA;
+
 
        // Don't program 0xF into the register field. Not valid since
        // K1 / K2 field is only 1 / 2 bits wide
@@ -1018,6 +1020,7 @@ static const struct dccg_funcs dccg35_funcs = {
        .disable_dsc = dccg35_disable_dscclk,
        .enable_dsc = dccg35_enable_dscclk,
        .set_pixel_rate_div = dccg35_set_pixel_rate_div,
+       .get_pixel_rate_div = dccg35_get_pixel_rate_div,
        .trigger_dio_fifo_resync = dccg35_trigger_dio_fifo_resync,
        .set_valid_pixel_rate = dccg35_set_valid_pixel_rate,
        .enable_symclk_se = dccg35_enable_symclk_se,
index a496a250f8924808185511d018f3bd47c259d7a1..3538e190f2175320c957fb9f92b8b0794f276cad 100644 (file)
@@ -119,7 +119,7 @@ static void dccg401_wait_for_dentist_change_done(
 static void dccg401_get_pixel_rate_div(
                struct dccg *dccg,
                uint32_t otg_inst,
-               enum pixel_rate_div *tmds_div,
+               uint32_t *tmds_div,
                uint32_t *dp_dto_int)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
@@ -161,7 +161,7 @@ static void dccg401_set_pixel_rate_div(
                enum pixel_rate_div unused)
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       enum pixel_rate_div cur_tmds_div = PIXEL_RATE_DIV_NA;
+       uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
        uint32_t dp_dto_int;
        uint32_t reg_val;
 
@@ -962,6 +962,7 @@ static const struct dccg_funcs dccg401_funcs = {
        .otg_add_pixel = dccg401_otg_add_pixel,
        .otg_drop_pixel = dccg401_otg_drop_pixel,
        .set_pixel_rate_div = dccg401_set_pixel_rate_div,
+       .get_pixel_rate_div = dccg401_get_pixel_rate_div,
        .set_dp_dto = dccg401_set_dp_dto,
        .enable_symclk_se = dccg401_enable_symclk_se,
        .disable_symclk_se = dccg401_disable_symclk_se,
index 2fef1419ae91743cbfd2903df5f64d85751758fb..1a9bb614c41e03b60cffde9c0f542c4f9c912f26 100644 (file)
 
 static void enc32_dp_set_odm_combine(
        struct stream_encoder *enc,
-       bool odm_combine)
+       bool two_pixel_per_cyle)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
 
-       REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_PER_CYCLE_PROCESSING_MODE, odm_combine ? 1 : 0);
+       REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_PER_CYCLE_PROCESSING_MODE, two_pixel_per_cyle ? 1 : 0);
 }
 
 /* setup stream encoder in dvi mode */
@@ -241,46 +241,12 @@ static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
        return two_pix;
 }
 
-static bool is_h_timing_divisible_by_2(const struct dc_crtc_timing *timing)
-{
-       /* math borrowed from function of same name in inc/resource
-        * checks if h_timing is divisible by 2
-        */
-
-       bool divisible = false;
-       uint16_t h_blank_start = 0;
-       uint16_t h_blank_end = 0;
-
-       if (timing) {
-               h_blank_start = timing->h_total - timing->h_front_porch;
-               h_blank_end = h_blank_start - timing->h_addressable;
-
-               /* HTOTAL, Hblank start/end, and Hsync start/end all must be
-                * divisible by 2 in order for the horizontal timing params
-                * to be considered divisible by 2. Hsync start is always 0.
-                */
-               divisible = (timing->h_total % 2 == 0) &&
-                               (h_blank_start % 2 == 0) &&
-                               (h_blank_end % 2 == 0) &&
-                               (timing->h_sync_width % 2 == 0);
-       }
-       return divisible;
-}
-
-static bool is_dp_dig_pixel_rate_div_policy(struct dc *dc, const struct dc_crtc_timing *timing)
-{
-       /* should be functionally the same as dcn32_is_dp_dig_pixel_rate_div_policy for DP encoders*/
-       return is_h_timing_divisible_by_2(timing) &&
-               dc->debug.enable_dp_dig_pixel_rate_div_policy;
-}
-
 void enc32_stream_encoder_dp_unblank(
        struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-       struct dc *dc = enc->ctx->dc;
 
        if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
                uint32_t n_vid = 0x8000;
@@ -291,7 +257,7 @@ void enc32_stream_encoder_dp_unblank(
 
                /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
                if (is_two_pixels_per_containter(&param->timing) || param->opp_cnt > 1
-                       || is_dp_dig_pixel_rate_div_policy(dc, &param->timing)) {
+                       || param->pix_per_cycle > 1) {
                        /*this logic should be the same in get_pixel_clock_parameters() */
                        n_multiply = 1;
                        pix_per_cycle = 1;
index 62a8f0b56006201d6b8db01a0641d5a355887cbb..2595cbef59423cd0a8f8a2fc31596da7badce4eb 100644 (file)
@@ -273,46 +273,12 @@ static bool is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
        return two_pix;
 }
 
-static bool is_h_timing_divisible_by_2(const struct dc_crtc_timing *timing)
-{
-       /* math borrowed from function of same name in inc/resource
-        * checks if h_timing is divisible by 2
-        */
-
-       bool divisible = false;
-       uint16_t h_blank_start = 0;
-       uint16_t h_blank_end = 0;
-
-       if (timing) {
-               h_blank_start = timing->h_total - timing->h_front_porch;
-               h_blank_end = h_blank_start - timing->h_addressable;
-
-               /* HTOTAL, Hblank start/end, and Hsync start/end all must be
-                * divisible by 2 in order for the horizontal timing params
-                * to be considered divisible by 2. Hsync start is always 0.
-                */
-               divisible = (timing->h_total % 2 == 0) &&
-                               (h_blank_start % 2 == 0) &&
-                               (h_blank_end % 2 == 0) &&
-                               (timing->h_sync_width % 2 == 0);
-       }
-       return divisible;
-}
-
-static bool is_dp_dig_pixel_rate_div_policy(struct dc *dc, const struct dc_crtc_timing *timing)
-{
-       /* should be functionally the same as dcn32_is_dp_dig_pixel_rate_div_policy for DP encoders*/
-       return is_h_timing_divisible_by_2(timing) &&
-               dc->debug.enable_dp_dig_pixel_rate_div_policy;
-}
-
 static void enc35_stream_encoder_dp_unblank(
                struct dc_link *link,
                struct stream_encoder *enc,
                const struct encoder_unblank_param *param)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
-       struct dc *dc = enc->ctx->dc;
 
        if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
                uint32_t n_vid = 0x8000;
@@ -323,7 +289,7 @@ static void enc35_stream_encoder_dp_unblank(
 
                /* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
                if (is_two_pixels_per_containter(&param->timing) || param->opp_cnt > 1
-                       || is_dp_dig_pixel_rate_div_policy(dc, &param->timing)) {
+                       || param->pix_per_cycle > 1) {
                        /*this logic should be the same in get_pixel_clock_parameters() */
                        n_multiply = 1;
                        pix_per_cycle = 1;
index da6507f5f20219eb8351a504758d486aacdd212e..f489371a3bc6b0d25f53a5f81be537a2a3ba34ac 100644 (file)
@@ -1779,6 +1779,7 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
        struct dc_stream_state *edp_streams[MAX_NUM_EDP];
        struct dc_link *edp_link_with_sink = NULL;
        struct dc_link *edp_link = NULL;
+       struct pipe_ctx *pipe_ctx = NULL;
        struct dce_hwseq *hws = dc->hwseq;
        int edp_with_sink_num;
        int edp_num;
@@ -1815,9 +1816,26 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
                                can_apply_edp_fast_boot = dc_validate_boot_timing(dc,
                                        edp_stream->sink, &edp_stream->timing);
                                edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot;
-                               if (can_apply_edp_fast_boot)
-                                       DC_LOG_EVENT_LINK_TRAINING("eDP fast boot disabled to optimize link rate\n");
-
+                               if (can_apply_edp_fast_boot) {
+                                       DC_LOG_EVENT_LINK_TRAINING("eDP fast boot Enable\n");
+
+                                       // Vbios & Driver support different pixel rate div policy.
+                                       pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, edp_stream);
+                                       if (pipe_ctx &&
+                                               hws->funcs.is_dp_dig_pixel_rate_div_policy &&
+                                               hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)) {
+                                               // Get Vbios div factor from register
+                                               dc->res_pool->dccg->funcs->get_pixel_rate_div(
+                                                       dc->res_pool->dccg,
+                                                       pipe_ctx->stream_res.tg->inst,
+                                                       &pipe_ctx->pixel_rate_divider.div_factor1,
+                                                       &pipe_ctx->pixel_rate_divider.div_factor2);
+
+                                               // VBios doesn't support pixel rate div, so force it.
+                                               // If VBios supports it, we check it from reigster or other flags.
+                                               pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle = 1;
+                                       }
+                               }
                                break;
                        }
                }
index 42c3c440ed8908a4e0e076c64968a83536e38eb4..0d58c9d439c6f57102e267d9981e4e6884689f7d 100644 (file)
@@ -829,20 +829,17 @@ enum dc_status dcn20_enable_stream_timing(
        bool is_two_pixels_per_container =
                        pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
        bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container);
-       unsigned int k1_div = PIXEL_RATE_DIV_NA;
-       unsigned int k2_div = PIXEL_RATE_DIV_NA;
        int odm_slice_width;
        int last_odm_slice_width;
        struct pipe_ctx *opp_heads[MAX_PIPES];
 
-       if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
-               hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
-
+       if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
                dc->res_pool->dccg->funcs->set_pixel_rate_div(
                        dc->res_pool->dccg,
                        pipe_ctx->stream_res.tg->inst,
-                       k1_div, k2_div);
-       }
+                       pipe_ctx->pixel_rate_divider.div_factor1,
+                       pipe_ctx->pixel_rate_divider.div_factor2);
+
        /* by upper caller loop, pipe0 is parent pipe and be called first.
         * back end is set up by for pipe0. Other children pipe share back end
         * with pipe 0. No program is needed.
@@ -2685,6 +2682,7 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
                        pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
 
        params.opp_cnt = 1;
+
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                params.opp_cnt++;
        }
@@ -2940,9 +2938,7 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
        struct dccg *dccg = dc->res_pool->dccg;
        enum phyd32clk_clock_source phyd32clk;
        int dp_hpo_inst;
-       struct dce_hwseq *hws = dc->hwseq;
-       unsigned int k1_div = PIXEL_RATE_DIV_NA;
-       unsigned int k2_div = PIXEL_RATE_DIV_NA;
+
        struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
        struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc;
 
@@ -2963,14 +2959,13 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
                        dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
                                                      link_enc->transmitter - TRANSMITTER_UNIPHY_A);
        }
-       if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
-               hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
 
+       if (dc->res_pool->dccg->funcs->set_pixel_rate_div)
                dc->res_pool->dccg->funcs->set_pixel_rate_div(
                        dc->res_pool->dccg,
                        pipe_ctx->stream_res.tg->inst,
-                       k1_div, k2_div);
-       }
+                       pipe_ctx->pixel_rate_divider.div_factor1,
+                       pipe_ctx->pixel_rate_divider.div_factor2);
 
        link_hwss->setup_stream_encoder(pipe_ctx);
 
index 1d853241ca32292b17352106ec3602c59ef200e8..8e68e05e3b72fbd6f2d72bc758ea6144717f449d 100644 (file)
@@ -334,6 +334,27 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
        return odm_combine_factor;
 }
 
+void dcn314_calculate_pix_rate_divider(
+               struct dc *dc,
+               struct dc_state *context,
+               const struct dc_stream_state *stream)
+{
+       struct dce_hwseq *hws = dc->hwseq;
+       struct pipe_ctx *pipe_ctx = NULL;
+       unsigned int k1_div = PIXEL_RATE_DIV_NA;
+       unsigned int k2_div = PIXEL_RATE_DIV_NA;
+
+       pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
+
+       if (pipe_ctx) {
+               if (hws->funcs.calculate_dccg_k1_k2_values)
+                       hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
+
+               pipe_ctx->pixel_rate_divider.div_factor1 = k1_div;
+               pipe_ctx->pixel_rate_divider.div_factor2 = k2_div;
+       }
+}
+
 void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context)
 {
        unsigned int i;
index f4613d96e0139ba5368e9be89e7d0a505b0c75fd..fb4f90f61b22d633bb0779c5469310f459b0303c 100644 (file)
@@ -39,6 +39,8 @@ void dcn314_enable_power_gating_plane(struct dce_hwseq *hws, bool enable);
 
 unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsigned int *k1_div, unsigned int *k2_div);
 
+void dcn314_calculate_pix_rate_divider(struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream);
+
 void dcn314_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context);
 
 void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on);
index 9c46b6a7b4dca81fe48885b8c14ed8bf3a2315b6..7a8db4b81471e9be85e94f7e21caade0b1629ff3 100644 (file)
@@ -114,6 +114,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
        .optimize_pwr_state = dcn21_optimize_pwr_state,
        .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state,
        .update_visual_confirm_color = dcn10_update_visual_confirm_color,
+       .calculate_pix_rate_divider = dcn314_calculate_pix_rate_divider,
 };
 
 static const struct hwseq_private_funcs dcn314_private_funcs = {
index 7aaef3709baa7f5719ee3fa4d68fd51d07fc08e4..7330f9d796008b51dc5fb1785b6508659c5402c5 100644 (file)
@@ -1164,6 +1164,28 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
        return odm_combine_factor;
 }
 
+void dcn32_calculate_pix_rate_divider(
+               struct dc *dc,
+               struct dc_state *context,
+               const struct dc_stream_state *stream)
+{
+       struct dce_hwseq *hws = dc->hwseq;
+       struct pipe_ctx *pipe_ctx = NULL;
+       unsigned int k1_div = PIXEL_RATE_DIV_NA;
+       unsigned int k2_div = PIXEL_RATE_DIV_NA;
+
+       pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
+
+       if (pipe_ctx) {
+
+               if (hws->funcs.calculate_dccg_k1_k2_values)
+                       hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
+
+               pipe_ctx->pixel_rate_divider.div_factor1 = k1_div;
+               pipe_ctx->pixel_rate_divider.div_factor2 = k2_div;
+       }
+}
+
 void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_state *context)
 {
        unsigned int i;
@@ -1202,9 +1224,10 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
        struct dc_link *link = stream->link;
        struct dce_hwseq *hws = link->dc->hwseq;
        struct pipe_ctx *odm_pipe;
-       uint32_t pix_per_cycle = 1;
 
        params.opp_cnt = 1;
+       params.pix_per_cycle = pipe_ctx->stream_res.pix_clk_params.dio_se_pix_per_cycle;
+
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
                params.opp_cnt++;
 
@@ -1219,13 +1242,13 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
                                pipe_ctx->stream_res.hpo_dp_stream_enc,
                                pipe_ctx->stream_res.tg->inst);
        } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
-               if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) || params.opp_cnt > 1
-                       || dcn32_is_dp_dig_pixel_rate_div_policy(pipe_ctx)) {
+               if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) ||
+                       params.opp_cnt > 1) {
                        params.timing.pix_clk_100hz /= 2;
-                       pix_per_cycle = 2;
+                       params.pix_per_cycle = 2;
                }
                pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
-                               pipe_ctx->stream_res.stream_enc, pix_per_cycle > 1);
+                               pipe_ctx->stream_res.stream_enc, params.pix_per_cycle > 1);
                pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
        }
 
index 4621163b4b986cc82e3b3719eb69fa3ec8a3079f..db562e45d6ffeb935fb66c31b16c7087d27c8db0 100644 (file)
@@ -91,6 +91,8 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
 
 bool dcn32_is_dp_dig_pixel_rate_div_policy(struct pipe_ctx *pipe_ctx);
 
+void dcn32_calculate_pix_rate_divider(struct dc *dc, struct dc_state *context, const struct dc_stream_state *stream);
+
 void dcn32_disable_link_output(struct dc_link *link,
                const struct link_resource *link_res,
                enum signal_type signal);
index 10d2ae99c11842f7071bbb9bbafe8e6fc173da8e..5c50458b12cb1f8b43ffd1e7dbf41b0a5a235ffc 100644 (file)
@@ -119,6 +119,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom,
        .blank_phantom = dcn32_blank_phantom,
        .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless,
+       .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider,
 };
 
 static const struct hwseq_private_funcs dcn32_private_funcs = {
index 663bacd1fafdb7eb67de3822bedb059e7563a422..30e6a639883910ac4e5360104eb4b404cb0d4d0c 100644 (file)
@@ -123,6 +123,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
        .hw_block_power_down = dcn35_hw_block_power_down,
        .root_clock_control = dcn35_root_clock_control,
        .set_long_vtotal = dcn35_set_long_vblank,
+       .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider,
 };
 
 static const struct hwseq_private_funcs dcn35_private_funcs = {
index d8de1c6a84e8d824ae3d1f02f33d9d344bc68351..55e791552bca868351a33e28cc7162a7ec86ad4d 100644 (file)
@@ -122,6 +122,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
        .hw_block_power_down = dcn351_hw_block_power_down,
        .root_clock_control = dcn35_root_clock_control,
        .set_long_vtotal = dcn35_set_long_vblank,
+       .calculate_pix_rate_divider = dcn32_calculate_pix_rate_divider,
 };
 
 static const struct hwseq_private_funcs dcn351_private_funcs = {
index a9f2b7ee9dd82b17b98906c076c79fbb5e47f24a..e9b85884edcee2b173254943a9965abf226cc192 100644 (file)
@@ -339,6 +339,9 @@ struct hw_sequencer_funcs {
                        struct dc_state *context);
        void (*exit_optimized_pwr_state)(const struct dc *dc,
                        struct dc_state *context);
+       void (*calculate_pix_rate_divider)(struct dc *dc,
+                       struct dc_state *context,
+                       const struct dc_stream_state *stream);
 
        /* Audio Related */
        void (*enable_audio_stream)(struct pipe_ctx *pipe_ctx);
index 286f3219b77e124c22bc42340356417a62926f88..f58c27ad8b3e352bb47be5a397e206d8c66b3616 100644 (file)
@@ -399,6 +399,11 @@ union pipe_update_flags {
        uint32_t raw;
 };
 
+struct pixel_rate_divider {
+       uint32_t div_factor1;
+       uint32_t div_factor2;
+};
+
 enum p_state_switch_method {
        P_STATE_UNKNOWN                                         = 0,
        P_STATE_V_BLANK                                         = 1,
@@ -464,6 +469,7 @@ struct pipe_ctx {
        bool has_vactive_margin;
        /* subvp_index: only valid if the pipe is a SUBVP_MAIN*/
        uint8_t subvp_index;
+       struct pixel_rate_divider pixel_rate_divider;
 };
 
 /* Data used for dynamic link encoder assignment.
index 867bc67aabfa16f2d5cacec87a46ec01487403fe..4fb1aacee894be9677f16f37f4b2d4b0397fa510 100644 (file)
@@ -176,6 +176,11 @@ struct dccg_funcs {
                        enum pixel_rate_div k1,
                        enum pixel_rate_div k2);
 
+       void (*get_pixel_rate_div)(struct dccg *dccg,
+                       uint32_t otg_inst,
+                       uint32_t *div_factor1,
+                       uint32_t *div_factor2);
+
        void (*set_valid_pixel_rate)(
                        struct dccg *dccg,
                        int ref_dtbclk_khz,