PERF_TRACE();
 }
+static void apply_symclk_on_tx_off_wa(struct dc_link *link)
+{
+       /* There are use cases where SYMCLK is referenced by OTG. For instance
+        * for TMDS signal, OTG relies SYMCLK even if TX video output is off.
+        * However current link interface will power off PHY when disabling link
+        * output. This will turn off SYMCLK generated by PHY. The workaround is
+        * to identify such case where SYMCLK is still in use by OTG when we
+        * power off PHY. When this is detected, we will temporarily power PHY
+        * back on and move PHY's SYMCLK state to SYMCLK_ON_TX_OFF by calling
+        * program_pix_clk interface. When OTG is disabled, we will then power
+        * off PHY by calling disable link output again.
+        *
+        * In future dcn generations, we plan to rework transmitter control
+        * interface so that we could have an option to set SYMCLK ON TX OFF
+        * state in one step without this workaround
+        */
+
+       struct dc *dc = link->ctx->dc;
+       struct pipe_ctx *pipe_ctx = NULL;
+       uint8_t i;
+
+       if (link->phy_state.symclk_ref_cnts.otg > 0) {
+               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,
+                                               dc->link_srv->dp_get_encoding_format(
+                                                               &pipe_ctx->link_config.dp_link_settings),
+                                               &pipe_ctx->pll_settings);
+                               link->phy_state.symclk_state = SYMCLK_ON_TX_OFF;
+                               break;
+                       }
+               }
+       }
+}
+
+void dcn314_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->dc->hwss.edp_backlight_control(link, false);
+       else if (dmcu != NULL && dmcu->funcs->lock_phy)
+               dmcu->funcs->lock_phy(dmcu);
+
+       link_hwss->disable_link_output(link, link_res, signal);
+       link->phy_state.symclk_state = SYMCLK_OFF_TX_OFF;
+       /*
+        * Add the logic to extract BOTH power up and power down sequences
+        * from enable/disable link output and only call edp panel control
+        * in enable_link_dp and disable_link_dp once.
+        */
+       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);
+
+       apply_symclk_on_tx_off_wa(link);
+}
 
        .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 = dce110_disable_link_output,
+       .disable_link_output = dcn314_disable_link_output,
        .z10_restore = dcn31_z10_restore,
        .z10_save_init = dcn31_z10_save_init,
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,