This reverts commit "Revert "Add DPCD writes at key points" ".
The following patch will fix the system hang issue.
v2: squash in indentation warning fix
Signed-off-by: Leo (Hanghong) Ma <hanghong.ma@amd.com>
Acked-by: Mikita Lipski <mikita.lipski@amd.com>
Reviewed-by: Aric Cyr <aric.cyr@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
 {
        struct dc *dc = pipe_ctx->stream->ctx->dc;
        struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->sink->link;
        enum dc_status status;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
                        stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
 #endif
 
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+
        if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
                pipe_ctx->stream_res.stream_enc->funcs->hdmi_set_stream_attribute(
                        pipe_ctx->stream_res.stream_enc,
                resource_build_info_frame(pipe_ctx);
                dc->hwss.update_info_frame(pipe_ctx);
 
+               if (dc_is_dp_signal(pipe_ctx->stream->signal))
+                       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
+
                /* Do not touch link on seamless boot optimization. */
                if (pipe_ctx->stream->apply_seamless_boot_optimization) {
                        pipe_ctx->stream->dpms_off = false;
 
        /* We need to do this before the link training to ensure the idle pattern in SST
         * mode will be sent right after the link training
         */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       if (dp_get_link_encoding_format(¤t_setting) == DP_8b_10b_ENCODING)
-#endif
+       if (dp_get_link_encoding_format(¤t_setting) == DP_8b_10b_ENCODING) {
                link_enc->funcs->connect_dig_be_to_fe(link_enc,
                                                        pipe_ctx->stream_res.stream_enc->id, true);
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
+       }
 
        for (j = 0; j < attempts; ++j) {
 
                         * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
                         */
                        /* Blank stream */
-                       pipes->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
+                       pipes->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
                }
 
                dp_set_hw_test_pattern(link, test_pattern,
 
                        sizeof(state));
 }
 
+void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
+{
+       if (link->dc->debug.enable_driver_sequence_debug)
+               core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
+                                       &dp_test_mode, sizeof(dp_test_mode));
+}
+
 void dp_enable_link_phy(
        struct dc_link *link,
        enum signal_type signal,
        if (dmcu != NULL && dmcu->funcs->unlock_phy)
                dmcu->funcs->unlock_phy(dmcu);
 
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
        dp_receiver_power_ctrl(link, true);
 }
 
                        dmcu->funcs->unlock_phy(dmcu);
        }
 
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+
        /* Clear current link setting.*/
        memset(&link->cur_link_settings, 0,
                        sizeof(link->cur_link_settings));
 #else
        encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
 #endif
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
 }
 #if defined(CONFIG_DRM_AMD_DC_DCN)
 #undef DC_LOGGER
                        pipes[i].stream->link == link) {
                        udelay(100);
 
-                       pipes[i].stream_res.stream_enc->funcs->dp_blank(
+                       pipes[i].stream_res.stream_enc->funcs->dp_blank(link,
                                        pipes[i].stream_res.stream_enc);
 
                        /* disable any test pattern that might be active */
 
        bool force_enable_edp_fec;
        /* FEC/PSR1 sequence enable delay in 100us */
        uint8_t fec_enable_delay_in100us;
+       bool enable_driver_sequence_debug;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        bool disable_z10;
        bool enable_sw_cntl_psr;
 
 }
 
 static void dce110_stream_encoder_dp_blank(
+       struct dc_link *link,
        struct stream_encoder *enc)
 {
        struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
 
 /* output video stream to link encoder */
 static void dce110_stream_encoder_dp_unblank(
+       struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param)
 {
 
 #include "audio.h"
 #include "reg_helper.h"
 #include "panel_cntl.h"
-
+#include "inc/link_dpcd.h"
+#include "dpcd_defs.h"
 /* include DCE11 register header files */
 #include "dce/dce_11_0_d.h"
 #include "dce/dce_11_0_sh_mask.h"
                if (pipe_ctx->stream_res.audio)
                        pipe_ctx->stream_res.audio->enabled = true;
        }
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM);
 }
 
 void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
                 * stream->stream_engine_id);
                 */
        }
+
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM);
 }
 
 void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
                        pipe_ctx->stream_res.stream_enc->id,
                        false);
 #endif
-
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
 }
 
 void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
        params.link_settings.link_rate = link_settings->link_rate;
 
        if (dc_is_dp_signal(pipe_ctx->stream->signal))
-               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms);
+               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
 
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
                hws->funcs.edp_backlight_control(link, true);
 #else
        if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
 #endif
-               pipe_ctx->stream_res.stream_enc->funcs->dp_blank(pipe_ctx->stream_res.stream_enc);
+               pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
 
                if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
                        /*
                struct dc *dc)
 {
        struct dc_stream_state *stream = pipe_ctx->stream;
+       struct dc_link *link = stream->link;
        struct drr_params params = {0};
        unsigned int event_triggers = 0;
        struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
                        pipe_ctx->stream_res.stream_enc,
                        pipe_ctx->stream_res.tg->inst);
 
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
+
        pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
                        pipe_ctx->stream_res.opp,
                        COLOR_SPACE_YCBCR601,
         * hurt for non-DP
         */
        for (i = 0; i < dc->res_pool->stream_enc_count; i++) {
-               dc->res_pool->stream_enc[i]->funcs->dp_blank(
+               dc->res_pool->stream_enc[i]->funcs->dp_blank(dc->links[i],
                                        dc->res_pool->stream_enc[i]);
        }
 
 
 
                                        for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
                                                if (fe == dc->res_pool->stream_enc[j]->id) {
-                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(
+                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i],
                                                                                dc->res_pool->stream_enc[j]);
                                                        break;
                                                }
        if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
                if (params.timing.pixel_encoding == PIXEL_ENCODING_YCBCR420)
                        params.timing.pix_clk_100hz /= 2;
-               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms);
+               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
        }
 
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
 
 #include "dcn10_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
+#include "inc/link_dpcd.h"
+#include "dpcd_defs.h"
 
 #define DC_LOGGER \
                enc1->base.ctx->logger
 }
 
 void enc1_stream_encoder_dp_blank(
+       struct dc_link *link,
        struct stream_encoder *enc)
 {
        struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
        /* disable DP stream */
        REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, 0);
 
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM);
+
        /* the encoder stops sending the video stream
         * at the start of the vertical blanking.
         * Poll for DP_VID_STREAM_STATUS == 0
         */
 
        REG_UPDATE(DP_STEER_FIFO, DP_STEER_FIFO_RESET, true);
+
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET);
 }
 
 /* output video stream to link encoder */
 void enc1_stream_encoder_dp_unblank(
+       struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param)
 {
         */
 
        REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
+
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
 }
 
 void enc1_stream_encoder_set_avmute(
 
        struct stream_encoder *enc);
 
 void enc1_stream_encoder_dp_blank(
+       struct dc_link *link,
        struct stream_encoder *enc);
 
 void enc1_stream_encoder_dp_unblank(
+       struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param);
 
 
 #include "dc_dmub_srv.h"
 #include "dce/dmub_hw_lock_mgr.h"
 #include "hw_sequencer.h"
+#include "inc/link_dpcd.h"
+#include "dpcd_defs.h"
 
 #define DC_LOGGER_INIT(logger)
 
                        params.timing.pix_clk_100hz /= 2;
                pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
                                pipe_ctx->stream_res.stream_enc, params.opp_cnt > 1);
-               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, ¶ms);
+               pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(link, pipe_ctx->stream_res.stream_enc, ¶ms);
        }
 
        if (link->local_sink && link->local_sink->sink_signal == SIGNAL_TYPE_EDP) {
                link->link_enc->funcs->connect_dig_be_to_fe(
                        link->link_enc, pipe_ctx->stream_res.stream_enc->id, true);
 
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
+
        if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
                if (link->dc->hwss.program_dmdata_engine)
                        link->dc->hwss.program_dmdata_engine(pipe_ctx);
 
        link->dc->hwss.update_info_frame(pipe_ctx);
 
+       if (dc_is_dp_signal(pipe_ctx->stream->signal))
+               dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
+
        /* enable early control to avoid corruption on DP monitor*/
        active_total_with_borders =
                        timing->h_addressable
 
 #include "dcn20_stream_encoder.h"
 #include "reg_helper.h"
 #include "hw_shared.h"
+#include "inc/link_dpcd.h"
+#include "dpcd_defs.h"
 
 #define DC_LOGGER \
                enc1->base.ctx->logger
 }
 
 void enc2_stream_encoder_dp_unblank(
+               struct dc_link *link,
                struct stream_encoder *enc,
                const struct encoder_unblank_param *param)
 {
         */
 
        REG_UPDATE(DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, true);
+
+       dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM);
 }
 
 static void enc2_dp_set_odm_combine(
 
        uint32_t enable_sdp_splitting);
 
 void enc2_stream_encoder_dp_unblank(
+       struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param);
 
 
 
                                        for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
                                                if (fe == dc->res_pool->stream_enc[j]->id) {
-                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(
+                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i],
                                                                                dc->res_pool->stream_enc[j]);
                                                        break;
                                                }
 
 
                                        for (j = 0; j < dc->res_pool->stream_enc_count; j++) {
                                                if (fe == dc->res_pool->stream_enc[j]->id) {
-                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(
+                                                       dc->res_pool->stream_enc[j]->funcs->dp_blank(dc->links[i],
                                                                                dc->res_pool->stream_enc[j]);
                                                        break;
                                                }
 
                struct stream_encoder *enc);
 
        void (*dp_blank)(
+               struct dc_link *link,
                struct stream_encoder *enc);
 
        void (*dp_unblank)(
+               struct dc_link *link,
                struct stream_encoder *enc,
                const struct encoder_unblank_param *param);
 
 
        const struct dc_link_settings *link_settings);
 
 void dp_receiver_power_ctrl(struct dc_link *link, bool on);
+void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
 void edp_add_delay_for_T9(struct dc_link *link);
 bool edp_receiver_ready_T9(struct dc_link *link);
 bool edp_receiver_ready_T7(struct dc_link *link);
 
        struct stream_encoder *enc) {}
 
 static void virtual_stream_encoder_dp_blank(
+       struct dc_link *link,
        struct stream_encoder *enc) {}
 
 static void virtual_stream_encoder_dp_unblank(
+       struct dc_link *link,
        struct stream_encoder *enc,
        const struct encoder_unblank_param *param) {}
 
 
        PSR_SINK_STATE_SINK_INTERNAL_ERROR = 7,
 };
 
+#define DP_SOURCE_SEQUENCE                 0x30c
 #define DP_SOURCE_TABLE_REVISION           0x310
 #define DP_SOURCE_PAYLOAD_SIZE             0x311
 #define DP_SOURCE_SINK_CAP                 0x317
 
        DP_PANEL_MODE_SPECIAL
 };
 
+enum dpcd_source_sequence {
+       DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG = 1, /*done in apply_single_controller_ctx_to_hw */
+       DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR,         /*done in core_link_enable_stream */
+       DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME,      /*done in core_link_enable_stream/dcn20_enable_stream */
+       DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE,      /*done in perform_link_training_with_retries/dcn20_enable_stream */
+       DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY,        /*done in dp_enable_link_phy */
+       DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN,     /*done in dp_set_hw_test_pattern */
+       DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM,    /*done in dce110_enable_audio_stream */
+       DPCD_SOURCE_SEQ_AFTER_ENABLE_DP_VID_STREAM,   /*done in enc1_stream_encoder_dp_unblank */
+       DPCD_SOURCE_SEQ_AFTER_DISABLE_DP_VID_STREAM,  /*done in enc1_stream_encoder_dp_blank */
+       DPCD_SOURCE_SEQ_AFTER_FIFO_STEER_RESET,       /*done in enc1_stream_encoder_dp_blank */
+       DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM,   /*done in dce110_disable_audio_stream */
+       DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY,       /*done in dp_disable_link_phy */
+       DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE,   /*done in dce110_disable_stream */
+};
+
 /* DPCD_ADDR_TRAINING_LANEx_SET registers value */
 union dpcd_training_lane_set {
        struct {