]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Tie FRL programming together in HWSS
authorHarry Wentland <harry.wentland@amd.com>
Fri, 24 Apr 2026 16:27:02 +0000 (12:27 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 3 Jun 2026 17:44:37 +0000 (13:44 -0400)
This patch adds HW Sequencer support for FRL programming, which
ties the HW programming for the different blocks together for
FRL.

Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Fangzhi Zuo <Jerry.Zuo@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
22 files changed:
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c
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_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h
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/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c
drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_init.c
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h

index d81271b870bb2be954717acc319badacba173420..042602c50e350d9fc5051f7c6e074352431756fe 100644 (file)
@@ -1221,6 +1221,9 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
                        pipe_ctx->stream_res.stream_enc);
        }
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
+               pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->stop_hdmi_info_packets(
+                       pipe_ctx->stream_res.hpo_frl_stream_enc);
        if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
                                        pipe_ctx->stream_res.hpo_dp_stream_enc);
@@ -1245,6 +1248,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
                        }
                }
        } else if (dccg && dccg->funcs->disable_symclk_se) {
+               if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL)
                dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
                                               link_enc->transmitter - TRANSMITTER_UNIPHY_A);
        }
@@ -1316,6 +1320,18 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
                link->dc->link_srv->edp_receiver_ready_T9(link);
        }
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
+               pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_blank(pipe_ctx->stream_res.hpo_frl_stream_enc);
+
+               /* Set HDMISTREAMCLK source to REFCLK */
+               if (link->dc->res_pool->dccg &&
+                       link->dc->res_pool->dccg->funcs->set_hdmistreamclk) {
+                       link->dc->res_pool->dccg->funcs->set_hdmistreamclk(
+                                       link->dc->res_pool->dccg,
+                                       REFCLK,
+                                       pipe_ctx->stream_res.tg->inst);
+               }
+       }
 }
 
 
@@ -1505,9 +1521,32 @@ void build_audio_output(
 
                }
        }
+       if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+               switch (pipe_ctx->stream->link->frl_link_settings.frl_link_rate) {
+               case HDMI_FRL_LINK_RATE_3GBPS:
+                       audio_output->crtc_info.frl_character_clock_kHz = 166667;
+                       break;
+               case HDMI_FRL_LINK_RATE_6GBPS:
+               case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
+                       audio_output->crtc_info.frl_character_clock_kHz = 333333;
+                       break;
+               case HDMI_FRL_LINK_RATE_8GBPS:
+                       audio_output->crtc_info.frl_character_clock_kHz = 444444;
+                       break;
+               case HDMI_FRL_LINK_RATE_10GBPS:
+                       audio_output->crtc_info.frl_character_clock_kHz = 555555;
+                       break;
+               case HDMI_FRL_LINK_RATE_12GBPS:
+               default:
+                       audio_output->crtc_info.frl_character_clock_kHz = 666667;
+                       break;
+               }
+       } else
+                       audio_output->crtc_info.frl_character_clock_kHz = 0;
 
        if (state->clk_mgr &&
                (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT ||
+                       pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL ||
                        pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) {
                audio_output->pll_info.audio_dto_source_clock_in_khz =
                                state->clk_mgr->funcs->get_dp_ref_clk_frequency(
@@ -1732,7 +1771,8 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
                pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
                                pipe_ctx->stream_res.tg, event_triggers, 2);
 
-       if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
+       if (!dc_is_virtual_signal(pipe_ctx->stream->signal) &&
+               !dc_is_hdmi_frl_signal(pipe_ctx->stream->signal))
                pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
                        pipe_ctx->stream_res.stream_enc,
                        pipe_ctx->stream_res.tg->inst);
@@ -2486,7 +2526,8 @@ static void dce110_setup_audio_dto(
 
                if (pipe_ctx->top_pipe)
                        continue;
-               if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A)
+               if (pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_TYPE_A &&
+                       pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL)
                        continue;
                if (pipe_ctx->stream_res.audio != NULL) {
                        struct audio_output audio_output;
@@ -2495,15 +2536,27 @@ static void dce110_setup_audio_dto(
 
                        if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
                                struct dtbclk_dto_params dto_params = {0};
-
-                               dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
-                                       dc->res_pool->dccg, &dto_params);
-
-                               pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+                               dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+
+                               if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_FRL) {
+                                       /* For DCN3.1, audio to HPO FRL encoder is using audio DTBCLK DTO */
+                                       /* set audio DTBCLK DTO to 24MHz */
+                                       dto_params.req_audio_dtbclk_khz = 24000;
+                                       dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+                                               dc->res_pool->dccg,
+                                               &dto_params);
+                               } else {
+                                       /* Audio DTBCLK params default to disabled */
+                                       dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+                                               dc->res_pool->dccg,
+                                               &dto_params);
+
+                                       pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
                                                pipe_ctx->stream_res.audio,
                                                pipe_ctx->stream->signal,
                                                &audio_output.crtc_info,
                                                &audio_output.pll_info);
+                               }
                        } else
                                pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
                                        pipe_ctx->stream_res.audio,
@@ -2533,11 +2586,37 @@ static void dce110_setup_audio_dto(
 
                                build_audio_output(context, pipe_ctx, &audio_output);
 
-                               pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
-                                       pipe_ctx->stream_res.audio,
-                                       pipe_ctx->stream->signal,
-                                       &audio_output.crtc_info,
-                                       &audio_output.pll_info);
+                               /* Audio to HPO DP encoder is using audio DTBCLK DTO */
+                               if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
+                                       struct dtbclk_dto_params dto_params = {0};
+                                       dto_params.ref_dtbclk_khz =
+                                                       dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+
+                                       if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+                                               /* set audio DTBCLK DTO to 24MHz */
+                                               dto_params.req_audio_dtbclk_khz = 24000;
+                                               dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+                                                       dc->res_pool->dccg,
+                                                       &dto_params);
+                                       } else {
+                                               /* Audio DTBCLK params default to disabled */
+                                               dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
+                                                       dc->res_pool->dccg,
+                                                       &dto_params);
+
+                                               pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+                                                       pipe_ctx->stream_res.audio,
+                                                       pipe_ctx->stream->signal,
+                                                       &audio_output.crtc_info,
+                                                       &audio_output.pll_info);
+                                       }
+                               } else {
+                                       pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
+                                               pipe_ctx->stream_res.audio,
+                                               pipe_ctx->stream->signal,
+                                               &audio_output.crtc_info,
+                                               &audio_output.pll_info);
+                               }
                                break;
                        }
                }
index 7f58930fc87e62e8a9a54da3d47730eedbaf06fb..7112b71af97704483009cd038b577f9474558acc 100644 (file)
@@ -755,6 +755,43 @@ void dcn10_log_hw_state(struct dc *dc,
 
        log_mpc_crc(dc, log_ctx);
 
+       for (i = 0; i < pool->hpo_frl_stream_enc_count; i++) {
+               struct hpo_frl_stream_encoder_state hpo_se_state = {0};
+               struct hpo_frl_link_enc_state hpo_le_state = {0};
+               struct hpo_frl_stream_encoder *hpo_frl_stream_enc = pool->hpo_frl_stream_enc[i];
+               struct hpo_frl_link_encoder *hpo_frl_link_enc = dc->links[i]->hpo_frl_link_enc;
+               bool printed_header = false;
+
+               hpo_frl_stream_enc->funcs->read_state(hpo_frl_stream_enc, &hpo_se_state);
+               if (hpo_se_state.stream_enc_enabled)
+                       hpo_frl_link_enc->funcs->read_state(hpo_frl_link_enc, &hpo_le_state);
+
+               /* Only print if HPO link is enabled */
+               if ((hpo_se_state.stream_enc_enabled == 0)
+                               || (hpo_le_state.link_enc_enabled == 0))
+                       continue;
+               if (!printed_header) {
+                       DTN_INFO("\n");
+                       DTN_INFO("HPO:   OTG Inst     Link   Pixel Format   Depth   ODM Segments   Lanes   Borrow   h_active   h_blank\n");
+                       printed_header = true;
+               }
+
+               DTN_INFO("[%d]: %10d   %6s   %10s   %5d          %5d   %5d   %6s      %5d     %5d\n",
+                               hpo_frl_stream_enc->id - ENGINE_ID_HPO_0,
+                               hpo_se_state.otg_inst,
+                               hpo_le_state.link_active ? "Active" : "Training",
+                               (hpo_se_state.pixel_format == PIXEL_ENCODING_YCBCR420) ? "4:2:0" :
+                                               ((hpo_se_state.pixel_format == PIXEL_ENCODING_YCBCR422) ? "4:2:2" : "4:4:4"),
+                               hpo_se_state.color_depth,
+                               hpo_se_state.num_odm_segments,
+                               hpo_le_state.lane_count,
+                               (hpo_se_state.borrow_mode == 0) ? "NONE" :
+                                               ((hpo_se_state.borrow_mode == 1) ? "ACTIVE" : "BLANK"),
+                               hpo_se_state.h_active,
+                               hpo_se_state.h_blank);
+       }
+       DTN_INFO("\n");
+
        {
                if (pool->hpo_dp_stream_enc_count > 0) {
                        DTN_INFO("DP HPO S_ENC:  Enabled  OTG   Format   Depth   Vid   SDP   Compressed  Link\n");
index 07c53a8e73b5306c9c4b2c230947c5bdb940fe4f..e6a8206f8ce0af8a849e75e03f99ea72aa61e30b 100644 (file)
@@ -918,6 +918,11 @@ enum dc_status dcn20_enable_stream_timing(
                        pipe_ctx->stream->signal,
                        true);
 
+       /* Must use manual div mode for FRL */
+       if (pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode) {
+               bool manual_mode = dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) || !is_h_timing_divisible_by_2(stream) || dc_is_virtual_signal(pipe_ctx->stream->signal);
+               pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode(pipe_ctx->stream_res.tg, manual_mode);
+       }
        rate_control_2x_pclk = rate_control_2x_pclk || opp_cnt > 1;
        flow_control.flow_ctrl_mode = 0;
        flow_control.flow_ctrl_cnt0 = 0x80;
@@ -2789,6 +2794,16 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
                pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
        }
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
+               if (params.opp_cnt == 4)
+                       params.timing.pix_clk_100hz /= 4;
+               else if (is_two_pixels_per_container || params.opp_cnt > 1)
+                       params.timing.pix_clk_100hz /= 2;
+               if (link->link_status.link_active && link->frl_link_settings.frl_link_rate != 0)
+                       pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_unblank(
+                                       pipe_ctx->stream_res.hpo_frl_stream_enc,
+                                       pipe_ctx->stream_res.tg->inst);
+       }
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
                hws->funcs.edp_backlight_control(link, true);
        }
@@ -3056,7 +3071,9 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
                        dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
                }
        } else {
-               if (dccg->funcs->enable_symclk_se && link_enc) {
+               if (dccg->funcs->enable_symclk_se
+                       && link_enc
+                       && pipe_ctx->stream->signal != SIGNAL_TYPE_HDMI_FRL) {
                        if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA
                                && link->cur_link_settings.link_rate == LINK_RATE_UNKNOWN
                                && !link->link_status.link_active) {
index 3c70d685ba65f211d55f0f5599d6dd1e03ee0550..a7c85a2302aba532161f673ff59ce88987142877 100644 (file)
@@ -838,6 +838,10 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
        if (pipe_ctx == NULL)
                return;
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.hpo_frl_stream_enc != NULL)
+               pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->set_avmute(
+                               pipe_ctx->stream_res.hpo_frl_stream_enc,
+                               enable);
        if (dc_is_hdmi_signal(pipe_ctx->stream->signal) && pipe_ctx->stream_res.stream_enc != NULL) {
                pipe_ctx->stream_res.stream_enc->funcs->set_avmute(
                                pipe_ctx->stream_res.stream_enc,
@@ -858,22 +862,29 @@ void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx)
 {
        bool is_hdmi_tmds;
        bool is_dp;
+       bool is_hdmi_frl;
 
        ASSERT(pipe_ctx->stream);
 
-       if (pipe_ctx->stream_res.stream_enc == NULL)
+       if (pipe_ctx->stream_res.stream_enc == NULL &&
+                       pipe_ctx->stream_res.hpo_frl_stream_enc == NULL)
                return;  /* this is not root pipe */
 
        is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
        is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
 
-       if (!is_hdmi_tmds && !is_dp)
+       is_hdmi_frl = dc_is_hdmi_frl_signal(pipe_ctx->stream->signal);
+       if (!is_hdmi_tmds && !is_dp && !is_hdmi_frl)
                return;
 
        if (is_hdmi_tmds)
                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
+       else if (is_hdmi_frl)
+               pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->update_hdmi_info_packets(
+                       pipe_ctx->stream_res.hpo_frl_stream_enc,
+                       &pipe_ctx->stream_res.encoder_info_frame);
        else {
                if (pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num)
                        pipe_ctx->stream_res.stream_enc->funcs->update_dp_info_packets_sdp_line_num(
@@ -892,6 +903,7 @@ void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
        struct hubp               *hubp       = pipe_ctx->plane_res.hubp;
        bool                       enable     = false;
        struct stream_encoder     *stream_enc = pipe_ctx->stream_res.stream_enc;
+       struct hpo_frl_stream_encoder *hpo_enc    = pipe_ctx->stream_res.hpo_frl_stream_enc;
        enum dynamic_metadata_mode mode       = dc_is_dp_signal(stream->signal)
                                                        ? dmdata_dp
                                                        : dmdata_hdmi;
@@ -905,11 +917,44 @@ void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx)
        if (!hubp)
                return;
 
+       if (dc_is_hdmi_frl_signal(stream->signal)) {
+               ASSERT(mode == dmdata_hdmi);
+
+               if (!hpo_enc || !hpo_enc->funcs->set_dynamic_metadata)
+                       return;
+
+               hpo_enc->funcs->set_dynamic_metadata(hpo_enc, enable,
+                                                    hubp->inst, dmdata_hdmi);
+       } else {
        if (!stream_enc || !stream_enc->funcs->set_dynamic_metadata)
                return;
 
        stream_enc->funcs->set_dynamic_metadata(stream_enc, enable,
                                                        hubp->inst, mode);
+       }
+}
+enum dc_status dcn30_setup_hdmi_frl_link(
+               struct dc_link *link,
+               int hpo_inst,
+               enum clock_source_id frl_phy_clock_source_id)
+{
+       (void)hpo_inst;
+       enum dc_status status = DC_OK;
+       struct dc *dc = link->ctx->dc;
+
+       if ((!link->link_enc) ||
+                       (!link->hpo_frl_link_enc) ||
+                       (!dc->res_pool->dccg->funcs->enable_hdmicharclk))
+               return DC_ERROR_UNEXPECTED;
+
+       //Enable phy output for FRL case
+       link->hpo_frl_link_enc->funcs->enable_frl_phy_output(
+               link->hpo_frl_link_enc,
+               link->link_enc,
+               frl_phy_clock_source_id,
+               link->frl_link_settings.frl_link_rate);
+       link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
+       return status;
 }
 
 bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
index 40afbbfb5b9c36f8018c9dcf70996569b1565515..2306354e90af6bdebe763aaee2aa3990f78bffbe 100644 (file)
@@ -72,6 +72,22 @@ void dcn30_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
 void dcn30_update_info_frame(struct pipe_ctx *pipe_ctx);
 void dcn30_program_dmdata_engine(struct pipe_ctx *pipe_ctx);
 
+enum dc_status dcn30_setup_hdmi_frl_link(
+               struct dc_link *link,
+               int hpo_inst,
+               enum clock_source_id frl_phy_clock_source_id);
+void dcn30_hw_set_fva_vrr_adj(struct dc *dc, struct pipe_ctx **pipe_ctx, int num_pipes,
+               struct fva_adj *fva_adj,
+               struct dc_crtc_timing_adjust *vrr_adj);
+
+int dcn30_hw_get_max_fva_factor(struct dc *dc,
+               struct pipe_ctx *pipe_ctx,
+               struct dc_crtc_timing *timing,
+               unsigned int max_pixel_clock);
+
+void dcn30_hw_set_vstartup_dsc_frl(struct dc *dc,
+               struct pipe_ctx *pipe_ctx);
+
 bool dcn30_does_plane_fit_in_mall(struct dc *dc,
                unsigned int pitch,
                unsigned int height,
index 9834d30754878157f10e196c3086c9984ddb9f79..d5aa58462855cf024c437d96392e9d46272a911d 100644 (file)
@@ -105,6 +105,7 @@ static const struct hw_sequencer_funcs dcn30_funcs = {
        .enable_tmds_link_output = dce110_enable_tmds_link_output,
        .enable_dp_link_output = dce110_enable_dp_link_output,
        .disable_link_output = dce110_disable_link_output,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
        .get_dcc_en_bits = dcn10_get_dcc_en_bits,
        .update_visual_confirm_color = dcn10_update_visual_confirm_color,
index 71643ccf23d922bcefa7a798d76746441b9149f0..43e4edfe9182ed5f3928d40194fd4a37ef8acea0 100644 (file)
@@ -104,6 +104,8 @@ static void enable_memory_low_power(struct dc *dc)
                                dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg);
                for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++)
                        dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg);
+               for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++)
+                       dc->res_pool->hpo_frl_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_frl_stream_enc[i]->vpg);
        }
 
 }
@@ -377,22 +379,29 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
 {
        bool is_hdmi_tmds;
        bool is_dp;
+       bool is_hdmi_frl;
 
        ASSERT(pipe_ctx->stream);
 
-       if (pipe_ctx->stream_res.stream_enc == NULL)
+       if (pipe_ctx->stream_res.stream_enc == NULL &&
+                       pipe_ctx->stream_res.hpo_frl_stream_enc == NULL)
                return;  /* this is not root pipe */
 
        is_hdmi_tmds = dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal);
        is_dp = dc_is_dp_signal(pipe_ctx->stream->signal);
 
-       if (!is_hdmi_tmds && !is_dp)
+       is_hdmi_frl = dc_is_hdmi_frl_signal(pipe_ctx->stream->signal);
+       if (!is_hdmi_tmds && !is_dp && !is_hdmi_frl)
                return;
 
        if (is_hdmi_tmds)
                pipe_ctx->stream_res.stream_enc->funcs->update_hdmi_info_packets(
                        pipe_ctx->stream_res.stream_enc,
                        &pipe_ctx->stream_res.encoder_info_frame);
+       else if (is_hdmi_frl)
+               pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->update_hdmi_info_packets(
+                       pipe_ctx->stream_res.hpo_frl_stream_enc,
+                       &pipe_ctx->stream_res.encoder_info_frame);
        else if (pipe_ctx->stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                if (pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets_sdp_line_num)
                        pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->update_dp_info_packets_sdp_line_num(
index b14e6e60b8786ab9dcead5aa38a8b9465a3b4394..7197414e5bd69381390007aeeeb447eb7d1d16ff 100644 (file)
@@ -98,6 +98,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .set_backlight_level = dcn21_set_backlight_level,
        .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
        .set_pipe = dcn21_set_pipe,
index 09dfbb16dd29ae7d4c083b2b10651ec5a4742f98..6ddc678bacf961fd0978a075ccb18157aed3d050 100644 (file)
@@ -335,7 +335,8 @@ unsigned int dcn314_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsig
        two_pix_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
        odm_combine_factor = get_odm_config(pipe_ctx, NULL);
 
-       if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
+                       stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                *k1_div = PIXEL_RATE_DIV_BY_1;
                *k2_div = PIXEL_RATE_DIV_BY_1;
        } else if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal) || dc_is_dvi_signal(pipe_ctx->stream->signal)) {
index d782080883ab783f68f2e0c69bb08c9b521b7ebf..4966c044a86440936bbae632c5ae0775cdc2229a 100644 (file)
@@ -100,6 +100,7 @@ static const struct hw_sequencer_funcs dcn314_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .set_backlight_level = dcn21_set_backlight_level,
        .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
        .set_pipe = dcn21_set_pipe,
index 415b3f875f0d1f8a156b4ff6c32cf0cee894403d..a3242e7521a4829a7017f609aff9413b18b70e5a 100644 (file)
@@ -1205,7 +1205,8 @@ unsigned int dcn32_calculate_dccg_k1_k2_values(struct pipe_ctx *pipe_ctx, unsign
        two_pix_per_container = pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
        odm_combine_factor = get_odm_config(pipe_ctx, NULL);
 
-       if (stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal) ||
+                       stream->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) {
                *k1_div = PIXEL_RATE_DIV_BY_1;
                *k2_div = PIXEL_RATE_DIV_BY_1;
        } else if (dc_is_hdmi_tmds_signal(stream->signal) || dc_is_dvi_signal(stream->signal)) {
@@ -1351,6 +1352,16 @@ void dcn32_unblank_stream(struct pipe_ctx *pipe_ctx,
                pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
        }
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
+               if (params.opp_cnt == 4)
+                       params.timing.pix_clk_100hz /= 4;
+               else if (pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing) || params.opp_cnt > 1)
+                       params.timing.pix_clk_100hz /= 2;
+               if (link->link_status.link_active && link->frl_link_settings.frl_link_rate != 0)
+                       pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_unblank(
+                                       pipe_ctx->stream_res.hpo_frl_stream_enc,
+                                       pipe_ctx->stream_res.tg->inst);
+       }
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
                hws->funcs.edp_backlight_control(link, true);
 }
index c68b2010477324576c62d630420d0b1962185d66..364b4108f5d6f5709f3727a5a4a6d6546c1afc97 100644 (file)
@@ -31,6 +31,7 @@
 #include "dcn31/dcn31_hwseq.h"
 #include "dcn32/dcn32_hwseq.h"
 #include "dcn401/dcn401_hwseq.h"
+#include "dml/dcn32/dcn32_fpu.h"
 #include "dcn32_init.h"
 
 static const struct hw_sequencer_funcs dcn32_funcs = {
@@ -96,6 +97,8 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
+       .get_max_dispclk_mhz = dcn32_get_max_dispclk_mhz,
        .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations,
        .does_plane_fit_in_mall = NULL,
        .set_backlight_level = dcn31_set_backlight_level,
index 1a0123338dfae1f0e7e1165ccf48ab03b72afcb3..8f9038fec0f7ba690810b8f255351ad22c3f71bf 100644 (file)
@@ -110,6 +110,8 @@ static void enable_memory_low_power(struct dc *dc)
                for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++)
                        dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg);
 #endif
+               for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++)
+                       dc->res_pool->hpo_frl_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_frl_stream_enc[i]->vpg);
        }
 
 }
@@ -439,6 +441,9 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
+       if (!(pipe_ctx->stream_res.hpo_frl_stream_enc &&
+                       pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_fifo_odm_enabled &&
+                       pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_fifo_odm_enabled(pipe_ctx->stream_res.hpo_frl_stream_enc))) {
        if (opp_cnt > 1)
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
@@ -463,6 +468,7 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                                odm_pipe->stream_res.opp,
                                true);
        }
+       }
 
        if (pipe_ctx->stream_res.dsc) {
                struct pipe_ctx *current_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx];
@@ -501,6 +507,17 @@ void dcn35_dpstream_root_clock_control(struct dce_hwseq *hws, unsigned int dp_hp
        }
 }
 
+void dcn35_hdmistream_root_clock_control(struct dce_hwseq *hws, bool clock_on)
+{
+       if (!hws->ctx->dc->debug.root_clock_optimization.bits.hdmistream)
+               return;
+
+       if (hws->ctx->dc->res_pool->dccg->funcs->set_hdmistreamclk_root_clock_gating) {
+               hws->ctx->dc->res_pool->dccg->funcs->set_hdmistreamclk_root_clock_gating(
+                       hws->ctx->dc->res_pool->dccg, clock_on);
+       }
+}
+
 void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_inst, bool clock_on)
 {
        if (!hws->ctx->dc->debug.root_clock_optimization.bits.physymclk)
@@ -936,6 +953,14 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
 
        memset(update_state, 0, sizeof(struct pg_block_update));
 
+       for (ui = 0; ui < dc->res_pool->hpo_frl_stream_enc_count; ui++) {
+               if (context->res_ctx.is_hpo_frl_stream_enc_acquired[ui] &&
+                               dc->res_pool->hpo_frl_stream_enc[ui]) {
+                       hpo_frl_stream_enc_acquired = true;
+                       break;
+               }
+       }
+
        for (ui = 0; ui < dc->res_pool->hpo_dp_stream_enc_count; ui++) {
                if (context->res_ctx.is_hpo_dp_stream_enc_acquired[ui] &&
                                dc->res_pool->hpo_dp_stream_enc[ui]) {
@@ -991,6 +1016,9 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
                        update_state->pg_pipe_res_update[PG_DPSTREAM][pipe_ctx->stream_res.hpo_dp_stream_enc->inst] = false;
        }
 
+       if (hpo_frl_stream_enc_acquired)
+               update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = false;
+
        for (i = 0; i < dc->link_count; i++) {
                update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;
                if (dc->links[i]->type != dc_connection_none)
@@ -1113,6 +1141,14 @@ void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,
                if (dc->links[i]->type != dc_connection_none)
                        update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;
 
+       for (ui = 0; ui < dc->res_pool->hpo_frl_stream_enc_count; ui++) {
+               if (context->res_ctx.is_hpo_frl_stream_enc_acquired[ui] &&
+                               dc->res_pool->hpo_frl_stream_enc[ui]) {
+                       hpo_frl_stream_enc_acquired = true;
+                       break;
+               }
+       }
+
        for (ui = 0; ui < dc->res_pool->hpo_dp_stream_enc_count; ui++) {
                if (context->res_ctx.is_hpo_dp_stream_enc_acquired[ui] &&
                                dc->res_pool->hpo_dp_stream_enc[ui]) {
@@ -1330,6 +1366,9 @@ void dcn35_root_clock_control(struct dc *dc,
                                if (dc->hwseq->funcs.physymclk_root_clock_control)
                                        dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
 
+               if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
+                       if (dc->hwseq->funcs.hdmistream_root_clock_control)
+                               dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
        }
        for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
                if (update_state->pg_pipe_res_update[PG_DSC][i]) {
@@ -1360,6 +1399,9 @@ void dcn35_root_clock_control(struct dc *dc,
                                if (dc->hwseq->funcs.physymclk_root_clock_control)
                                        dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
 
+               if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
+                       if (dc->hwseq->funcs.hdmistream_root_clock_control)
+                               dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
        }
 }
 
index e3459546a908a12ce7772f151a5136c3cb56fead..235ebf00bd1f2146d2018180778cff41a1fcb1f1 100644 (file)
@@ -39,6 +39,8 @@ void dcn35_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst,
 
 void dcn35_dpstream_root_clock_control(struct dce_hwseq *hws, unsigned int dp_hpo_inst, bool clock_on);
 
+void dcn35_hdmistream_root_clock_control(struct dce_hwseq *hws, bool clock_on);
+
 void dcn35_physymclk_root_clock_control(struct dce_hwseq *hws, unsigned int phy_inst, bool clock_on);
 
 void dcn35_enable_power_gating_plane(struct dce_hwseq *hws, bool enable);
index 6ac8ad97cf13546d27a4653fef5ba1a93dde2032..fc18d2207711f8e3787377a58d4ebc28e9f74c7b 100644 (file)
@@ -107,6 +107,7 @@ static const struct hw_sequencer_funcs dcn35_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .set_backlight_level = dcn31_set_backlight_level,
        .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
        .set_pipe = dcn21_set_pipe,
@@ -158,6 +159,7 @@ static const struct hwseq_private_funcs dcn35_private_funcs = {
        //.hubp_pg_control = dcn35_hubp_pg_control,
        .dpp_root_clock_control = dcn35_dpp_root_clock_control,
        .dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
+       .hdmistream_root_clock_control = dcn35_hdmistream_root_clock_control,
        .physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
        .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
        .update_odm = dcn35_update_odm,
index 04c260015eec36f40f924b1d0ddeeec7215d3b2a..19ec5b4edfdc95da6a24a766a3e7f87ade4f1e00 100644 (file)
@@ -100,6 +100,7 @@ static const struct hw_sequencer_funcs dcn351_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .set_backlight_level = dcn31_set_backlight_level,
        .set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
        .set_pipe = dcn21_set_pipe,
@@ -147,6 +148,7 @@ static const struct hwseq_private_funcs dcn351_private_funcs = {
        //.hubp_pg_control = dcn35_hubp_pg_control,
        .dpp_root_clock_control = dcn35_dpp_root_clock_control,
        .dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
+       .hdmistream_root_clock_control = dcn35_hdmistream_root_clock_control,
        .physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
        .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
        .update_odm = dcn35_update_odm,
index 2daa588a72e54d793d5a2c1015b03531c50817b3..96815a92a6298add7465763dbaced05d27c0f1d5 100644 (file)
@@ -787,6 +787,9 @@ static void enable_stream_timing_calc(
                        stream->link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
        }
 
+       if (pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode) {
+               *manual_mode = !is_h_timing_divisible_by_2(stream);
+       }
        params->vertical_total_min = stream->adjust.v_total_min;
        params->vertical_total_max = stream->adjust.v_total_max;
        params->vertical_total_mid = stream->adjust.v_total_mid;
@@ -844,6 +847,8 @@ enum dc_status dcn401_enable_stream_timing(
        if (dc->res_pool->dccg->funcs->set_dtbclk_p_src) {
                if (dc_is_dp_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) {
                        dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DPREFCLK, pipe_ctx->stream_res.tg->inst);
+               } else if (dc_is_hdmi_frl_signal(stream->signal)) {
+                       dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, DTBCLK0, pipe_ctx->stream_res.tg->inst);
                }
        }
 
@@ -882,6 +887,8 @@ enum dc_status dcn401_enable_stream_timing(
                pipe_ctx->stream->signal,
                true);
 
+       if (pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode)
+               pipe_ctx->stream_res.tg->funcs->set_h_timing_div_manual_mode(pipe_ctx->stream_res.tg, manual_mode);
        for (i = 0; i < opp_cnt; i++) {
                opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
                                opp_heads[i]->stream_res.opp,
@@ -1846,6 +1853,12 @@ void dcn401_unblank_stream(struct pipe_ctx *pipe_ctx,
                pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, &params);
        }
 
+       if (dc_is_hdmi_frl_signal(pipe_ctx->stream->signal)) {
+               if (link->link_status.link_active && link->frl_link_settings.frl_link_rate != 0)
+                       pipe_ctx->stream_res.hpo_frl_stream_enc->funcs->hdmi_frl_unblank(
+                                       pipe_ctx->stream_res.hpo_frl_stream_enc,
+                                       pipe_ctx->stream_res.tg->inst);
+       }
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP)
                hws->funcs.edp_backlight_control(link, true);
 }
index 0908a791832baf077ea2e2ad64bf70028a319972..33b2cf344f1e6c366e58018039b16bbfe6fa4880 100644 (file)
@@ -84,6 +84,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .apply_idle_power_optimizations = dcn401_apply_idle_power_optimizations,
        .does_plane_fit_in_mall = NULL,
        .set_backlight_level = dcn31_set_backlight_level,
index cabfac151940fb11912755f6fba43b3e033fe43d..664004cadf10ea8626e41959fc1aecfee0d79d2f 100644 (file)
@@ -974,6 +974,14 @@ void dcn42_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
 
        update_state->pg_res_update[PG_DIO] = true;
 
+       for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
+               if (context->res_ctx.is_hpo_frl_stream_enc_acquired[i] &&
+                               dc->res_pool->hpo_frl_stream_enc[i]) {
+                       hpo_frl_stream_enc_acquired = true;
+                       break;
+               }
+       }
+
        for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {
                if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&
                                dc->res_pool->hpo_dp_stream_enc[i]) {
@@ -1019,11 +1027,14 @@ void dcn42_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
                if (pipe_ctx->link_res.dio_link_enc) {
                        update_state->pg_res_update[PG_DIO] = false;
                }
-               if (pipe_ctx->link_res.hpo_dp_link_enc) {
+               if (pipe_ctx->link_res.hpo_dp_link_enc
+                   || pipe_ctx->link_res.hpo_frl_link_enc) {
                        update_state->pg_res_update[PG_HPO] = false;
                }
        }
 
+       if (hpo_frl_stream_enc_acquired)
+               update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = false;
 
        for (i = 0; i < dc->link_count; i++) {
                update_state->pg_pipe_res_update[PG_PHYSYMCLK][dc->links[i]->link_enc_hw_inst] = true;
@@ -1043,6 +1054,12 @@ void dcn42_calc_blocks_to_gate(struct dc *dc, struct dc_state *context,
                }
        }
 
+       for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
+               if (dc->current_state->res_ctx.is_hpo_frl_stream_enc_acquired[i]) {
+                       update_state->pg_res_update[PG_HPO] = false;
+                       break;
+               }
+       }
 }
 
 void dcn42_prepare_bandwidth(
@@ -1090,6 +1107,7 @@ void dcn42_optimize_bandwidth(struct dc *dc, struct dc_state *context)
 void dcn42_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,
        struct pg_block_update *update_state)
 {
+       bool hpo_frl_stream_enc_acquired = false;
        bool hpo_dp_stream_enc_acquired = false;
        unsigned int i = 0;
        int j = 0;
@@ -1176,6 +1194,14 @@ void dcn42_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,
                        break;
                }
        }
+       for (i = 0; i < dc->res_pool->hpo_frl_stream_enc_count; i++) {
+               if (context->res_ctx.is_hpo_frl_stream_enc_acquired[i] &&
+                               dc->res_pool->hpo_frl_stream_enc[i]) {
+                       hpo_frl_stream_enc_acquired = true;
+                       break;
+               }
+       }
+
        for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) {
                if (context->res_ctx.is_hpo_dp_stream_enc_acquired[i] &&
                                dc->res_pool->hpo_dp_stream_enc[i]) {
@@ -1184,9 +1210,11 @@ void dcn42_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context,
                }
        }
 
-       if (hpo_dp_stream_enc_acquired)
+       if (hpo_frl_stream_enc_acquired || hpo_dp_stream_enc_acquired)
                update_state->pg_res_update[PG_HPO] = true;
 
+       if (hpo_frl_stream_enc_acquired)
+               update_state->pg_pipe_res_update[PG_HDMISTREAM][0] = true;
        if (count_active_streams(dc) > 0) {
                update_state->pg_res_update[PG_DCCG] = true;
                update_state->pg_res_update[PG_DCIO] = true;
@@ -1397,6 +1425,9 @@ void dcn42_root_clock_control(struct dc *dc,
                                if (dc->hwseq->funcs.physymclk_root_clock_control)
                                        dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
 
+               if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
+                       if (dc->hwseq->funcs.hdmistream_root_clock_control)
+                               dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
        }
        for (i = 0; i < (unsigned int)dc->res_pool->res_cap->num_dsc; i++) {
                if (update_state->pg_pipe_res_update[PG_DSC][i]) {
@@ -1427,6 +1458,9 @@ void dcn42_root_clock_control(struct dc *dc,
                                if (dc->hwseq->funcs.physymclk_root_clock_control)
                                        dc->hwseq->funcs.physymclk_root_clock_control(dc->hwseq, i, power_on);
 
+               if (update_state->pg_pipe_res_update[PG_HDMISTREAM][0])
+                       if (dc->hwseq->funcs.hdmistream_root_clock_control)
+                               dc->hwseq->funcs.hdmistream_root_clock_control(dc->hwseq, power_on);
        }
 }
 void dcn42_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc)
index b324a2195e8a6507ede3ec917e02de79cb8f2d54..49c13611a518673cbe67479385549319f4c2705b 100644 (file)
@@ -85,6 +85,7 @@ static const struct hw_sequencer_funcs dcn42_funcs = {
        .set_flip_control_gsl = dcn20_set_flip_control_gsl,
        .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
        .calc_vupdate_position = dcn10_calc_vupdate_position,
+       .setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
        .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations,
        .does_plane_fit_in_mall = NULL,
        .set_backlight_level = dcn31_set_backlight_level,
@@ -159,6 +160,7 @@ static const struct hwseq_private_funcs dcn42_private_funcs = {
        .program_cm_hist = dcn42_program_cm_hist,
        .dpp_root_clock_control = dcn35_dpp_root_clock_control,
        .dpstream_root_clock_control = dcn35_dpstream_root_clock_control,
+       .hdmistream_root_clock_control = dcn35_hdmistream_root_clock_control,
        .physymclk_root_clock_control = dcn35_physymclk_root_clock_control,
        .resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio,
        .wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
index 4b9fcb87e60dc17e2d94cdd84ec0a5ecfefeee36..a9569078622f4df862e196eadff3d4bcbd53bbff 100644 (file)
@@ -806,6 +806,10 @@ struct stream_enc_update_hdmi_info_packets_params {
        struct pipe_ctx *pipe_ctx;
 };
 
+struct hpo_frl_stream_enc_update_hdmi_info_packets_params {
+       struct pipe_ctx *pipe_ctx;
+};
+
 struct hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num_params {
        struct pipe_ctx *pipe_ctx;
 };
@@ -847,6 +851,12 @@ struct stream_enc_dp_set_dsc_pps_info_packet_params {
        bool pps_sdp_stream;
 };
 
+struct hpo_frl_stream_enc_set_dsc_config_params {
+       struct hpo_frl_stream_encoder *hpo_frl_stream_enc;
+       const struct dc_crtc_timing *timing;
+       uint8_t *dsc_packed_pps;
+};
+
 struct dp_trace_source_sequence_params {
        struct dc_link *link;
        enum dpcd_source_sequence source;
@@ -1028,6 +1038,7 @@ union block_sequence_params {
        struct update_cursor_offload_pipe_params update_cursor_offload_pipe_params;
        struct commit_cursor_offload_update_params commit_cursor_offload_update_params;
        struct stream_enc_update_hdmi_info_packets_params stream_enc_update_hdmi_info_packets_params;
+       struct hpo_frl_stream_enc_update_hdmi_info_packets_params hpo_frl_stream_enc_update_hdmi_info_packets_params;
        struct hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num_params hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num_params;
        struct hpo_dp_stream_enc_update_dp_info_packets_params hpo_dp_stream_enc_update_dp_info_packets_params;
        struct stream_enc_update_dp_info_packets_sdp_line_num_params stream_enc_update_dp_info_packets_sdp_line_num_params;
@@ -1036,6 +1047,7 @@ union block_sequence_params {
        struct stream_enc_dp_set_dsc_config_params stream_enc_dp_set_dsc_config_params;
        struct hpo_dp_stream_enc_dp_set_dsc_pps_info_packet_params hpo_dp_stream_enc_dp_set_dsc_pps_info_packet_params;
        struct stream_enc_dp_set_dsc_pps_info_packet_params stream_enc_dp_set_dsc_pps_info_packet_params;
+       struct hpo_frl_stream_enc_set_dsc_config_params hpo_frl_stream_enc_set_dsc_config_params;
        struct dp_trace_source_sequence_params dp_trace_source_sequence_params;
        struct set_dmdata_attributes_params set_dmdata_attributes_params;
        struct link_increase_mst_payload_params link_increase_mst_payload_params;
@@ -1179,6 +1191,7 @@ enum block_sequence_func {
        HUBP_SET_BLANK,
        PHANTOM_HUBP_POST_ENABLE,
        STREAM_ENC_UPDATE_HDMI_INFO_PACKETS,
+       HPO_FRL_STREAM_ENC_UPDATE_HDMI_INFO_PACKETS,
        HPO_DP_STREAM_ENC_UPDATE_DP_INFO_PACKETS_SDP_LINE_NUM,
        HPO_DP_STREAM_ENC_UPDATE_DP_INFO_PACKETS,
        STREAM_ENC_UPDATE_DP_INFO_PACKETS_SDP_LINE_NUM,
@@ -1187,6 +1200,7 @@ enum block_sequence_func {
        STREAM_ENC_DP_SET_DSC_CONFIG,
        HPO_DP_STREAM_ENC_DP_SET_DSC_PPS_INFO_PACKET,
        STREAM_ENC_DP_SET_DSC_PPS_INFO_PACKET,
+       HPO_FRL_STREAM_ENC_SET_DSC_CONFIG,
        LINK_INCREASE_MST_PAYLOAD,
        LINK_REDUCE_MST_PAYLOAD,
        DP_TRACE_SOURCE_SEQUENCE,
@@ -1415,6 +1429,14 @@ struct hw_sequencer_funcs {
 
        void (*get_dcc_en_bits)(struct dc *dc, int *dcc_en_bits);
 
+       enum dc_status (*setup_hdmi_frl_link)(
+                       struct dc_link *link,
+                       int hpo_inst,
+                       enum clock_source_id frl_phy_clock_source_id);
+
+       unsigned int (*get_max_dispclk_mhz)(struct dc *dc,
+                       struct dc_state *context);
+
        /* Idle Optimization Related */
        bool (*apply_idle_power_optimizations)(struct dc *dc, bool enable);
 
@@ -1672,6 +1694,8 @@ void hwss_dsc_set_config_simple(union block_sequence_params *params);
 
 void hwss_stream_enc_update_hdmi_info_packets(union block_sequence_params *params);
 
+void hwss_hpo_frl_stream_enc_update_hdmi_info_packets(union block_sequence_params *params);
+
 void hwss_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num(union block_sequence_params *params);
 
 void hwss_hpo_dp_stream_enc_update_dp_info_packets(union block_sequence_params *params);
@@ -2367,6 +2391,9 @@ void hwss_add_commit_cursor_offload_update(struct block_sequence_state *seq_stat
 void hwss_add_stream_enc_update_hdmi_info_packets(struct block_sequence_state *seq_state,
                struct pipe_ctx *pipe_ctx);
 
+void hwss_add_hpo_frl_stream_enc_update_hdmi_info_packets(struct block_sequence_state *seq_state,
+               struct pipe_ctx *pipe_ctx);
+
 void hwss_add_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num(struct block_sequence_state *seq_state,
                struct pipe_ctx *pipe_ctx);
 
@@ -2400,6 +2427,11 @@ void hwss_add_stream_enc_dp_set_dsc_pps_info_packet(struct block_sequence_state
                uint8_t *dsc_packed_pps,
                bool pps_sdp_stream);
 
+void hwss_add_hpo_frl_stream_enc_set_dsc_config(struct block_sequence_state *seq_state,
+               struct hpo_frl_stream_encoder *hpo_frl_stream_enc,
+               const struct dc_crtc_timing *timing,
+               uint8_t *dsc_packed_pps);
+
 void hwss_add_setup_periodic_interrupt(struct block_sequence_state *seq_state,
                struct dc *dc,
                struct pipe_ctx *pipe_ctx);
index 8e3f54fb53fd60b8116ecf460d891d34fb35c9ed..63c6c841c681fefee72ce23dc370f9d0382aed7a 100644 (file)
@@ -140,6 +140,9 @@ struct hwseq_private_funcs {
                        struct dce_hwseq *hws,
                        unsigned int dpp_inst,
                        bool clock_on);
+       void (*hdmistream_root_clock_control)(
+                       struct dce_hwseq *hws,
+                       bool clock_on);
        void (*physymclk_root_clock_control)(
                        struct dce_hwseq *hws,
                        unsigned int phy_inst,