]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Configure DTBCLK_P with OPTC only for dcn401
authorDillon Varone <dillon.varone@amd.com>
Fri, 20 Sep 2024 20:56:20 +0000 (16:56 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 1 Oct 2024 21:38:17 +0000 (17:38 -0400)
[WHY]
DTBCLK_P is used to generate virtual pixel clock, and to drive the HPO
stream encoder clock. Programming the required clock when
enabling/disabling both components can cause issues.
For example, if HPO is being disabled and clock source is changed to
REFCLK, virtual pixel rate will then be wrong, causing issues in CRTC.

[HOW]
Only program the DTBCLK_P when programming CRTC, as its expected it will
be enabled prior to HPO, and disabled after HPO in all valid cases.

Reviewed-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Dillon Varone <dillon.varone@amd.com>
Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/dccg/dcn401/dcn401_dccg.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c

index 5babd53025aef474425df2a5e9917d3eec30c545..d3e46c3cfa5750d5565fef2b5b4d30b18842ef85 100644 (file)
@@ -580,9 +580,6 @@ static void dccg401_set_dpstreamclk(
                int otg_inst,
                int dp_hpo_inst)
 {
-       /* set the dtbclk_p source */
-       dccg401_set_dtbclk_p_src(dccg, src, otg_inst);
-
        /* enabled to select one of the DTBCLKs for pipe */
        if (src == REFCLK)
                dccg401_disable_dpstreamclk(dccg, dp_hpo_inst);
index b690f0565d285d8fcf8b875d6c142d02c5ebc496..49a37f5ee28e78cbb01e0d006d8b975e4b57f685 100644 (file)
@@ -844,6 +844,13 @@ enum dc_status dcn401_enable_stream_timing(
                                odm_slice_width, last_odm_slice_width);
        }
 
+       /* set DTBCLK_P */
+       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);
+               }
+       }
+
        /* HW program guide assume display already disable
         * by unplug sequence. OTG assume stop.
         */
@@ -1004,8 +1011,6 @@ void dcn401_enable_stream(struct pipe_ctx *pipe_ctx)
 
                        dccg->funcs->enable_symclk32_se(dccg, dp_hpo_inst, phyd32clk);
                } else {
-                       /* need to set DTBCLK_P source to DPREFCLK for DP8B10B */
-                       dccg->funcs->set_dtbclk_p_src(dccg, DPREFCLK, tg->inst);
                        dccg->funcs->enable_symclk_se(dccg, stream_enc->stream_enc_inst,
                                        link_enc->transmitter - TRANSMITTER_UNIPHY_A);
                }
@@ -1819,3 +1824,129 @@ void dcn401_program_outstanding_updates(struct dc *dc,
        if (hubbub->funcs->program_compbuf_segments)
                hubbub->funcs->program_compbuf_segments(hubbub, context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true);
 }
+
+void dcn401_reset_back_end_for_pipe(
+               struct dc *dc,
+               struct pipe_ctx *pipe_ctx,
+               struct dc_state *context)
+{
+       int i;
+       struct dc_link *link = pipe_ctx->stream->link;
+       const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+
+       DC_LOGGER_INIT(dc->ctx->logger);
+       if (pipe_ctx->stream_res.stream_enc == NULL) {
+               pipe_ctx->stream = NULL;
+               return;
+       }
+
+       /* DPMS may already disable or */
+       /* dpms_off status is incorrect due to fastboot
+        * feature. When system resume from S4 with second
+        * screen only, the dpms_off would be true but
+        * VBIOS lit up eDP, so check link status too.
+        */
+       if (!pipe_ctx->stream->dpms_off || link->link_status.link_active)
+               dc->link_srv->set_dpms_off(pipe_ctx);
+       else if (pipe_ctx->stream_res.audio)
+               dc->hwss.disable_audio_stream(pipe_ctx);
+
+       /* free acquired resources */
+       if (pipe_ctx->stream_res.audio) {
+               /*disable az_endpoint*/
+               pipe_ctx->stream_res.audio->funcs->az_disable(pipe_ctx->stream_res.audio);
+
+               /*free audio*/
+               if (dc->caps.dynamic_audio == true) {
+                       /*we have to dynamic arbitrate the audio endpoints*/
+                       /*we free the resource, need reset is_audio_acquired*/
+                       update_audio_usage(&dc->current_state->res_ctx, dc->res_pool,
+                                       pipe_ctx->stream_res.audio, false);
+                       pipe_ctx->stream_res.audio = NULL;
+               }
+       }
+
+       /* by upper caller loop, parent pipe: pipe0, will be reset last.
+        * back end share by all pipes and will be disable only when disable
+        * parent pipe.
+        */
+       if (pipe_ctx->top_pipe == NULL) {
+
+               dc->hwss.set_abm_immediate_disable(pipe_ctx);
+
+               pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg);
+
+               pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false);
+               if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass)
+                       pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
+                                       pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+
+               if (pipe_ctx->stream_res.tg->funcs->set_drr)
+                       pipe_ctx->stream_res.tg->funcs->set_drr(
+                                       pipe_ctx->stream_res.tg, NULL);
+               /* TODO - convert symclk_ref_cnts for otg to a bit map to solve
+                * the case where the same symclk is shared across multiple otg
+                * instances
+                */
+               if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
+                       link->phy_state.symclk_ref_cnts.otg = 0;
+               if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) {
+                       link_hwss->disable_link_output(link,
+                                       &pipe_ctx->link_res, pipe_ctx->stream->signal);
+                       link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+               }
+
+               /* reset DTBCLK_P */
+               if (dc->res_pool->dccg->funcs->set_dtbclk_p_src)
+                       dc->res_pool->dccg->funcs->set_dtbclk_p_src(dc->res_pool->dccg, REFCLK, pipe_ctx->stream_res.tg->inst);
+       }
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++)
+               if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx)
+                       break;
+
+       if (i == dc->res_pool->pipe_count)
+               return;
+
+/*
+ * In case of a dangling plane, setting this to NULL unconditionally
+ * causes failures during reset hw ctx where, if stream is NULL,
+ * it is expected that the pipe_ctx pointers to pipes and plane are NULL.
+ */
+       pipe_ctx->stream = NULL;
+       DC_LOG_DEBUG("Reset back end for pipe %d, tg:%d\n",
+                                       pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst);
+}
+
+void dcn401_reset_hw_ctx_wrap(
+               struct dc *dc,
+               struct dc_state *context)
+{
+       int i;
+       struct dce_hwseq *hws = dc->hwseq;
+
+       /* Reset Back End*/
+       for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
+               struct pipe_ctx *pipe_ctx_old =
+                       &dc->current_state->res_ctx.pipe_ctx[i];
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+               if (!pipe_ctx_old->stream)
+                       continue;
+
+               if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
+                       continue;
+
+               if (!pipe_ctx->stream ||
+                               pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) {
+                       struct clock_source *old_clk = pipe_ctx_old->clock_source;
+
+                       if (hws->funcs.reset_back_end_for_pipe)
+                               hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
+                       if (hws->funcs.enable_stream_gating)
+                               hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
+                       if (old_clk)
+                               old_clk->funcs->cs_power_down(old_clk);
+               }
+       }
+}
index e6692cd905d65758732449a4ac6a0df333384a41..66d679080c4498e9d65726ca705c79fa51aae8c4 100644 (file)
@@ -88,4 +88,11 @@ void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct
 void dcn401_wait_for_det_buffer_update_under_otg_master(struct dc *dc, struct dc_state *context, struct pipe_ctx *otg_master);
 void dcn401_interdependent_update_lock(struct dc *dc, struct dc_state *context, bool lock);
 void dcn401_program_outstanding_updates(struct dc *dc, struct dc_state *context);
+void dcn401_reset_back_end_for_pipe(
+               struct dc *dc,
+               struct pipe_ctx *pipe_ctx,
+               struct dc_state *context);
+void dcn401_reset_hw_ctx_wrap(
+               struct dc *dc,
+               struct dc_state *context);
 #endif /* __DC_HWSS_DCN401_H__ */
index d1128a8082a5eb420c838cfee4e3ee35584ccc45..af0d40a5cb77a3008bb495919308358695b3574a 100644 (file)
@@ -112,7 +112,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
        .power_down = dce110_power_down,
        .enable_display_power_gating = dcn10_dummy_display_power_gating,
        .blank_pixel_data = dcn20_blank_pixel_data,
-       .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap,
+       .reset_hw_ctx_wrap = dcn401_reset_hw_ctx_wrap,
        .enable_stream_timing = dcn401_enable_stream_timing,
        .edp_backlight_control = dce110_edp_backlight_control,
        .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
@@ -137,7 +137,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
        .update_mall_sel = dcn32_update_mall_sel,
        .calculate_dccg_k1_k2_values = NULL,
        .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
-       .reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe,
+       .reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe,
        .populate_mcm_luts = NULL,
 };