]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/display: Adjust PHY FSM transition to TX_EN-to-PLL_ON for TMDS
authorRyan Seto <ryanseto@amd.com>
Fri, 13 Sep 2024 20:01:47 +0000 (16:01 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 1 Oct 2024 21:36:31 +0000 (17:36 -0400)
[Why]
If two monitors with TMDS signals were timing synced and one was
disconnected, the stream would go out of sync too early due to
the PLL turning off and the system could hang

[How]
On link disable output, change PHY FSM transition from TX_EN-to-PHY_OFF
to TX_EN-to-PLL_ON for TMDS

Reviewed-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Ryan Seto <ryanseto@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 0b889004509ad0977afa775c7b73a4ad6e688819..5babd53025aef474425df2a5e9917d3eec30c545 100644 (file)
@@ -805,33 +805,6 @@ static void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst
 {
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 
-       switch (link_enc_inst) {
-       case 0:
-               REG_UPDATE(SYMCLKA_CLOCK_ENABLE,
-                               SYMCLKA_CLOCK_ENABLE, 1);
-               if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
-                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, 1);
-               break;
-       case 1:
-               REG_UPDATE(SYMCLKB_CLOCK_ENABLE,
-                               SYMCLKB_CLOCK_ENABLE, 1);
-               if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
-                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, 1);
-               break;
-       case 2:
-               REG_UPDATE(SYMCLKC_CLOCK_ENABLE,
-                               SYMCLKC_CLOCK_ENABLE, 1);
-               if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
-                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, 1);
-               break;
-       case 3:
-               REG_UPDATE(SYMCLKD_CLOCK_ENABLE,
-                               SYMCLKD_CLOCK_ENABLE, 1);
-               if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
-                       REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, 1);
-               break;
-       }
-
        switch (stream_enc_inst) {
        case 0:
                REG_UPDATE_2(SYMCLKA_CLOCK_ENABLE,
@@ -864,37 +837,8 @@ static void dccg401_enable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst
        }
 }
 
-/*get other front end connected to this backend*/
-static uint8_t dccg401_get_number_enabled_symclk_fe_connected_to_be(struct dccg *dccg, uint32_t link_enc_inst)
-{
-       uint8_t num_enabled_symclk_fe = 0;
-       uint32_t fe_clk_en[4] = {0}, be_clk_sel[4] = {0};
-       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
-       uint8_t i;
-
-       REG_GET_2(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, &fe_clk_en[0],
-                       SYMCLKA_FE_SRC_SEL, &be_clk_sel[0]);
-
-       REG_GET_2(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, &fe_clk_en[1],
-                       SYMCLKB_FE_SRC_SEL, &be_clk_sel[1]);
-
-       REG_GET_2(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, &fe_clk_en[2],
-                       SYMCLKC_FE_SRC_SEL, &be_clk_sel[2]);
-
-       REG_GET_2(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, &fe_clk_en[3],
-                       SYMCLKD_FE_SRC_SEL, &be_clk_sel[3]);
-
-       for (i = 0; i < ARRAY_SIZE(fe_clk_en); i++) {
-               if (fe_clk_en[i] && be_clk_sel[i] == link_enc_inst)
-                       num_enabled_symclk_fe++;
-       }
-
-       return num_enabled_symclk_fe;
-}
-
 static void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_inst, uint32_t link_enc_inst)
 {
-       uint8_t num_enabled_symclk_fe = 0;
        struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
 
        switch (stream_enc_inst) {
@@ -919,31 +863,6 @@ static void dccg401_disable_symclk_se(struct dccg *dccg, uint32_t stream_enc_ins
                                SYMCLKD_FE_SRC_SEL, 0);
                break;
        }
-
-       /*check other enabled symclk fe connected to this be */
-       num_enabled_symclk_fe = dccg401_get_number_enabled_symclk_fe_connected_to_be(dccg, link_enc_inst);
-       /*only turn off backend clk if other front ends attached to this backend are all off,
-        for mst, only turn off the backend if this is the last front end*/
-       if (num_enabled_symclk_fe == 0) {
-               switch (link_enc_inst) {
-               case 0:
-                       REG_UPDATE(SYMCLKA_CLOCK_ENABLE,
-                                       SYMCLKA_CLOCK_ENABLE, 0);
-                       break;
-               case 1:
-                       REG_UPDATE(SYMCLKB_CLOCK_ENABLE,
-                                       SYMCLKB_CLOCK_ENABLE, 0);
-                       break;
-               case 2:
-                       REG_UPDATE(SYMCLKC_CLOCK_ENABLE,
-                                       SYMCLKC_CLOCK_ENABLE, 0);
-                       break;
-               case 3:
-                       REG_UPDATE(SYMCLKD_CLOCK_ENABLE,
-                                       SYMCLKD_CLOCK_ENABLE, 0);
-                       break;
-               }
-       }
 }
 
 static const struct dccg_funcs dccg401_funcs = {
index 805e7b52df29d12d5bccc8dacb425b4884b33c06..b690f0565d285d8fcf8b875d6c142d02c5ebc496 100644 (file)
@@ -1097,6 +1097,58 @@ void adjust_hotspot_between_slices_for_2x_magnify(uint32_t cursor_width, struct
        }
 }
 
+static void disable_link_output_symclk_on_tx_off(struct dc_link *link, enum dp_link_encoding link_encoding)
+{
+       struct dc *dc = link->ctx->dc;
+       struct pipe_ctx *pipe_ctx = NULL;
+       uint8_t i;
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
+               if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
+                       pipe_ctx->clock_source->funcs->program_pix_clk(
+                                       pipe_ctx->clock_source,
+                                       &pipe_ctx->stream_res.pix_clk_params,
+                                       link_encoding,
+                                       &pipe_ctx->pll_settings);
+                       break;
+               }
+       }
+}
+
+void dcn401_disable_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal)
+{
+       struct dc *dc = link->ctx->dc;
+       const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+       struct dmcu *dmcu = dc->res_pool->dmcu;
+
+       if (signal == SIGNAL_TYPE_EDP &&
+                       link->dc->hwss.edp_backlight_control &&
+                       !link->skip_implict_edp_power_control)
+               link->dc->hwss.edp_backlight_control(link, false);
+       else if (dmcu != NULL && dmcu->funcs->lock_phy)
+               dmcu->funcs->lock_phy(dmcu);
+
+       if (dc_is_tmds_signal(signal) && link->phy_state.symclk_ref_cnts.otg > 0) {
+               disable_link_output_symclk_on_tx_off(link, DP_UNKNOWN_ENCODING);
+               link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
+       } else {
+               link_hwss->disable_link_output(link, link_res, signal);
+               link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+       }
+
+       if (signal == SIGNAL_TYPE_EDP &&
+                       link->dc->hwss.edp_backlight_control &&
+                       !link->skip_implict_edp_power_control)
+               link->dc->hwss.edp_power_control(link, false);
+       else if (dmcu != NULL && dmcu->funcs->lock_phy)
+               dmcu->funcs->unlock_phy(dmcu);
+
+       dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+}
+
 void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx)
 {
        struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
index 1e8189bb447e4dc97469ef0d72421b25a0adced0..e6692cd905d65758732449a4ac6a0df333384a41 100644 (file)
@@ -55,6 +55,10 @@ void dcn401_populate_mcm_luts(struct dc *dc,
                bool lut_bank_a);
 void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable);
 
+void dcn401_disable_link_output(struct dc_link *link,
+               const struct link_resource *link_res,
+               enum signal_type signal);
+
 void dcn401_set_cursor_position(struct pipe_ctx *pipe_ctx);
 
 bool dcn401_apply_idle_power_optimizations(struct dc *dc, bool enable);
index 73a632b5ff89328d7f922114f85a4a610c5e42d4..d1128a8082a5eb420c838cfee4e3ee35584ccc45 100644 (file)
@@ -84,7 +84,7 @@ static const struct hw_sequencer_funcs dcn401_funcs = {
        .enable_lvds_link_output = dce110_enable_lvds_link_output,
        .enable_tmds_link_output = dce110_enable_tmds_link_output,
        .enable_dp_link_output = dce110_enable_dp_link_output,
-       .disable_link_output = dcn32_disable_link_output,
+       .disable_link_output = dcn401_disable_link_output,
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
        .get_dcc_en_bits = dcn10_get_dcc_en_bits,
        .enable_phantom_streams = dcn32_enable_phantom_streams,