aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch')
-rw-r--r--common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch1341
1 files changed, 1341 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch b/common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch
new file mode 100644
index 00000000..c39b410d
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0680-drm-amd-dal-Refactor-Stream-Encoder-for-DCE8-11.patch
@@ -0,0 +1,1341 @@
+From 5e0ac3c9da50fb9f57d0f5992a8895eafece9e22 Mon Sep 17 00:00:00 2001
+From: Chris Park <Chris.Park@amd.com>
+Date: Thu, 7 Jan 2016 20:14:28 -0500
+Subject: [PATCH 0680/1110] drm/amd/dal: Refactor Stream Encoder for DCE8/11
+
+Signed-off-by: Chris Park <Chris.Park@amd.com>
+Acked-by: Jordan Lazare <Jordan.Lazare@amd.com>
+---
+ .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 27 +-
+ .../gpu/drm/amd/dal/dc/dce110/dce110_resource.c | 81 ++-
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.c | 805 +++++++++------------
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.h | 16 +-
+ drivers/gpu/drm/amd/dal/dc/inc/stream_encoder.h | 33 +
+ 5 files changed, 465 insertions(+), 497 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+index 685301b..0d8b050 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+@@ -633,11 +633,11 @@ static void update_bios_scratch_critical_state(struct adapter_service *as,
+ static void update_info_frame(struct core_stream *stream)
+ {
+ if (dc_is_hdmi_signal(stream->signal))
+- dce110_stream_encoder_update_hdmi_info_packets(
++ stream->stream_enc->funcs->update_hdmi_info_packets(
+ stream->stream_enc,
+ &stream->encoder_info_frame);
+ else if (dc_is_dp_signal(stream->signal))
+- dce110_stream_encoder_update_dp_info_packets(
++ stream->stream_enc->funcs->update_dp_info_packets(
+ stream->stream_enc,
+ &stream->encoder_info_frame);
+ }
+@@ -695,11 +695,11 @@ static void disable_stream(struct core_stream *stream)
+ struct core_link *link = stream->sink->link;
+
+ if (dc_is_hdmi_signal(stream->signal))
+- dce110_stream_encoder_stop_hdmi_info_packets(
++ stream->stream_enc->funcs->stop_hdmi_info_packets(
+ stream->stream_enc);
+
+ if (dc_is_dp_signal(stream->signal))
+- dce110_stream_encoder_stop_dp_info_packets(
++ stream->stream_enc->funcs->stop_dp_info_packets(
+ stream->stream_enc);
+
+ if (stream->audio) {
+@@ -716,7 +716,7 @@ static void disable_stream(struct core_stream *stream)
+
+ /* blank at encoder level */
+ if (dc_is_dp_signal(stream->signal))
+- dce110_stream_encoder_dp_blank(stream->stream_enc);
++ stream->stream_enc->funcs->dp_blank(stream->stream_enc);
+
+ dce110_link_encoder_connect_dig_be_to_fe(
+ link->link_enc,
+@@ -734,7 +734,7 @@ static void unblank_stream(struct core_stream *stream,
+ params.crtc_timing.pixel_clock =
+ stream->public.timing.pix_clk_khz;
+ params.link_settings.link_rate = link_settings->link_rate;
+- dce110_stream_encoder_dp_unblank(
++ stream->stream_enc->funcs->dp_unblank(
+ stream->stream_enc, &params);
+ }
+
+@@ -855,18 +855,18 @@ static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
+ stream->signal);
+
+ if (dc_is_dp_signal(stream->signal))
+- dce110_stream_encoder_dp_set_stream_attribute(
++ stream->stream_enc->funcs->dp_set_stream_attribute(
+ stream->stream_enc,
+ &stream->public.timing);
+
+ if (dc_is_hdmi_signal(stream->signal))
+- dce110_stream_encoder_hdmi_set_stream_attribute(
++ stream->stream_enc->funcs->hdmi_set_stream_attribute(
+ stream->stream_enc,
+ &stream->public.timing,
+ stream->audio != NULL);
+
+ if (dc_is_dvi_signal(stream->signal))
+- dce110_stream_encoder_dvi_set_stream_attribute(
++ stream->stream_enc->funcs->dvi_set_stream_attribute(
+ stream->stream_enc,
+ &stream->public.timing,
+ (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
+@@ -1728,6 +1728,13 @@ static void disable_vga(struct timing_generator *tg)
+ tg->funcs->disable_vga(tg);
+ }
+
++static void set_mst_bandwidth(struct stream_encoder *stream_enc,
++ struct fixed31_32 avg_time_slots_per_mtp)
++{
++ stream_enc->funcs->set_mst_bandwidth(stream_enc,
++ avg_time_slots_per_mtp);
++}
++
+ static const struct hw_sequencer_funcs dce110_funcs = {
+ .apply_ctx_to_hw = apply_ctx_to_hw,
+ .reset_hw_ctx = reset_hw_ctx,
+@@ -1767,7 +1774,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {
+ .enable_stream = enable_stream,
+ .disable_stream = disable_stream,
+ .update_mst_stream_allocation_table = dce110_link_encoder_update_mst_stream_allocation_table,
+- .set_mst_bandwidth = dce110_stream_encoder_set_mst_bandwidth
++ .set_mst_bandwidth = set_mst_bandwidth
+ };
+
+ bool dce110_hw_sequencer_construct(struct dc *dc)
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+index d7eea0d..266b761 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+@@ -51,32 +51,36 @@ enum dce110_clk_src_array_id {
+ };
+
+ static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = {
+- {
+- .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
+- },
+- {
+- .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
+- },
+- {
+- .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
+- },
+- {
+- .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL),
+- },
+- {
+- .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL),
+- },
+- {
+- .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL),
+- .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL),
+- }
++ {
++ .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL),
++ .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL),
++ },
++ {
++ .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL),
++ .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL),
++ },
++ {
++ .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL),
++ .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL),
++ }
++};
++
++static const struct dce110_stream_enc_offsets dce110_str_enc_offsets[] = {
++ {
++ .dig = (mmDIG0_DIG_FE_CNTL - mmDIG_FE_CNTL),
++ .dp = (mmDP0_DP_SEC_CNTL - mmDP_SEC_CNTL)
++ },
++ {
++ .dig = (mmDIG1_DIG_FE_CNTL - mmDIG_FE_CNTL),
++ .dp = (mmDP1_DP_SEC_CNTL - mmDP_SEC_CNTL)
++ },
++ {
++ .dig = (mmDIG2_DIG_FE_CNTL - mmDIG_FE_CNTL),
++ .dp = (mmDP2_DP_SEC_CNTL - mmDP_SEC_CNTL)
++ }
+ };
+
++
+ static struct timing_generator *dce110_timing_generator_create(
+ struct adapter_service *as,
+ struct dc_context *ctx,
+@@ -97,6 +101,26 @@ static struct timing_generator *dce110_timing_generator_create(
+ return NULL;
+ }
+
++static struct stream_encoder *dce110_stream_encoder_create(
++ enum engine_id eng_id,
++ struct dc_context *ctx,
++ struct bios_parser *bp,
++ const struct dce110_stream_enc_offsets *offsets)
++{
++ struct dce110_stream_encoder *enc110 =
++ dc_service_alloc(ctx, sizeof(struct dce110_stream_encoder));
++
++ if (!enc110)
++ return NULL;
++
++ if (dce110_stream_encoder_construct(enc110, ctx, bp, eng_id, offsets))
++ return &enc110->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, enc110);
++ return NULL;
++}
++
+ bool dce110_construct_resource_pool(
+ struct adapter_service *adapter_serv,
+ struct dc *dc,
+@@ -238,7 +262,8 @@ bool dce110_construct_resource_pool(
+ pool->stream_enc[i] = dce110_stream_encoder_create(
+ i, dc->ctx,
+ dal_adapter_service_get_bios_parser(
+- adapter_serv));
++ adapter_serv),
++ &dce110_str_enc_offsets[i]);
+ if (pool->stream_enc[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dal_error("DC: failed to create stream_encoder!\n");
+@@ -252,7 +277,8 @@ bool dce110_construct_resource_pool(
+ stream_enc_create_fail:
+ for (i = 0; i < pool->stream_enc_count; i++) {
+ if (pool->stream_enc[i] != NULL)
+- dce110_stream_encoder_destroy(&pool->stream_enc[i]);
++ dc_service_free(pool->stream_enc[i]->ctx,
++ DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+ }
+
+ audio_create_fail:
+@@ -321,7 +347,8 @@ void dce110_destruct_resource_pool(struct resource_pool *pool)
+
+ for (i = 0; i < pool->stream_enc_count; i++) {
+ if (pool->stream_enc[i] != NULL)
+- dce110_stream_encoder_destroy(&pool->stream_enc[i]);
++ dc_service_free(pool->stream_enc[i]->ctx,
++ DCE110STRENC_FROM_STRENC(pool->stream_enc[i]));
+ }
+
+ for (i = 0; i < pool->clk_src_count; i++) {
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
+index a07758f..81996f7 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
+@@ -30,25 +30,10 @@
+ #include "dce/dce_11_0_enum.h"
+
+ #define DIG_REG(reg)\
+- (reg + enc110->offsets.dig_offset)
++ (reg + enc110->offsets.dig)
+
+ #define DP_REG(reg)\
+- (reg + enc110->offsets.dp_offset)
+-
+-static const struct dce110_stream_enc_offsets reg_offsets[] = {
+-{
+- .dig_offset = (mmDIG0_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL),
+- .dp_offset = (mmDP0_DP_SEC_CNTL - mmDP0_DP_SEC_CNTL)
+-},
+-{
+- .dig_offset = (mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL),
+- .dp_offset = (mmDP1_DP_SEC_CNTL - mmDP0_DP_SEC_CNTL)
+-},
+-{
+- .dig_offset = (mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL),
+- .dp_offset = (mmDP2_DP_SEC_CNTL - mmDP0_DP_SEC_CNTL)
+-}
+-};
++ (reg + enc110->offsets.dig)
+
+ #define VBI_LINE_0 0
+ #define DP_BLANK_MAX_RETRY 20
+@@ -63,106 +48,30 @@ enum {
+ DP_MST_UPDATE_MAX_RETRY = 50
+ };
+
+-static void update_avi_info_packet(
+- struct dce110_stream_encoder *enc110,
+- const struct encoder_info_packet *info_packet)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t regval;
+- uint32_t addr;
+- uint32_t control0val;
+- uint32_t control1val;
+-
+- if (info_packet->valid) {
+- const uint32_t *content =
+- (const uint32_t *) &info_packet->sb[0];
+-
+- addr = DIG_REG(mmAFMT_AVI_INFO0);
+- regval = content[0];
+- dal_write_reg(
+- ctx,
+- addr,
+- regval);
+- regval = content[1];
+-
+- addr = DIG_REG(mmAFMT_AVI_INFO1);
+- dal_write_reg(
+- ctx,
+- addr,
+- regval);
+- regval = content[2];
+-
+- addr = DIG_REG(mmAFMT_AVI_INFO2);
+- dal_write_reg(
+- ctx,
+- addr,
+- regval);
+- regval = content[3];
+-
+- /* move version to AVI_INFO3 */
+- addr = DIG_REG(mmAFMT_AVI_INFO3);
+- set_reg_field_value(
+- regval,
+- info_packet->hb1,
+- AFMT_AVI_INFO3,
+- AFMT_AVI_INFO_VERSION);
+-
+- dal_write_reg(
+- ctx,
+- addr,
+- regval);
+-
+- addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL0);
+-
+- control0val = dal_read_reg(ctx, addr);
+-
+- set_reg_field_value(
+- control0val,
+- 1,
+- HDMI_INFOFRAME_CONTROL0,
+- HDMI_AVI_INFO_SEND);
+-
+- set_reg_field_value(
+- control0val,
+- 1,
+- HDMI_INFOFRAME_CONTROL0,
+- HDMI_AVI_INFO_CONT);
+-
+- dal_write_reg(ctx, addr, control0val);
+-
+- addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL1);
+-
+- control1val = dal_read_reg(ctx, addr);
+-
+- set_reg_field_value(
+- control1val,
+- VBI_LINE_0 + 2,
+- HDMI_INFOFRAME_CONTROL1,
+- HDMI_AVI_INFO_LINE);
+-
+- dal_write_reg(ctx, addr, control1val);
+- } else {
+- addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL0);
+-
+- regval = dal_read_reg(ctx, addr);
+-
+- set_reg_field_value(
+- regval,
+- 0,
+- HDMI_INFOFRAME_CONTROL0,
+- HDMI_AVI_INFO_SEND);
+-
+- set_reg_field_value(
+- regval,
+- 0,
+- HDMI_INFOFRAME_CONTROL0,
+- HDMI_AVI_INFO_CONT);
+-
+- dal_write_reg(ctx, addr, regval);
+- }
+-}
++static struct stream_encoder_funcs dce110_str_enc_funcs = {
++ .dp_set_stream_attribute =
++ dce110_stream_encoder_dp_set_stream_attribute,
++ .hdmi_set_stream_attribute =
++ dce110_stream_encoder_hdmi_set_stream_attribute,
++ .dvi_set_stream_attribute =
++ dce110_stream_encoder_dvi_set_stream_attribute,
++ .set_mst_bandwidth =
++ dce110_stream_encoder_set_mst_bandwidth,
++ .update_hdmi_info_packets =
++ dce110_stream_encoder_update_hdmi_info_packets,
++ .stop_hdmi_info_packets =
++ dce110_stream_encoder_stop_hdmi_info_packets,
++ .update_dp_info_packets =
++ dce110_stream_encoder_update_dp_info_packets,
++ .stop_dp_info_packets =
++ dce110_stream_encoder_stop_dp_info_packets,
++ .dp_blank =
++ dce110_stream_encoder_dp_blank,
++ .dp_unblank =
++ dce110_stream_encoder_dp_unblank,
++};
+
+-static void update_generic_info_packet(
++static void dce110_update_generic_info_packet(
+ struct dce110_stream_encoder *enc110,
+ uint32_t packet_index,
+ const struct encoder_info_packet *info_packet)
+@@ -266,7 +175,7 @@ static void update_generic_info_packet(
+ }
+ }
+
+-static void update_hdmi_info_packet(
++static void dce110_update_hdmi_info_packet(
+ struct dce110_stream_encoder *enc110,
+ uint32_t packet_index,
+ const struct encoder_info_packet *info_packet)
+@@ -277,7 +186,7 @@ static void update_hdmi_info_packet(
+ uint32_t regval;
+
+ if (info_packet->valid) {
+- update_generic_info_packet(
++ dce110_update_generic_info_packet(
+ enc110,
+ packet_index,
+ info_packet);
+@@ -370,215 +279,39 @@ static void update_hdmi_info_packet(
+ dal_write_reg(ctx, addr, regval);
+ }
+
+-static void update_dp_info_packet(
+- struct dce110_stream_encoder *enc110,
+- uint32_t packet_index,
+- const struct encoder_info_packet *info_packet)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t addr = DP_REG(mmDP_SEC_CNTL);
+-
+- uint32_t value;
+-
+- if (info_packet->valid)
+- update_generic_info_packet(
+- enc110,
+- packet_index,
+- info_packet);
+-
+- /* enable/disable transmission of packet(s).
+- * If enabled, packet transmission begins on the next frame */
+-
+- value = dal_read_reg(ctx, addr);
+-
+- switch (packet_index) {
+- case 0:
+- set_reg_field_value(
+- value,
+- info_packet->valid,
+- DP_SEC_CNTL,
+- DP_SEC_GSP0_ENABLE);
+- break;
+- case 1:
+- set_reg_field_value(
+- value,
+- info_packet->valid,
+- DP_SEC_CNTL,
+- DP_SEC_GSP1_ENABLE);
+- break;
+- case 2:
+- set_reg_field_value(
+- value,
+- info_packet->valid,
+- DP_SEC_CNTL,
+- DP_SEC_GSP2_ENABLE);
+- break;
+- case 3:
+- set_reg_field_value(
+- value,
+- info_packet->valid,
+- DP_SEC_CNTL,
+- DP_SEC_GSP3_ENABLE);
+- break;
+- default:
+- /* invalid HW packet index */
+- ASSERT_CRITICAL(false);
+- return;
+- }
+-
+- /* This bit is the master enable bit.
+- * When enabling secondary stream engine,
+- * this master bit must also be set.
+- * This register shared with audio info frame.
+- * Therefore we need to enable master bit
+- * if at least on of the fields is not 0 */
+-
+- if (value)
+- set_reg_field_value(
+- value,
+- 1,
+- DP_SEC_CNTL,
+- DP_SEC_STREAM_ENABLE);
+-
+- dal_write_reg(ctx, addr, value);
+-}
+-
+-static void dp_steer_fifo_reset(
+- struct dce110_stream_encoder *enc110,
+- bool reset)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- const uint32_t addr = DP_REG(mmDP_STEER_FIFO);
+-
+- uint32_t value = dal_read_reg(ctx, addr);
+-
+- set_reg_field_value(value, reset, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
+-
+- dal_write_reg(ctx, addr, value);
+-}
+-
+-static void unblank_dp_output(
+- struct dce110_stream_encoder *enc110)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t addr;
+- uint32_t value;
+-
+- /* set DIG_START to 0x1 to resync FIFO */
+- addr = DIG_REG(mmDIG_FE_CNTL);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(value, 1, DIG_FE_CNTL, DIG_START);
+- dal_write_reg(ctx, addr, value);
+-
+- /* switch DP encoder to CRTC data */
+- dp_steer_fifo_reset(enc110, false);
+-
+- /* wait 100us for DIG/DP logic to prime
+- * (i.e. a few video lines) */
+- dc_service_delay_in_microseconds(ctx, 100);
+-
+- /* the hardware would start sending video at the start of the next DP
+- * frame (i.e. rising edge of the vblank).
+- * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this
+- * register has no effect on enable transition! HW always guarantees
+- * VID_STREAM enable at start of next frame, and this is not
+- * programmable */
+- addr = DP_REG(mmDP_VID_STREAM_CNTL);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(
+- value,
+- true,
+- DP_VID_STREAM_CNTL,
+- DP_VID_STREAM_ENABLE);
+- dal_write_reg(ctx, addr, value);
+-
+-}
+-
+-static void setup_vid_stream(
+- struct dce110_stream_encoder *enc110,
+- uint32_t m_vid,
+- uint32_t n_vid)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t addr;
+- uint32_t value;
+-
+- /* enable auto measurement */
+- addr = DP_REG(mmDP_VID_TIMING);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(value, 0, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
+- dal_write_reg(ctx, addr, value);
+-
+- /* auto measurement need 1 full 0x8000 symbol cycle to kick in,
+- * therefore program initial value for Mvid and Nvid */
+- addr = DP_REG(mmDP_VID_N);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(value, n_vid, DP_VID_N, DP_VID_N);
+- dal_write_reg(ctx, addr, value);
+-
+- addr = DP_REG(mmDP_VID_M);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(value, m_vid, DP_VID_M, DP_VID_M);
+- dal_write_reg(ctx, addr, value);
+-
+- addr = DP_REG(mmDP_VID_TIMING);
+- value = dal_read_reg(ctx, addr);
+- set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
+- dal_write_reg(ctx, addr, value);
+-}
+-
+-static void set_tmds_stream_attributes(
++bool dce110_stream_encoder_construct(
+ struct dce110_stream_encoder *enc110,
+- const struct dc_crtc_timing *timing,
+- bool is_dvi
+- )
++ struct dc_context *ctx,
++ struct bios_parser *bp,
++ enum engine_id eng_id,
++ const struct dce110_stream_enc_offsets *offsets)
+ {
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t addr = DIG_REG(mmDIG_FE_CNTL);
+- uint32_t value = dal_read_reg(ctx, addr);
++ if (!enc110)
++ return false;
++ if (!bp)
++ return false;
+
+- switch (timing->pixel_encoding) {
+- case PIXEL_ENCODING_YCBCR422:
+- set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+- break;
+- default:
+- set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+- break;
+- }
++ enc110->base.funcs = &dce110_str_enc_funcs;
++ enc110->base.ctx = ctx;
++ enc110->base.id = eng_id;
++ enc110->base.bp = bp;
++ enc110->offsets = *offsets;
+
+- switch (timing->display_color_depth) {
+- case COLOR_DEPTH_101010:
+- if (is_dvi &&
+- timing->pixel_encoding == PIXEL_ENCODING_RGB)
+- set_reg_field_value(
+- value,
+- 2,
+- DIG_FE_CNTL,
+- TMDS_COLOR_FORMAT);
+- else
+- set_reg_field_value(
+- value,
+- 0,
+- DIG_FE_CNTL,
+- TMDS_COLOR_FORMAT);
+- break;
+- default:
+- set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
+- break;
+- }
+- dal_write_reg(ctx, addr, value);
++ return true;
+ }
+
+-static void set_dp_stream_attributes(
+- struct dce110_stream_encoder *enc110,
+- const struct dc_crtc_timing *timing)
++/* setup stream encoder in dp mode */
++void dce110_stream_encoder_dp_set_stream_attribute(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing)
+ {
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+ struct dc_context *ctx = enc110->base.ctx;
+ const uint32_t addr = DP_REG(mmDP_PIXEL_FORMAT);
+ uint32_t value = dal_read_reg(ctx, addr);
+
+ /* set pixel encoding */
+- switch (timing->pixel_encoding) {
++ switch (crtc_timing->pixel_encoding) {
+ case PIXEL_ENCODING_YCBCR422:
+ set_reg_field_value(
+ value,
+@@ -593,8 +326,8 @@ static void set_dp_stream_attributes(
+ DP_PIXEL_FORMAT,
+ DP_PIXEL_ENCODING);
+
+- if (timing->flags.Y_ONLY)
+- if (timing->display_color_depth != COLOR_DEPTH_666)
++ if (crtc_timing->flags.Y_ONLY)
++ if (crtc_timing->display_color_depth != COLOR_DEPTH_666)
+ /* HW testing only, no use case yet.
+ * Color depth of Y-only could be
+ * 8, 10, 12, 16 bits */
+@@ -619,7 +352,7 @@ static void set_dp_stream_attributes(
+
+ /* set color depth */
+
+- switch (timing->display_color_depth) {
++ switch (crtc_timing->display_color_depth) {
+ case COLOR_DEPTH_888:
+ set_reg_field_value(
+ value,
+@@ -642,30 +375,61 @@ static void set_dp_stream_attributes(
+ DP_COMPONENT_DEPTH);
+ break;
+ default:
+- set_reg_field_value(
+- value,
+- DP_COMPONENT_DEPTH_6BPC,
+- DP_PIXEL_FORMAT,
+- DP_COMPONENT_DEPTH);
++ set_reg_field_value(
++ value,
++ DP_COMPONENT_DEPTH_6BPC,
++ DP_PIXEL_FORMAT,
++ DP_COMPONENT_DEPTH);
++ break;
++ }
++
++ /* set dynamic range and YCbCr range */
++ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_DYN_RANGE);
++ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_YCBCR_RANGE);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++/* setup stream encoder in hdmi mode */
++void dce110_stream_encoder_hdmi_set_stream_attribute(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing,
++ bool enable_audio)
++{
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
++ struct dc_context *ctx = enc110->base.ctx;
++ uint32_t output_pixel_clock = crtc_timing->pix_clk_khz;
++ uint32_t value;
++ uint32_t addr;
++ struct bp_encoder_control cntl = {0};
++
++ cntl.action = ENCODER_CONTROL_SETUP;
++ cntl.engine_id = enc110->base.id;
++ cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
++ cntl.enable_dp_audio = enable_audio;
++ cntl.pixel_clock = crtc_timing->pix_clk_khz;
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.color_depth = crtc_timing->display_color_depth;
++
++ if (dal_bios_parser_encoder_control(
++ enc110->base.bp, &cntl) != BP_RESULT_OK)
++ return;
++
++ addr = DIG_REG(mmDIG_FE_CNTL);
++ value = dal_read_reg(ctx, addr);
++
++ switch (crtc_timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
++ break;
++ default:
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
+ break;
+ }
+-
+- /* set dynamic range and YCbCr range */
+- set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_DYN_RANGE);
+- set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_YCBCR_RANGE);
+-
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
+ dal_write_reg(ctx, addr, value);
+-}
+-
+-static void setup_hdmi(
+- struct dce110_stream_encoder *enc110,
+- const struct dc_crtc_timing *timing)
+-{
+- struct dc_context *ctx = enc110->base.ctx;
+- uint32_t output_pixel_clock = timing->pix_clk_khz;
+- uint32_t value;
+- uint32_t addr;
+
++ /* setup HDMI engine */
+ addr = DIG_REG(mmHDMI_CONTROL);
+ value = dal_read_reg(ctx, addr);
+ set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_PACKET_GEN_VERSION);
+@@ -674,7 +438,7 @@ static void setup_hdmi(
+ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN);
+ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_CLOCK_CHANNEL_RATE);
+
+- switch (timing->display_color_depth) {
++ switch (crtc_timing->display_color_depth) {
+ case COLOR_DEPTH_888:
+ set_reg_field_value(
+ value,
+@@ -693,7 +457,7 @@ static void setup_hdmi(
+ 1,
+ HDMI_CONTROL,
+ HDMI_DEEP_COLOR_ENABLE);
+- output_pixel_clock = (timing->pix_clk_khz * 30) / 24;
++ output_pixel_clock = (crtc_timing->pix_clk_khz * 30) / 24;
+ break;
+ case COLOR_DEPTH_121212:
+ set_reg_field_value(
+@@ -706,7 +470,7 @@ static void setup_hdmi(
+ 1,
+ HDMI_CONTROL,
+ HDMI_DEEP_COLOR_ENABLE);
+- output_pixel_clock = (timing->pix_clk_khz * 36) / 24;
++ output_pixel_clock = (crtc_timing->pix_clk_khz * 36) / 24;
+ break;
+ case COLOR_DEPTH_161616:
+ set_reg_field_value(
+@@ -719,7 +483,7 @@ static void setup_hdmi(
+ 1,
+ HDMI_CONTROL,
+ HDMI_DEEP_COLOR_ENABLE);
+- output_pixel_clock = (timing->pix_clk_khz * 48) / 24;
++ output_pixel_clock = (crtc_timing->pix_clk_khz * 48) / 24;
+ break;
+ default:
+ break;
+@@ -740,7 +504,7 @@ static void setup_hdmi(
+ 1,
+ HDMI_CONTROL,
+ HDMI_CLOCK_CHANNEL_RATE);
+- } else if (timing->flags.LTE_340MCSC_SCRAMBLE) {
++ } else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
+
+ /* TODO: New feature for DCE11, still need to implement */
+
+@@ -803,87 +567,6 @@ static void setup_hdmi(
+ value = dal_read_reg(ctx, addr);
+ set_reg_field_value(value, 0, HDMI_GC, HDMI_GC_AVMUTE);
+ dal_write_reg(ctx, addr, value);
+-
+-}
+-
+-static bool construct(
+- struct dce110_stream_encoder *enc110,
+- struct dc_context *ctx,
+- struct bios_parser *bp,
+- enum engine_id eng_id)
+-{
+- if (eng_id > ARRAY_SIZE(reg_offsets))
+- return false;
+-
+- enc110->base.ctx = ctx;
+- enc110->base.id = eng_id;
+- enc110->base.bp = bp;
+- enc110->offsets = reg_offsets[eng_id];
+-
+- return true;
+-}
+-
+-struct stream_encoder *dce110_stream_encoder_create(
+- enum engine_id eng_id,
+- struct dc_context *ctx,
+- struct bios_parser *bp)
+-{
+- struct dce110_stream_encoder *enc110 =
+- dc_service_alloc(ctx, sizeof(struct dce110_stream_encoder));
+-
+- if (!enc110)
+- return NULL;
+-
+- if (construct(enc110, ctx, bp, eng_id))
+- return &enc110->base;
+-
+- BREAK_TO_DEBUGGER();
+- dc_service_free(ctx, enc110);
+- return NULL;
+-}
+-
+-void dce110_stream_encoder_destroy(struct stream_encoder **enc)
+-{
+- dc_service_free((*enc)->ctx, TO_DCE110_STREAM_ENC(*enc));
+- *enc = NULL;
+-}
+-
+-/* setup stream encoder in dp mode */
+-void dce110_stream_encoder_dp_set_stream_attribute(
+- struct stream_encoder *enc,
+- struct dc_crtc_timing *crtc_timing)
+-{
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
+-
+- set_dp_stream_attributes(enc110, crtc_timing);
+-}
+-
+-/* setup stream encoder in hdmi mode */
+-void dce110_stream_encoder_hdmi_set_stream_attribute(
+- struct stream_encoder *enc,
+- struct dc_crtc_timing *crtc_timing,
+- bool enable_audio)
+-{
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
+- struct bp_encoder_control cntl = {0};
+-
+- cntl.action = ENCODER_CONTROL_SETUP;
+- cntl.engine_id = enc110->base.id;
+- cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
+- cntl.enable_dp_audio = enable_audio;
+- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+- cntl.lanes_number = LANE_COUNT_FOUR;
+- cntl.color_depth = crtc_timing->display_color_depth;
+-
+- if (dal_bios_parser_encoder_control(
+- enc->bp, &cntl) != BP_RESULT_OK)
+- return;
+-
+-
+- set_tmds_stream_attributes(enc110, crtc_timing, false);
+-
+- /* setup HDMI engine */
+- setup_hdmi(enc110, crtc_timing);
+ }
+
+ /* setup stream encoder in dvi mode */
+@@ -892,7 +575,10 @@ void dce110_stream_encoder_dvi_set_stream_attribute(
+ struct dc_crtc_timing *crtc_timing,
+ bool is_dual_link)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
++ struct dc_context *ctx = enc110->base.ctx;
++ uint32_t addr = DIG_REG(mmDIG_FE_CNTL);
++ uint32_t value = dal_read_reg(ctx, addr);
+ struct bp_encoder_control cntl = {0};
+
+ cntl.action = ENCODER_CONTROL_SETUP;
+@@ -910,14 +596,42 @@ void dce110_stream_encoder_dvi_set_stream_attribute(
+ enc110->base.bp, &cntl) != BP_RESULT_OK)
+ return;
+
+- set_tmds_stream_attributes(enc110, crtc_timing, true);
++ switch (crtc_timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
++ break;
++ default:
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
++ break;
++ }
++
++ switch (crtc_timing->display_color_depth) {
++ case COLOR_DEPTH_101010:
++ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
++ set_reg_field_value(
++ value,
++ 2,
++ DIG_FE_CNTL,
++ TMDS_COLOR_FORMAT);
++ else
++ set_reg_field_value(
++ value,
++ 0,
++ DIG_FE_CNTL,
++ TMDS_COLOR_FORMAT);
++ break;
++ default:
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
++ break;
++ }
++ dal_write_reg(ctx, addr, value);
+ }
+
+ void dce110_stream_encoder_set_mst_bandwidth(
+ struct stream_encoder *enc,
+ struct fixed31_32 avg_time_slots_per_mtp)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+ struct dc_context *ctx = enc110->base.ctx;
+ uint32_t addr;
+ uint32_t field;
+@@ -980,20 +694,110 @@ void dce110_stream_encoder_update_hdmi_info_packets(
+ struct stream_encoder *enc,
+ const struct encoder_info_frame *info_frame)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
+-
+- update_avi_info_packet(
+- enc110,
+- &info_frame->avi);
+- update_hdmi_info_packet(enc110, 0, &info_frame->vendor);
+- update_hdmi_info_packet(enc110, 1, &info_frame->gamut);
+- update_hdmi_info_packet(enc110, 2, &info_frame->spd);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
++ struct dc_context *ctx = enc110->base.ctx;
++ uint32_t regval;
++ uint32_t addr;
++ uint32_t control0val;
++ uint32_t control1val;
++
++ if (info_frame->avi.valid) {
++ const uint32_t *content =
++ (const uint32_t *) &info_frame->avi.sb[0];
++
++ addr = DIG_REG(mmAFMT_AVI_INFO0);
++ regval = content[0];
++ dal_write_reg(
++ ctx,
++ addr,
++ regval);
++ regval = content[1];
++
++ addr = DIG_REG(mmAFMT_AVI_INFO1);
++ dal_write_reg(
++ ctx,
++ addr,
++ regval);
++ regval = content[2];
++
++ addr = DIG_REG(mmAFMT_AVI_INFO2);
++ dal_write_reg(
++ ctx,
++ addr,
++ regval);
++ regval = content[3];
++
++ /* move version to AVI_INFO3 */
++ addr = DIG_REG(mmAFMT_AVI_INFO3);
++ set_reg_field_value(
++ regval,
++ info_frame->avi.hb1,
++ AFMT_AVI_INFO3,
++ AFMT_AVI_INFO_VERSION);
++
++ dal_write_reg(
++ ctx,
++ addr,
++ regval);
++
++ addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL0);
++
++ control0val = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ control0val,
++ 1,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_SEND);
++
++ set_reg_field_value(
++ control0val,
++ 1,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_CONT);
++
++ dal_write_reg(ctx, addr, control0val);
++
++ addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL1);
++
++ control1val = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ control1val,
++ VBI_LINE_0 + 2,
++ HDMI_INFOFRAME_CONTROL1,
++ HDMI_AVI_INFO_LINE);
++
++ dal_write_reg(ctx, addr, control1val);
++ } else {
++ addr = DIG_REG(mmHDMI_INFOFRAME_CONTROL0);
++
++ regval = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ regval,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_SEND);
++
++ set_reg_field_value(
++ regval,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_CONT);
++
++ dal_write_reg(ctx, addr, regval);
++ }
++
++ dce110_update_hdmi_info_packet(enc110, 0, &info_frame->vendor);
++ dce110_update_hdmi_info_packet(enc110, 1, &info_frame->gamut);
++ dce110_update_hdmi_info_packet(enc110, 2, &info_frame->spd);
+ }
+
+ void dce110_stream_encoder_stop_hdmi_info_packets(
+ struct stream_encoder *enc)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+ struct dc_context *ctx = enc110->base.ctx;
+ uint32_t addr = 0;
+ uint32_t value = 0;
+@@ -1096,16 +900,50 @@ void dce110_stream_encoder_update_dp_info_packets(
+ struct stream_encoder *enc,
+ const struct encoder_info_frame *info_frame)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
++ struct dc_context *ctx = enc110->base.ctx;
++ uint32_t addr = DP_REG(mmDP_SEC_CNTL);
++ uint32_t value;
++
++ if (info_frame->vsc.valid)
++ dce110_update_generic_info_packet(
++ enc110,
++ 0,
++ &info_frame->vsc);
++
++ /* enable/disable transmission of packet(s).
++ * If enabled, packet transmission begins on the next frame
++ */
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ info_frame->vsc.valid,
++ DP_SEC_CNTL,
++ DP_SEC_GSP0_ENABLE);
++ /* This bit is the master enable bit.
++ * When enabling secondary stream engine,
++ * this master bit must also be set.
++ * This register shared with audio info frame.
++ * Therefore we need to enable master bit
++ * if at least on of the fields is not 0
++ */
++ if (value)
++ set_reg_field_value(
++ value,
++ 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
+
+- update_dp_info_packet(enc110, 0, &info_frame->vsc);
++ dal_write_reg(ctx, addr, value);
+ }
+
+ void dce110_stream_encoder_stop_dp_info_packets(
+ struct stream_encoder *enc)
+ {
+ /* stop generic packets on DP */
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+ struct dc_context *ctx = enc110->base.ctx;
+ uint32_t addr = DP_REG(mmDP_SEC_CNTL);
+ uint32_t value = dal_read_reg(ctx, addr);
+@@ -1135,7 +973,7 @@ void dce110_stream_encoder_stop_dp_info_packets(
+ void dce110_stream_encoder_dp_blank(
+ struct stream_encoder *enc)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+ struct dc_context *ctx = enc110->base.ctx;
+ uint32_t addr = DP_REG(mmDP_VID_STREAM_CNTL);
+ uint32_t value = dal_read_reg(ctx, addr);
+@@ -1157,8 +995,9 @@ void dce110_stream_encoder_dp_blank(
+ DP_VID_STREAM_CNTL,
+ DP_VID_STREAM_DIS_DEFER);
+ /* Larger delay to wait until VBLANK - use max retry of
+- * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
+- * a little more because we may not trust delay accuracy. */
++ * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
++ * a little more because we may not trust delay accuracy.
++ */
+ max_retries = DP_BLANK_MAX_RETRY * 150;
+
+ /* disable DP stream */
+@@ -1166,8 +1005,9 @@ void dce110_stream_encoder_dp_blank(
+ dal_write_reg(ctx, addr, value);
+
+ /* the encoder stops sending the video stream
+- * at the start of the vertical blanking.
+- * Poll for DP_VID_STREAM_STATUS == 0 */
++ * at the start of the vertical blanking.
++ * Poll for DP_VID_STREAM_STATUS == 0
++ */
+
+ do {
+ value = dal_read_reg(ctx, addr);
+@@ -1186,10 +1026,14 @@ void dce110_stream_encoder_dp_blank(
+ ASSERT(retries <= max_retries);
+
+ /* Tell the DP encoder to ignore timing from CRTC, must be done after
+- * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
+- * complete, stream status will be stuck in video stream enabled state,
+- * i.e. DP_VID_STREAM_STATUS stuck at 1. */
+- dp_steer_fifo_reset(enc110, true);
++ * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
++ * complete, stream status will be stuck in video stream enabled state,
++ * i.e. DP_VID_STREAM_STATUS stuck at 1.
++ */
++ addr = DP_REG(mmDP_STEER_FIFO);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, true, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
++ dal_write_reg(ctx, addr, value);
+ }
+
+ /* output video stream to link encoder */
+@@ -1197,14 +1041,18 @@ void dce110_stream_encoder_dp_unblank(
+ struct stream_encoder *enc,
+ const struct encoder_unblank_param *param)
+ {
+- struct dce110_stream_encoder *enc110 = TO_DCE110_STREAM_ENC(enc);
++ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
++ struct dc_context *ctx = enc110->base.ctx;
++ uint32_t addr;
++ uint32_t value;
+
+ if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
+ uint32_t n_vid = 0x8000;
+ uint32_t m_vid;
+
+ /* M / N = Fstream / Flink
+- * m_vid / n_vid = pixel rate / link rate */
++ * m_vid / n_vid = pixel rate / link rate
++ */
+
+ uint64_t m_vid_l = n_vid;
+
+@@ -1215,9 +1063,62 @@ void dce110_stream_encoder_dp_unblank(
+
+ m_vid = (uint32_t) m_vid_l;
+
+- setup_vid_stream(enc110, m_vid, n_vid);
++ /* enable auto measurement */
++ addr = DP_REG(mmDP_VID_TIMING);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, 0, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
++ dal_write_reg(ctx, addr, value);
++
++ /* auto measurement need 1 full 0x8000 symbol cycle to kick in,
++ * therefore program initial value for Mvid and Nvid
++ */
++ addr = DP_REG(mmDP_VID_N);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, n_vid, DP_VID_N, DP_VID_N);
++ dal_write_reg(ctx, addr, value);
++
++ addr = DP_REG(mmDP_VID_M);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, m_vid, DP_VID_M, DP_VID_M);
++ dal_write_reg(ctx, addr, value);
++
++ addr = DP_REG(mmDP_VID_TIMING);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
++ dal_write_reg(ctx, addr, value);
+ }
+
+- unblank_dp_output(enc110);
++ /* set DIG_START to 0x1 to resync FIFO */
++ addr = DIG_REG(mmDIG_FE_CNTL);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, 1, DIG_FE_CNTL, DIG_START);
++ dal_write_reg(ctx, addr, value);
++
++ /* switch DP encoder to CRTC data */
++ addr = DP_REG(mmDP_STEER_FIFO);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(value, 0, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
++ dal_write_reg(ctx, addr, value);
++
++ /* wait 100us for DIG/DP logic to prime
++ * (i.e. a few video lines)
++ */
++ dc_service_delay_in_microseconds(ctx, 100);
++
++ /* the hardware would start sending video at the start of the next DP
++ * frame (i.e. rising edge of the vblank).
++ * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this
++ * register has no effect on enable transition! HW always guarantees
++ * VID_STREAM enable at start of next frame, and this is not
++ * programmable
++ */
++ addr = DP_REG(mmDP_VID_STREAM_CNTL);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ true,
++ DP_VID_STREAM_CNTL,
++ DP_VID_STREAM_ENABLE);
++ dal_write_reg(ctx, addr, value);
+ }
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
+index 8d859a9..200308c 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
+@@ -28,12 +28,12 @@
+
+ #include "inc/stream_encoder.h"
+
+-#define TO_DCE110_STREAM_ENC(stream_encoder)\
++#define DCE110STRENC_FROM_STRENC(stream_encoder)\
+ container_of(stream_encoder, struct dce110_stream_encoder, base)
+
+ struct dce110_stream_enc_offsets {
+- uint32_t dig_offset;
+- uint32_t dp_offset;
++ uint32_t dig;
++ uint32_t dp;
+ };
+
+ struct dce110_stream_encoder {
+@@ -41,12 +41,12 @@ struct dce110_stream_encoder {
+ struct dce110_stream_enc_offsets offsets;
+ };
+
+-struct stream_encoder *dce110_stream_encoder_create(
+- enum engine_id eng_id,
++bool dce110_stream_encoder_construct(
++ struct dce110_stream_encoder *enc110,
+ struct dc_context *ctx,
+- struct bios_parser *bp);
+-
+-void dce110_stream_encoder_destroy(struct stream_encoder **enc);
++ struct bios_parser *bp,
++ enum engine_id eng_id,
++ const struct dce110_stream_enc_offsets *offsets);
+
+ /***** HW programming ***********/
+ /* setup stream encoder in dp mode */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/stream_encoder.h b/drivers/gpu/drm/amd/dal/dc/inc/stream_encoder.h
+index d2da14a..25028b7 100644
+--- a/drivers/gpu/drm/amd/dal/dc/inc/stream_encoder.h
++++ b/drivers/gpu/drm/amd/dal/dc/inc/stream_encoder.h
+@@ -10,9 +10,42 @@
+ #include "include/bios_parser_interface.h"
+
+ struct stream_encoder {
++ struct stream_encoder_funcs *funcs;
+ struct dc_context *ctx;
+ struct bios_parser *bp;
+ enum engine_id id;
+ };
+
++struct stream_encoder_funcs {
++ void (*dp_set_stream_attribute)(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing);
++ void (*hdmi_set_stream_attribute)(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing,
++ bool enable_audio);
++ void (*dvi_set_stream_attribute)(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing,
++ bool is_dual_link);
++ void (*set_mst_bandwidth)(
++ struct stream_encoder *enc,
++ struct fixed31_32 avg_time_slots_per_mtp);
++ void (*update_hdmi_info_packets)(
++ struct stream_encoder *enc,
++ const struct encoder_info_frame *info_frame);
++ void (*stop_hdmi_info_packets)(
++ struct stream_encoder *enc);
++ void (*update_dp_info_packets)(
++ struct stream_encoder *enc,
++ const struct encoder_info_frame *info_frame);
++ void (*stop_dp_info_packets)(
++ struct stream_encoder *enc);
++ void (*dp_blank)(
++ struct stream_encoder *enc);
++ void (*dp_unblank)(
++ struct stream_encoder *enc,
++ const struct encoder_unblank_param *param);
++};
++
+ #endif /* STREAM_ENCODER_H_ */
+--
+2.7.4
+