aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch')
-rw-r--r--common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch1691
1 files changed, 1691 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch b/common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch
new file mode 100644
index 00000000..5f22ada6
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0518-drm-amd-dal-Reorganize-link-encoder-and-stream-encod.patch
@@ -0,0 +1,1691 @@
+From 2e6975280175f40d209cc2e86c1141a9a61fe23b Mon Sep 17 00:00:00 2001
+From: Chris Park <Chris.Park@amd.com>
+Date: Wed, 25 Nov 2015 11:14:09 -0500
+Subject: [PATCH 0518/1110] drm/amd/dal: Reorganize link encoder and stream
+ encoder interface function order
+
+Part of link encoder & stream encoder clean-up. No functionality change.
+
+Signed-off-by: Chris Park <Chris.Park@amd.com>
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Acked-by: Harry Wentland <harry.wentland@amd.com>
+---
+ .../drm/amd/dal/dc/dce110/dce110_link_encoder.c | 1103 ++++++++++----------
+ .../drm/amd/dal/dc/dce110/dce110_link_encoder.h | 41 +-
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.c | 335 +++---
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.h | 18 +-
+ 4 files changed, 750 insertions(+), 747 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
+index 0297bd3..9817318 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
+@@ -461,45 +461,6 @@ static void set_dp_phy_pattern_80bit_custom(
+ enable_phy_bypass_mode(ctx, be_addr_offset, true);
+ }
+
+-void dce110_link_encoder_setup(
+- struct link_encoder *enc,
+- enum signal_type signal)
+-{
+- const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
+- uint32_t value = dal_read_reg(enc->ctx, addr);
+-
+- switch (signal) {
+- case SIGNAL_TYPE_EDP:
+- case SIGNAL_TYPE_DISPLAY_PORT:
+- /* DP SST */
+- set_reg_field_value(value, 0, DIG_BE_CNTL, DIG_MODE);
+- break;
+- case SIGNAL_TYPE_LVDS:
+- /* LVDS */
+- set_reg_field_value(value, 1, DIG_BE_CNTL, DIG_MODE);
+- break;
+- case SIGNAL_TYPE_DVI_SINGLE_LINK:
+- case SIGNAL_TYPE_DVI_DUAL_LINK:
+- /* TMDS-DVI */
+- set_reg_field_value(value, 2, DIG_BE_CNTL, DIG_MODE);
+- break;
+- case SIGNAL_TYPE_HDMI_TYPE_A:
+- /* TMDS-HDMI */
+- set_reg_field_value(value, 3, DIG_BE_CNTL, DIG_MODE);
+- break;
+- case SIGNAL_TYPE_DISPLAY_PORT_MST:
+- /* DP MST */
+- set_reg_field_value(value, 5, DIG_BE_CNTL, DIG_MODE);
+- break;
+- default:
+- ASSERT_CRITICAL(false);
+- /* invalid mode ! */
+- break;
+- }
+-
+- dal_write_reg(enc->ctx, addr, value);
+-}
+-
+ static void set_dp_phy_pattern_hbr2_compliance(
+ struct link_encoder *enc,
+ const int32_t be_addr_offset)
+@@ -751,137 +712,6 @@ static void construct(
+ FEATURE_SUPPORT_DP_YUV);
+ }
+
+-struct link_encoder *dce110_link_encoder_create(
+- const struct encoder_init_data *init)
+-{
+- struct link_encoder *enc =
+- dc_service_alloc(init->ctx, sizeof(struct link_encoder));
+-
+- if (!enc)
+- goto enc_create_fail;
+-
+- construct(enc, init);
+-
+- return enc;
+-
+-enc_create_fail:
+- return NULL;
+-}
+-
+-void dce110_link_encoder_destroy(struct link_encoder **enc)
+-{
+- struct link_encoder *encoder = *enc;
+- dc_service_free(encoder->ctx, encoder);
+- *enc = NULL;
+-}
+-
+-void dce110_link_encoder_set_dp_phy_pattern(
+- struct link_encoder *enc,
+- const struct encoder_set_dp_phy_pattern_param *param)
+-{
+- const int32_t offset = enc->be_engine_offset;
+-
+-
+- switch (param->dp_phy_pattern) {
+- case DP_TEST_PATTERN_TRAINING_PATTERN1:
+- set_dp_phy_pattern_training_pattern(enc->ctx,
+- offset, 0);
+- break;
+- case DP_TEST_PATTERN_TRAINING_PATTERN2:
+- set_dp_phy_pattern_training_pattern(enc->ctx,
+- offset, 1);
+- break;
+- case DP_TEST_PATTERN_TRAINING_PATTERN3:
+- set_dp_phy_pattern_training_pattern(enc->ctx,
+- offset, 2);
+- break;
+- case DP_TEST_PATTERN_D102:
+- set_dp_phy_pattern_d102(enc->ctx, offset);
+- break;
+- case DP_TEST_PATTERN_SYMBOL_ERROR:
+- set_dp_phy_pattern_symbol_error(enc->ctx, offset);
+- break;
+- case DP_TEST_PATTERN_PRBS7:
+- set_dp_phy_pattern_prbs7(enc->ctx, offset);
+- break;
+- case DP_TEST_PATTERN_80BIT_CUSTOM:
+- set_dp_phy_pattern_80bit_custom(
+- enc->ctx,
+- offset, param->custom_pattern);
+- break;
+- case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
+- set_dp_phy_pattern_hbr2_compliance(
+- enc, offset);
+- break;
+- case DP_TEST_PATTERN_VIDEO_MODE: {
+- set_dp_phy_pattern_passthrough_mode(
+- enc->ctx,
+- offset,
+- param->dp_panel_mode);
+- break;
+- }
+-
+-
+- default:
+- /* invalid phy pattern */
+- ASSERT_CRITICAL(false);
+- break;
+- }
+-}
+-
+-enum encoder_result dce110_link_encoder_dp_set_lane_settings(
+- struct link_encoder *enc,
+- const struct link_training_settings *link_settings)
+-{
+- union dpcd_training_lane_set training_lane_set = { { 0 } };
+-
+- int32_t lane = 0;
+-
+- struct bp_transmitter_control cntl = { 0 };
+-
+- if (!link_settings) {
+- BREAK_TO_DEBUGGER();
+- return ENCODER_RESULT_ERROR;
+- }
+-
+- cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
+- cntl.transmitter = enc->transmitter;
+- cntl.connector_obj_id = enc->connector;
+- cntl.lanes_number = link_settings->link_settings.lane_count;
+- cntl.hpd_sel = enc->hpd_source;
+- cntl.pixel_clock = link_settings->link_settings.link_rate *
+- LINK_RATE_REF_FREQ_IN_KHZ;
+-
+- for (lane = 0; lane < link_settings->link_settings.lane_count; ++lane) {
+- /* translate lane settings */
+-
+- training_lane_set.bits.VOLTAGE_SWING_SET =
+- link_settings->lane_settings[lane].VOLTAGE_SWING;
+- training_lane_set.bits.PRE_EMPHASIS_SET =
+- link_settings->lane_settings[lane].PRE_EMPHASIS;
+-
+- /* post cursor 2 setting only applies to HBR2 link rate */
+- if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
+- /* this is passed to VBIOS
+- * to program post cursor 2 level */
+-
+- training_lane_set.bits.POST_CURSOR2_SET =
+- link_settings->lane_settings[lane].POST_CURSOR2;
+- }
+-
+- cntl.lane_select = lane;
+- cntl.lane_settings = training_lane_set.raw;
+-
+- /* call VBIOS table to set voltage swing and pre-emphasis */
+-
+- dal_bios_parser_transmitter_control(
+- dal_adapter_service_get_bios_parser(
+- enc->adapter_service), &cntl);
+- }
+-
+- return ENCODER_RESULT_OK;
+-}
+-
+ /* return value is bit-vector */
+ static uint8_t get_frontend_source(
+ enum engine_id engine)
+@@ -1167,72 +997,6 @@ static enum encoder_result link_encoder_edp_backlight_control(
+ return ENCODER_RESULT_OK;
+ }
+
+-/*
+- * @brief
+- * Configure digital transmitter and enable both encoder and transmitter
+- * Actual output will be available after calling unblank()
+- */
+-enum encoder_result dce110_link_encoder_enable_output(
+- struct link_encoder *enc,
+- const struct link_settings *link_settings,
+- enum engine_id engine,
+- enum clock_source_id clock_source,
+- enum signal_type signal,
+- enum dc_color_depth color_depth,
+- uint32_t pixel_clock)
+-{
+- struct bp_transmitter_control cntl = { 0 };
+-
+- if (enc->connector.id == CONNECTOR_ID_EDP) {
+- /* power up eDP panel */
+-
+- link_encoder_edp_power_control(
+- enc, true);
+-
+- link_encoder_edp_wait_for_hpd_ready(
+- enc, enc->connector, true);
+-
+- /* have to turn off the backlight
+- * before power down eDP panel */
+- link_encoder_edp_backlight_control(
+- enc, true);
+- }
+-
+- /* Enable the PHY */
+-
+- /* number_of_lanes is used for pixel clock adjust,
+- * but it's not passed to asic_control.
+- * We need to set number of lanes manually. */
+- if (dc_is_dp_signal(signal))
+- configure_encoder(enc, engine, link_settings);
+-
+- cntl.action = TRANSMITTER_CONTROL_ENABLE;
+- cntl.engine_id = engine;
+- cntl.transmitter = enc->transmitter;
+- cntl.pll_id = clock_source;
+- cntl.signal = signal;
+- cntl.lanes_number = link_settings->lane_count;
+- cntl.hpd_sel = enc->hpd_source;
+- if (dc_is_dp_signal(signal))
+- cntl.pixel_clock = link_settings->link_rate
+- * LINK_RATE_REF_FREQ_IN_KHZ;
+- else
+- cntl.pixel_clock = pixel_clock;
+- cntl.color_depth = color_depth;
+-
+- if (DELAY_AFTER_PIXEL_FORMAT_CHANGE)
+- dc_service_sleep_in_milliseconds(
+- enc->ctx,
+- DELAY_AFTER_PIXEL_FORMAT_CHANGE);
+-
+- dal_bios_parser_transmitter_control(
+- dal_adapter_service_get_bios_parser(
+- enc->adapter_service),
+- &cntl);
+-
+- return ENCODER_RESULT_OK;
+-}
+-
+ static bool is_dig_enabled(const struct link_encoder *link_enc)
+ {
+ uint32_t value;
+@@ -1268,141 +1032,18 @@ static void link_encoder_disable(struct link_encoder *link_enc)
+ dal_write_reg(link_enc->ctx, addr, value);
+ }
+
+-/*
+- * @brief
+- * Disable transmitter and its encoder
+- */
+-enum encoder_result dce110_link_encoder_disable_output(
+- struct link_encoder *link_enc,
+- enum signal_type signal)
++static void hpd_initialize(
++ struct link_encoder *enc,
++ enum hpd_source_id hpd_source)
+ {
+- struct bp_transmitter_control cntl = { 0 };
+-
+- if (link_enc->connector.id == CONNECTOR_ID_EDP) {
+- /* have to turn off the backlight
+- * before power down eDP panel */
+- link_encoder_edp_backlight_control(
+- link_enc, false);
+- }
+-
+- if (!is_dig_enabled(link_enc) &&
+- dal_adapter_service_should_optimize(link_enc->adapter_service,
+- OF_SKIP_POWER_DOWN_INACTIVE_ENCODER)) {
+- return ENCODER_RESULT_OK;
+- }
+- /* Power-down RX and disable GPU PHY should be paired.
+- * Disabling PHY without powering down RX may cause
+- * symbol lock loss, on which we will get DP Sink interrupt. */
+-
+- /* There is a case for the DP active dongles
+- * where we want to disable the PHY but keep RX powered,
+- * for those we need to ignore DP Sink interrupt
+- * by checking lane count that has been set
+- * on the last do_enable_output(). */
+-
+- /* disable transmitter */
+- cntl.action = TRANSMITTER_CONTROL_DISABLE;
+- cntl.transmitter = link_enc->transmitter;
+- cntl.hpd_sel = link_enc->hpd_source;
+- cntl.signal = signal;
+- cntl.connector_obj_id = link_enc->connector;
+-
+- dal_bios_parser_transmitter_control(
+- dal_adapter_service_get_bios_parser(
+- link_enc->adapter_service), &cntl);
+-
+- /* disable encoder */
+- if (dc_is_dp_signal(signal))
+- link_encoder_disable(link_enc);
+-
+- if (link_enc->connector.id == CONNECTOR_ID_EDP) {
+- /* power down eDP panel */
+- /* TODO: Power control cause regression, we should implement
+- * it properly, for now just comment it.
+- *
+- * link_encoder_edp_wait_for_hpd_ready(
+- link_enc,
+- link_enc->connector,
+- false);
+-
+- * link_encoder_edp_power_control(
+- link_enc, false); */
+- }
+-
+- return ENCODER_RESULT_OK;
+-}
+-
+-static void hpd_initialize(
+- struct link_encoder *enc,
+- enum hpd_source_id hpd_source)
+-{
+- /* Associate HPD with DIG_BE */
+- const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
+- uint32_t value = dal_read_reg(enc->ctx, addr);
++ /* Associate HPD with DIG_BE */
++ const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
++ uint32_t value = dal_read_reg(enc->ctx, addr);
+
+ set_reg_field_value(value, hpd_source, DIG_BE_CNTL, DIG_HPD_SELECT);
+ dal_write_reg(enc->ctx, addr, value);
+ }
+
+-enum encoder_result dce110_link_encoder_power_up(
+- struct link_encoder *enc)
+-{
+- struct bp_transmitter_control cntl = { 0 };
+-
+- enum bp_result result;
+-
+- cntl.action = TRANSMITTER_CONTROL_INIT;
+- cntl.engine_id = ENGINE_ID_UNKNOWN;
+- cntl.transmitter = enc->transmitter;
+- cntl.connector_obj_id = enc->connector;
+- cntl.lanes_number = LANE_COUNT_FOUR;
+- cntl.coherent = false;
+- cntl.hpd_sel = enc->hpd_source;
+-
+- result = dal_bios_parser_transmitter_control(
+- dal_adapter_service_get_bios_parser(
+- enc->adapter_service),
+- &cntl);
+-
+- if (result != BP_RESULT_OK) {
+- dal_logger_write(enc->ctx->logger,
+- LOG_MAJOR_ERROR,
+- LOG_MINOR_COMPONENT_ENCODER,
+- "%s: Failed to execute VBIOS command table!\n",
+- __func__);
+- BREAK_TO_DEBUGGER();
+- return ENCODER_RESULT_ERROR;
+- }
+-
+- if (enc->connector.id == CONNECTOR_ID_LVDS) {
+- cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS;
+-
+- result = dal_bios_parser_transmitter_control(
+- dal_adapter_service_get_bios_parser(
+- enc->adapter_service),
+- &cntl);
+- ASSERT(result == BP_RESULT_OK);
+-
+- } else if (enc->connector.id == CONNECTOR_ID_EDP) {
+- link_encoder_edp_power_control(enc, true);
+-
+- link_encoder_edp_wait_for_hpd_ready(
+- enc, enc->connector, true);
+-
+- }
+- aux_initialize(enc, enc->hpd_source);
+-
+- /* reinitialize HPD.
+- * hpd_initialize() will pass DIG_FE id to HW context.
+- * All other routine within HW context will use fe_engine_offset
+- * as DIG_FE id even caller pass DIG_FE id.
+- * So this routine must be called first. */
+- hpd_initialize(enc, enc->hpd_source);
+-
+- return ENCODER_RESULT_OK;
+-}
+-
+-
+ static bool validate_dvi_output(
+ const struct link_encoder *enc,
+ enum signal_type connector_signal,
+@@ -1569,6 +1210,31 @@ static bool validate_wireless_output(
+ return false;
+ }
+
++struct link_encoder *dce110_link_encoder_create(
++ const struct encoder_init_data *init)
++{
++ struct link_encoder *enc =
++ dc_service_alloc(init->ctx, sizeof(struct link_encoder));
++
++ if (!enc)
++ goto enc_create_fail;
++
++ construct(enc, init);
++
++ return enc;
++
++enc_create_fail:
++ return NULL;
++}
++
++void dce110_link_encoder_destroy(struct link_encoder **enc)
++{
++ struct link_encoder *encoder = *enc;
++
++ dc_service_free(encoder->ctx, encoder);
++ *enc = NULL;
++}
++
+ enum encoder_result dce110_link_encoder_validate_output_with_stream(
+ struct link_encoder *enc,
+ const struct core_stream *stream)
+@@ -1614,84 +1280,540 @@ enum encoder_result dce110_link_encoder_validate_output_with_stream(
+ return is_valid ? ENCODER_RESULT_OK : ENCODER_RESULT_ERROR;
+ }
+
+-/*
+- * get_supported_stream_engines
+- *
+- * @brief
+- * get a list of supported engine
+- *
+- * @param
+- * const struct encoder_impl *enc - not used.
+- *
+- * @return
+- * list of engines with supported ones enabled.
+- */
+-union supported_stream_engines dce110_get_supported_stream_engines(
+- const struct link_encoder *enc)
++enum encoder_result dce110_link_encoder_power_up(
++ struct link_encoder *enc)
+ {
+- union supported_stream_engines result = {.u_all = 0};
+-
+- result.engine.ENGINE_ID_DIGA = 1;
+- result.engine.ENGINE_ID_DIGB = 1;
+- result.engine.ENGINE_ID_DIGC = 1;
++ struct bp_transmitter_control cntl = { 0 };
+
+- if (enc->connector.id == CONNECTOR_ID_EDP /*|| wireless*/)
+- result.u_all = (1 << enc->preferred_engine);
++ enum bp_result result;
+
+- return result;
+-}
++ cntl.action = TRANSMITTER_CONTROL_INIT;
++ cntl.engine_id = ENGINE_ID_UNKNOWN;
++ cntl.transmitter = enc->transmitter;
++ cntl.connector_obj_id = enc->connector;
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.coherent = false;
++ cntl.hpd_sel = enc->hpd_source;
+
+-void dce110_link_encoder_set_lcd_backlight_level(
+- struct link_encoder *enc,
+- uint32_t level)
+-{
+- struct dc_context *ctx = enc->ctx;
++ result = dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
+
+- const uint32_t backlight_update_pending_max_retry = 1000;
++ if (result != BP_RESULT_OK) {
++ dal_logger_write(enc->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "%s: Failed to execute VBIOS command table!\n",
++ __func__);
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
+
+- uint32_t backlight;
+- uint32_t backlight_period;
+- uint32_t backlight_lock;
++ if (enc->connector.id == CONNECTOR_ID_LVDS) {
++ cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS;
+
+- uint32_t i;
+- uint32_t backlight_24bit;
+- uint32_t backlight_17bit;
+- uint32_t backlight_16bit;
+- uint32_t masked_pwm_period;
+- uint8_t rounding_bit;
+- uint8_t bit_count;
+- uint64_t active_duty_cycle;
++ result = dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
++ ASSERT(result == BP_RESULT_OK);
+
+- backlight = dal_read_reg(ctx, mmBL_PWM_CNTL);
+- backlight_period = dal_read_reg(ctx, mmBL_PWM_PERIOD_CNTL);
+- backlight_lock = dal_read_reg(ctx, mmBL_PWM_GRP1_REG_LOCK);
++ } else if (enc->connector.id == CONNECTOR_ID_EDP) {
++ link_encoder_edp_power_control(enc, true);
+
+- /*
+- * 1. Convert 8-bit value to 17 bit U1.16 format
+- * (1 integer, 16 fractional bits)
+- */
++ link_encoder_edp_wait_for_hpd_ready(
++ enc, enc->connector, true);
+
+- /* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
+- * effectively multiplying value by 256/255
+- * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
+- */
+- backlight_24bit = level * 0x10101;
++ }
++ aux_initialize(enc, enc->hpd_source);
+
+- /* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
+- * used for rounding, take most significant bit of fraction for
+- * rounding, e.g. for 0xEFEFEF, rounding bit is 1
+- */
+- rounding_bit = (backlight_24bit >> 7) & 1;
++ /* reinitialize HPD.
++ * hpd_initialize() will pass DIG_FE id to HW context.
++ * All other routine within HW context will use fe_engine_offset
++ * as DIG_FE id even caller pass DIG_FE id.
++ * So this routine must be called first. */
++ hpd_initialize(enc, enc->hpd_source);
+
+- /* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
+- * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
+- */
+- backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
++ return ENCODER_RESULT_OK;
++}
+
+- /*
+- * 2. Find 16 bit backlight active duty cycle, where 0 <= backlight
+- * active duty cycle <= backlight period
+- */
++void dce110_link_encoder_setup(
++ struct link_encoder *enc,
++ enum signal_type signal)
++{
++ const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ switch (signal) {
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ /* DP SST */
++ set_reg_field_value(value, 0, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_LVDS:
++ /* LVDS */
++ set_reg_field_value(value, 1, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ /* TMDS-DVI */
++ set_reg_field_value(value, 2, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ /* TMDS-HDMI */
++ set_reg_field_value(value, 3, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ /* DP MST */
++ set_reg_field_value(value, 5, DIG_BE_CNTL, DIG_MODE);
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ /* invalid mode ! */
++ break;
++ }
++
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++/*
++ * @brief
++ * Configure digital transmitter and enable both encoder and transmitter
++ * Actual output will be available after calling unblank()
++ */
++enum encoder_result dce110_link_encoder_enable_output(
++ struct link_encoder *enc,
++ const struct link_settings *link_settings,
++ enum engine_id engine,
++ enum clock_source_id clock_source,
++ enum signal_type signal,
++ enum dc_color_depth color_depth,
++ uint32_t pixel_clock)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (enc->connector.id == CONNECTOR_ID_EDP) {
++ /* power up eDP panel */
++
++ link_encoder_edp_power_control(
++ enc, true);
++
++ link_encoder_edp_wait_for_hpd_ready(
++ enc, enc->connector, true);
++
++ /* have to turn off the backlight
++ * before power down eDP panel */
++ link_encoder_edp_backlight_control(
++ enc, true);
++ }
++
++ /* Enable the PHY */
++
++ /* number_of_lanes is used for pixel clock adjust,
++ * but it's not passed to asic_control.
++ * We need to set number of lanes manually. */
++ if (dc_is_dp_signal(signal))
++ configure_encoder(enc, engine, link_settings);
++
++ cntl.action = TRANSMITTER_CONTROL_ENABLE;
++ cntl.engine_id = engine;
++ cntl.transmitter = enc->transmitter;
++ cntl.pll_id = clock_source;
++ cntl.signal = signal;
++ cntl.lanes_number = link_settings->lane_count;
++ cntl.hpd_sel = enc->hpd_source;
++ if (dc_is_dp_signal(signal))
++ cntl.pixel_clock = link_settings->link_rate
++ * LINK_RATE_REF_FREQ_IN_KHZ;
++ else
++ cntl.pixel_clock = pixel_clock;
++ cntl.color_depth = color_depth;
++
++ if (DELAY_AFTER_PIXEL_FORMAT_CHANGE)
++ dc_service_sleep_in_milliseconds(
++ enc->ctx,
++ DELAY_AFTER_PIXEL_FORMAT_CHANGE);
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
++
++ return ENCODER_RESULT_OK;
++}
++
++/*
++ * @brief
++ * Disable transmitter and its encoder
++ */
++enum encoder_result dce110_link_encoder_disable_output(
++ struct link_encoder *link_enc,
++ enum signal_type signal)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (link_enc->connector.id == CONNECTOR_ID_EDP) {
++ /* have to turn off the backlight
++ * before power down eDP panel */
++ link_encoder_edp_backlight_control(
++ link_enc, false);
++ }
++
++ if (!is_dig_enabled(link_enc) &&
++ dal_adapter_service_should_optimize(link_enc->adapter_service,
++ OF_SKIP_POWER_DOWN_INACTIVE_ENCODER)) {
++ return ENCODER_RESULT_OK;
++ }
++ /* Power-down RX and disable GPU PHY should be paired.
++ * Disabling PHY without powering down RX may cause
++ * symbol lock loss, on which we will get DP Sink interrupt. */
++
++ /* There is a case for the DP active dongles
++ * where we want to disable the PHY but keep RX powered,
++ * for those we need to ignore DP Sink interrupt
++ * by checking lane count that has been set
++ * on the last do_enable_output(). */
++
++ /* disable transmitter */
++ cntl.action = TRANSMITTER_CONTROL_DISABLE;
++ cntl.transmitter = link_enc->transmitter;
++ cntl.hpd_sel = link_enc->hpd_source;
++ cntl.signal = signal;
++ cntl.connector_obj_id = link_enc->connector;
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ link_enc->adapter_service), &cntl);
++
++ /* disable encoder */
++ if (dc_is_dp_signal(signal))
++ link_encoder_disable(link_enc);
++
++ if (link_enc->connector.id == CONNECTOR_ID_EDP) {
++ /* power down eDP panel */
++ /* TODO: Power control cause regression, we should implement
++ * it properly, for now just comment it.
++ *
++ * link_encoder_edp_wait_for_hpd_ready(
++ link_enc,
++ link_enc->connector,
++ false);
++
++ * link_encoder_edp_power_control(
++ link_enc, false); */
++ }
++
++ return ENCODER_RESULT_OK;
++}
++
++enum encoder_result dce110_link_encoder_dp_set_lane_settings(
++ struct link_encoder *enc,
++ const struct link_training_settings *link_settings)
++{
++ union dpcd_training_lane_set training_lane_set = { { 0 } };
++
++ int32_t lane = 0;
++
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (!link_settings) {
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
++
++ cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
++ cntl.transmitter = enc->transmitter;
++ cntl.connector_obj_id = enc->connector;
++ cntl.lanes_number = link_settings->link_settings.lane_count;
++ cntl.hpd_sel = enc->hpd_source;
++ cntl.pixel_clock = link_settings->link_settings.link_rate *
++ LINK_RATE_REF_FREQ_IN_KHZ;
++
++ for (lane = 0; lane < link_settings->link_settings.lane_count; ++lane) {
++ /* translate lane settings */
++
++ training_lane_set.bits.VOLTAGE_SWING_SET =
++ link_settings->lane_settings[lane].VOLTAGE_SWING;
++ training_lane_set.bits.PRE_EMPHASIS_SET =
++ link_settings->lane_settings[lane].PRE_EMPHASIS;
++
++ /* post cursor 2 setting only applies to HBR2 link rate */
++ if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
++ /* this is passed to VBIOS
++ * to program post cursor 2 level */
++
++ training_lane_set.bits.POST_CURSOR2_SET =
++ link_settings->lane_settings[lane].POST_CURSOR2;
++ }
++
++ cntl.lane_select = lane;
++ cntl.lane_settings = training_lane_set.raw;
++
++ /* call VBIOS table to set voltage swing and pre-emphasis */
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service), &cntl);
++ }
++
++ return ENCODER_RESULT_OK;
++}
++
++void dce110_link_encoder_set_dp_phy_pattern(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param)
++{
++ const int32_t offset = enc->be_engine_offset;
++
++
++ switch (param->dp_phy_pattern) {
++ case DP_TEST_PATTERN_TRAINING_PATTERN1:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 0);
++ break;
++ case DP_TEST_PATTERN_TRAINING_PATTERN2:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 1);
++ break;
++ case DP_TEST_PATTERN_TRAINING_PATTERN3:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 2);
++ break;
++ case DP_TEST_PATTERN_D102:
++ set_dp_phy_pattern_d102(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_SYMBOL_ERROR:
++ set_dp_phy_pattern_symbol_error(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_PRBS7:
++ set_dp_phy_pattern_prbs7(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_80BIT_CUSTOM:
++ set_dp_phy_pattern_80bit_custom(
++ enc->ctx,
++ offset, param->custom_pattern);
++ break;
++ case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
++ set_dp_phy_pattern_hbr2_compliance(
++ enc, offset);
++ break;
++ case DP_TEST_PATTERN_VIDEO_MODE: {
++ set_dp_phy_pattern_passthrough_mode(
++ enc->ctx,
++ offset,
++ param->dp_panel_mode);
++ break;
++ }
++
++
++ default:
++ /* invalid phy pattern */
++ ASSERT_CRITICAL(false);
++ break;
++ }
++}
++
++/*
++ * get_supported_stream_engines
++ *
++ * @brief
++ * get a list of supported engine
++ *
++ * @param
++ * const struct encoder_impl *enc - not used.
++ *
++ * @return
++ * list of engines with supported ones enabled.
++ */
++union supported_stream_engines dce110_get_supported_stream_engines(
++ const struct link_encoder *enc)
++{
++ union supported_stream_engines result = {.u_all = 0};
++
++ result.engine.ENGINE_ID_DIGA = 1;
++ result.engine.ENGINE_ID_DIGB = 1;
++ result.engine.ENGINE_ID_DIGC = 1;
++
++ if (enc->connector.id == CONNECTOR_ID_EDP /*|| wireless*/)
++ result.u_all = (1 << enc->preferred_engine);
++
++ return result;
++}
++
++void dce110_link_encoder_update_mst_stream_allocation_table(
++ struct link_encoder *enc,
++ const struct dp_mst_stream_allocation_table *table,
++ bool is_removal)
++{
++ int32_t addr_offset = enc->be_engine_offset;
++ uint32_t value0;
++ uint32_t value1;
++ uint32_t retries = 0;
++
++ /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/
++
++ /* --- Set MSE Stream Attribute -
++ * Setup VC Payload Table on Tx Side,
++ * Issue allocation change trigger
++ * to commit payload on both tx and rx side */
++
++ value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset);
++ value1 = dal_read_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset);
++
++ if (table->stream_count >= 1) {
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[0].engine,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SRC0);
++
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[0].slot_count,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SLOT_COUNT0);
++ }
++
++ if (table->stream_count >= 2) {
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[1].engine,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SRC1);
++
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[1].slot_count,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SLOT_COUNT1);
++ }
++
++ if (table->stream_count >= 3) {
++ set_reg_field_value(
++ value1,
++ table->stream_allocations[2].engine,
++ DP_MSE_SAT1,
++ DP_MSE_SAT_SRC2);
++
++ set_reg_field_value(
++ value1,
++ table->stream_allocations[2].slot_count,
++ DP_MSE_SAT1,
++ DP_MSE_SAT_SLOT_COUNT2);
++ }
++
++ /* update ASIC MSE stream allocation table */
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset, value0);
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset, value1);
++
++ /* --- wait for transaction finish */
++
++ /* send allocation change trigger (ACT) ?
++ * this step first sends the ACT,
++ * then double buffers the SAT into the hardware
++ * making the new allocation active on the DP MST mode link */
++
++ value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset);
++
++ /* DP_MSE_SAT_UPDATE:
++ * 0 - No Action
++ * 1 - Update SAT with trigger
++ * 2 - Update SAT without trigger */
++
++ set_reg_field_value(
++ value0,
++ 1,
++ DP_MSE_SAT_UPDATE,
++ DP_MSE_SAT_UPDATE);
++
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset, value0);
++
++ /* wait for update to complete
++ * (i.e. DP_MSE_SAT_UPDATE field is reset to 0)
++ * then wait for the transmission
++ * of at least 16 MTP headers on immediate local link.
++ * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0
++ * a value of 1 indicates that DP MST mode
++ * is in the 16 MTP keepout region after a VC has been added.
++ * MST stream bandwidth (VC rate) can be configured
++ * after this bit is cleared */
++
++ do {
++ dc_service_delay_in_microseconds(enc->ctx, 10);
++
++ value0 = dal_read_reg(enc->ctx,
++ mmDP_MSE_SAT_UPDATE + addr_offset);
++
++ value1 = get_reg_field_value(
++ value0,
++ DP_MSE_SAT_UPDATE,
++ DP_MSE_16_MTP_KEEPOUT);
++
++ /* bit field DP_MSE_SAT_UPDATE is set to 1 already */
++ if (value1)
++ break;
++ ++retries;
++ } while (retries < DP_MST_UPDATE_MAX_RETRY);
++
++ /* TODO should not need. clean this after light up
++ * if (is_removal)
++ * dal_write_reg(enc->ctx, addr, value);
++ */
++}
++
++
++void dce110_link_encoder_set_lcd_backlight_level(
++ struct link_encoder *enc,
++ uint32_t level)
++{
++ struct dc_context *ctx = enc->ctx;
++
++ const uint32_t backlight_update_pending_max_retry = 1000;
++
++ uint32_t backlight;
++ uint32_t backlight_period;
++ uint32_t backlight_lock;
++
++ uint32_t i;
++ uint32_t backlight_24bit;
++ uint32_t backlight_17bit;
++ uint32_t backlight_16bit;
++ uint32_t masked_pwm_period;
++ uint8_t rounding_bit;
++ uint8_t bit_count;
++ uint64_t active_duty_cycle;
++
++ backlight = dal_read_reg(ctx, mmBL_PWM_CNTL);
++ backlight_period = dal_read_reg(ctx, mmBL_PWM_PERIOD_CNTL);
++ backlight_lock = dal_read_reg(ctx, mmBL_PWM_GRP1_REG_LOCK);
++
++ /*
++ * 1. Convert 8-bit value to 17 bit U1.16 format
++ * (1 integer, 16 fractional bits)
++ */
++
++ /* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
++ * effectively multiplying value by 256/255
++ * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
++ */
++ backlight_24bit = level * 0x10101;
++
++ /* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
++ * used for rounding, take most significant bit of fraction for
++ * rounding, e.g. for 0xEFEFEF, rounding bit is 1
++ */
++ rounding_bit = (backlight_24bit >> 7) & 1;
++
++ /* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
++ * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
++ */
++ backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
++
++ /*
++ * 2. Find 16 bit backlight active duty cycle, where 0 <= backlight
++ * active duty cycle <= backlight period
++ */
+
+ /* 2.1 Apply bitmask for backlight period value based on value of BITCNT
+ */
+@@ -1831,127 +1953,6 @@ void dce110_set_afmt_memory_power_state(
+ dal_write_reg(ctx, mmDCO_MEM_PWR_CTRL, value);
+ }
+
+-void dce110_link_encoder_update_mst_stream_allocation_table(
+- struct link_encoder *enc,
+- const struct dp_mst_stream_allocation_table *table,
+- bool is_removal)
+-{
+- int32_t addr_offset = enc->be_engine_offset;
+- uint32_t value0;
+- uint32_t value1;
+- uint32_t retries = 0;
+-
+- /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/
+-
+- /* --- Set MSE Stream Attribute -
+- * Setup VC Payload Table on Tx Side,
+- * Issue allocation change trigger
+- * to commit payload on both tx and rx side */
+-
+- value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset);
+- value1 = dal_read_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset);
+-
+- if (table->stream_count >= 1) {
+- set_reg_field_value(
+- value0,
+- table->stream_allocations[0].engine,
+- DP_MSE_SAT0,
+- DP_MSE_SAT_SRC0);
+-
+- set_reg_field_value(
+- value0,
+- table->stream_allocations[0].slot_count,
+- DP_MSE_SAT0,
+- DP_MSE_SAT_SLOT_COUNT0);
+- }
+-
+- if (table->stream_count >= 2) {
+- set_reg_field_value(
+- value0,
+- table->stream_allocations[1].engine,
+- DP_MSE_SAT0,
+- DP_MSE_SAT_SRC1);
+-
+- set_reg_field_value(
+- value0,
+- table->stream_allocations[1].slot_count,
+- DP_MSE_SAT0,
+- DP_MSE_SAT_SLOT_COUNT1);
+- }
+-
+- if (table->stream_count >= 3) {
+- set_reg_field_value(
+- value1,
+- table->stream_allocations[2].engine,
+- DP_MSE_SAT1,
+- DP_MSE_SAT_SRC2);
+-
+- set_reg_field_value(
+- value1,
+- table->stream_allocations[2].slot_count,
+- DP_MSE_SAT1,
+- DP_MSE_SAT_SLOT_COUNT2);
+- }
+-
+- /* update ASIC MSE stream allocation table */
+- dal_write_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset, value0);
+- dal_write_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset, value1);
+-
+- /* --- wait for transaction finish */
+-
+- /* send allocation change trigger (ACT) ?
+- * this step first sends the ACT,
+- * then double buffers the SAT into the hardware
+- * making the new allocation active on the DP MST mode link */
+-
+- value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset);
+-
+- /* DP_MSE_SAT_UPDATE:
+- * 0 - No Action
+- * 1 - Update SAT with trigger
+- * 2 - Update SAT without trigger */
+-
+- set_reg_field_value(
+- value0,
+- 1,
+- DP_MSE_SAT_UPDATE,
+- DP_MSE_SAT_UPDATE);
+-
+- dal_write_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset, value0);
+-
+- /* wait for update to complete
+- * (i.e. DP_MSE_SAT_UPDATE field is reset to 0)
+- * then wait for the transmission
+- * of at least 16 MTP headers on immediate local link.
+- * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0
+- * a value of 1 indicates that DP MST mode
+- * is in the 16 MTP keepout region after a VC has been added.
+- * MST stream bandwidth (VC rate) can be configured
+- * after this bit is cleared */
+-
+- do {
+- dc_service_delay_in_microseconds(enc->ctx, 10);
+-
+- value0 = dal_read_reg(enc->ctx,
+- mmDP_MSE_SAT_UPDATE + addr_offset);
+-
+- value1 = get_reg_field_value(
+- value0,
+- DP_MSE_SAT_UPDATE,
+- DP_MSE_16_MTP_KEEPOUT);
+-
+- /* bit field DP_MSE_SAT_UPDATE is set to 1 already */
+- if (value1)
+- break;
+- ++retries;
+- } while (retries < DP_MST_UPDATE_MAX_RETRY);
+-
+- /* TODO should not need. clean this after light up
+- * if (is_removal)
+- * dal_write_reg(enc->ctx, addr, value);
+- */
+-}
+-
+ void dce110_link_encoder_set_mst_bandwidth(
+ struct link_encoder *enc,
+ enum engine_id engine,
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
+index 4331bf0..eae2267 100644
+--- a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
+@@ -30,26 +30,11 @@ struct link_encoder *dce110_link_encoder_create(
+ const struct encoder_init_data *init);
+ void dce110_link_encoder_destroy(struct link_encoder **enc);
+
+-void dce110_link_encoder_set_dp_phy_pattern(
+- struct link_encoder *enc,
+- const struct encoder_set_dp_phy_pattern_param *param);
+-
+-enum encoder_result dce110_link_encoder_power_up(struct link_encoder *enc);
+-
+-enum encoder_result dce110_link_encoder_dp_set_lane_settings(
+- struct link_encoder *enc,
+- const struct link_training_settings *link_settings);
+-
+-union supported_stream_engines dce110_get_supported_stream_engines(
+- const struct link_encoder *enc);
+-
+ enum encoder_result dce110_link_encoder_validate_output_with_stream(
+ struct link_encoder *enc,
+ const struct core_stream *stream);
+
+-void dce110_link_encoder_set_lcd_backlight_level(
+- struct link_encoder *enc,
+- uint32_t level);
++enum encoder_result dce110_link_encoder_power_up(struct link_encoder *enc);
+
+ void dce110_link_encoder_setup(
+ struct link_encoder *enc,
+@@ -68,16 +53,32 @@ enum encoder_result dce110_link_encoder_disable_output(
+ struct link_encoder *link_enc,
+ enum signal_type signal);
+
+-void dce110_set_afmt_memory_power_state(
+- const struct dc_context *ctx,
+- enum engine_id id,
+- bool enable);
++
++enum encoder_result dce110_link_encoder_dp_set_lane_settings(
++ struct link_encoder *enc,
++ const struct link_training_settings *link_settings);
++
++void dce110_link_encoder_set_dp_phy_pattern(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param);
++
++union supported_stream_engines dce110_get_supported_stream_engines(
++ const struct link_encoder *enc);
+
+ void dce110_link_encoder_update_mst_stream_allocation_table(
+ struct link_encoder *enc,
+ const struct dp_mst_stream_allocation_table *table,
+ bool is_removal);
+
++void dce110_link_encoder_set_lcd_backlight_level(
++ struct link_encoder *enc,
++ uint32_t level);
++
++void dce110_set_afmt_memory_power_state(
++ const struct dc_context *ctx,
++ enum engine_id id,
++ bool enable);
++
+ void dce110_link_encoder_set_mst_bandwidth(
+ struct link_encoder *enc,
+ enum engine_id engine,
+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 a9edf96..d3ab89a 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
+@@ -54,29 +54,6 @@ static void construct(
+ enc->adapter_service = init->adapter_service;
+ }
+
+-struct stream_encoder *dce110_stream_encoder_create(
+- struct stream_enc_init_data *init)
+-{
+- struct stream_encoder *enc =
+- dc_service_alloc(init->ctx, sizeof(struct stream_encoder));
+-
+- if (!enc)
+- goto enc_create_fail;
+-
+- construct(enc, init);
+-
+- return enc;
+-
+-enc_create_fail:
+- return NULL;
+-}
+-
+-void dce110_stream_encoder_destroy(struct stream_encoder **enc)
+-{
+- dc_service_free((*enc)->ctx, *enc);
+- *enc = NULL;
+-}
+-
+ static void stop_hdmi_info_packets(struct dc_context *ctx, uint32_t offset)
+ {
+ uint32_t addr = 0;
+@@ -207,22 +184,6 @@ static void stop_dp_info_packets(struct dc_context *ctx, int32_t offset)
+ dal_write_reg(ctx, addr, value);
+ }
+
+-void dce110_stream_encoder_stop_info_packets(
+- struct stream_encoder *enc,
+- enum engine_id engine,
+- enum signal_type signal)
+-{
+- if (dc_is_hdmi_signal(signal))
+- stop_hdmi_info_packets(
+- enc->ctx,
+- fe_engine_offsets[engine]);
+- else if (dc_is_dp_signal(signal))
+- stop_dp_info_packets(
+- enc->ctx,
+- fe_engine_offsets[engine]);
+-}
+-
+-
+ static void update_avi_info_packet(
+ struct stream_encoder *enc,
+ enum engine_id engine,
+@@ -615,24 +576,6 @@ static void update_dp_info_packet(
+ dal_write_reg(enc->ctx, addr, value);
+ }
+
+-void dce110_stream_encoder_update_info_packets(
+- struct stream_encoder *enc,
+- enum signal_type signal,
+- const struct encoder_info_frame *info_frame)
+-{
+- if (dc_is_hdmi_signal(signal)) {
+- update_avi_info_packet(
+- enc,
+- enc->id,
+- signal,
+- &info_frame->avi);
+- update_hdmi_info_packet(enc, enc->id, 0, &info_frame->vendor);
+- update_hdmi_info_packet(enc, enc->id, 1, &info_frame->gamut);
+- update_hdmi_info_packet(enc, enc->id, 2, &info_frame->spd);
+- } else if (dc_is_dp_signal(signal))
+- update_dp_info_packet(enc, enc->id, 0, &info_frame->vsc);
+-}
+-
+ static void dp_steer_fifo_reset(
+ struct dc_context *ctx,
+ enum engine_id engine,
+@@ -647,76 +590,6 @@ static void dp_steer_fifo_reset(
+ dal_write_reg(ctx, addr, value);
+ }
+
+-/*
+- * @brief
+- * Output blank data,
+- * prevents output of the actual surface data on active transmitter
+- */
+-enum encoder_result dce110_stream_encoder_blank(
+- struct stream_encoder *enc,
+- enum signal_type signal)
+-{
+- enum engine_id engine = enc->id;
+- const uint32_t addr = mmDP_VID_STREAM_CNTL + fe_engine_offsets[engine];
+- uint32_t value = dal_read_reg(enc->ctx, addr);
+- uint32_t retries = 0;
+- uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
+-
+- if (!dc_is_dp_signal(signal))
+- return ENCODER_RESULT_OK;
+-
+- /* Note: For CZ, we are changing driver default to disable
+- * stream deferred to next VBLANK. If results are positive, we
+- * will make the same change to all DCE versions. There are a
+- * handful of panels that cannot handle disable stream at
+- * HBLANK and will result in a white line flash across the
+- * screen on stream disable. */
+-
+- /* Specify the video stream disable point
+- * (2 = start of the next vertical blank) */
+- set_reg_field_value(
+- value,
+- 2,
+- 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. */
+- max_retries = DP_BLANK_MAX_RETRY * 150;
+-
+- /* disable DP stream */
+- set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
+- dal_write_reg(enc->ctx, addr, value);
+-
+- /* the encoder stops sending the video stream
+- * at the start of the vertical blanking.
+- * Poll for DP_VID_STREAM_STATUS == 0 */
+-
+- do {
+- value = dal_read_reg(enc->ctx, addr);
+-
+- if (!get_reg_field_value(
+- value,
+- DP_VID_STREAM_CNTL,
+- DP_VID_STREAM_STATUS))
+- break;
+-
+- dc_service_delay_in_microseconds(enc->ctx, 10);
+-
+- ++retries;
+- } while (retries < max_retries);
+-
+- 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(enc->ctx, engine, true);
+-
+- return ENCODER_RESULT_OK;
+-}
+-
+ static void unblank_dp_output(
+ struct stream_encoder *enc,
+ enum engine_id engine)
+@@ -786,46 +659,6 @@ static void setup_vid_stream(
+ set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
+ dal_write_reg(enc->ctx, addr, value);
+ }
+-/*
+- * @brief
+- * Stop sending blank data,
+- * output the actual surface data on active transmitter
+- */
+-enum encoder_result dce110_stream_encoder_unblank(
+- struct stream_encoder *enc,
+- const struct encoder_unblank_param *param)
+-{
+- bool is_dp_signal = param->signal == SIGNAL_TYPE_DISPLAY_PORT
+- || param->signal == SIGNAL_TYPE_DISPLAY_PORT_MST
+- || param->signal == SIGNAL_TYPE_EDP;
+-
+- if (!is_dp_signal)
+- return ENCODER_RESULT_OK;
+-
+- 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 */
+-
+- uint64_t m_vid_l = n_vid;
+-
+- m_vid_l *= param->crtc_timing.pixel_clock;
+- m_vid_l = div_u64(m_vid_l,
+- param->link_settings.link_rate
+- * LINK_RATE_REF_FREQ_IN_KHZ);
+-
+- m_vid = (uint32_t) m_vid_l;
+-
+- setup_vid_stream(enc,
+- enc->id, m_vid, n_vid);
+- }
+-
+- unblank_dp_output(enc, enc->id);
+-
+- return ENCODER_RESULT_OK;
+-}
+
+ static void set_dp_stream_attributes(
+ struct stream_encoder *enc,
+@@ -1106,6 +939,29 @@ static void set_tmds_stream_attributes(
+ dal_write_reg(enc->ctx, addr, value);
+ }
+
++struct stream_encoder *dce110_stream_encoder_create(
++ struct stream_enc_init_data *init)
++{
++ struct stream_encoder *enc =
++ dc_service_alloc(init->ctx, sizeof(struct stream_encoder));
++
++ if (!enc)
++ goto enc_create_fail;
++
++ construct(enc, init);
++
++ return enc;
++
++enc_create_fail:
++ return NULL;
++}
++
++void dce110_stream_encoder_destroy(struct stream_encoder **enc)
++{
++ dc_service_free((*enc)->ctx, *enc);
++ *enc = NULL;
++}
++
+ /*
+ * @brief
+ * Associate digital encoder with specified output transmitter
+@@ -1166,3 +1022,148 @@ enum encoder_result dce110_stream_encoder_setup(
+
+ return ENCODER_RESULT_OK;
+ }
++
++void dce110_stream_encoder_update_info_packets(
++ struct stream_encoder *enc,
++ enum signal_type signal,
++ const struct encoder_info_frame *info_frame)
++{
++ if (dc_is_hdmi_signal(signal)) {
++ update_avi_info_packet(
++ enc,
++ enc->id,
++ signal,
++ &info_frame->avi);
++ update_hdmi_info_packet(enc, enc->id, 0, &info_frame->vendor);
++ update_hdmi_info_packet(enc, enc->id, 1, &info_frame->gamut);
++ update_hdmi_info_packet(enc, enc->id, 2, &info_frame->spd);
++ } else if (dc_is_dp_signal(signal))
++ update_dp_info_packet(enc, enc->id, 0, &info_frame->vsc);
++}
++
++void dce110_stream_encoder_stop_info_packets(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal)
++{
++ if (dc_is_hdmi_signal(signal))
++ stop_hdmi_info_packets(
++ enc->ctx,
++ fe_engine_offsets[engine]);
++ else if (dc_is_dp_signal(signal))
++ stop_dp_info_packets(
++ enc->ctx,
++ fe_engine_offsets[engine]);
++}
++
++/*
++ * @brief
++ * Output blank data,
++ * prevents output of the actual surface data on active transmitter
++ */
++enum encoder_result dce110_stream_encoder_blank(
++ struct stream_encoder *enc,
++ enum signal_type signal)
++{
++ enum engine_id engine = enc->id;
++ const uint32_t addr = mmDP_VID_STREAM_CNTL + fe_engine_offsets[engine];
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++ uint32_t retries = 0;
++ uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
++
++ if (!dc_is_dp_signal(signal))
++ return ENCODER_RESULT_OK;
++
++ /* Note: For CZ, we are changing driver default to disable
++ * stream deferred to next VBLANK. If results are positive, we
++ * will make the same change to all DCE versions. There are a
++ * handful of panels that cannot handle disable stream at
++ * HBLANK and will result in a white line flash across the
++ * screen on stream disable. */
++
++ /* Specify the video stream disable point
++ * (2 = start of the next vertical blank) */
++ set_reg_field_value(
++ value,
++ 2,
++ 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. */
++ max_retries = DP_BLANK_MAX_RETRY * 150;
++
++ /* disable DP stream */
++ set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* the encoder stops sending the video stream
++ * at the start of the vertical blanking.
++ * Poll for DP_VID_STREAM_STATUS == 0 */
++
++ do {
++ value = dal_read_reg(enc->ctx, addr);
++
++ if (!get_reg_field_value(
++ value,
++ DP_VID_STREAM_CNTL,
++ DP_VID_STREAM_STATUS))
++ break;
++
++ dc_service_delay_in_microseconds(enc->ctx, 10);
++
++ ++retries;
++ } while (retries < max_retries);
++
++ 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(enc->ctx, engine, true);
++
++ return ENCODER_RESULT_OK;
++}
++
++/*
++ * @brief
++ * Stop sending blank data,
++ * output the actual surface data on active transmitter
++ */
++enum encoder_result dce110_stream_encoder_unblank(
++ struct stream_encoder *enc,
++ const struct encoder_unblank_param *param)
++{
++ bool is_dp_signal = param->signal == SIGNAL_TYPE_DISPLAY_PORT
++ || param->signal == SIGNAL_TYPE_DISPLAY_PORT_MST
++ || param->signal == SIGNAL_TYPE_EDP;
++
++ if (!is_dp_signal)
++ return ENCODER_RESULT_OK;
++
++ 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 */
++
++ uint64_t m_vid_l = n_vid;
++
++ m_vid_l *= param->crtc_timing.pixel_clock;
++ m_vid_l = div_u64(m_vid_l,
++ param->link_settings.link_rate
++ * LINK_RATE_REF_FREQ_IN_KHZ);
++
++ m_vid = (uint32_t) m_vid_l;
++
++ setup_vid_stream(enc,
++ enc->id, m_vid, n_vid);
++ }
++
++ unblank_dp_output(enc, enc->id);
++
++ return ENCODER_RESULT_OK;
++}
++
+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 d2c7b90..83df255 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
+@@ -37,16 +37,22 @@ struct stream_encoder *dce110_stream_encoder_create(
+
+ void dce110_stream_encoder_destroy(struct stream_encoder **enc);
+
+-void dce110_stream_encoder_stop_info_packets(
++enum encoder_result dce110_stream_encoder_setup(
+ struct stream_encoder *enc,
+- enum engine_id engine,
+- enum signal_type signal);
++ struct dc_crtc_timing *crtc_timing,
++ enum signal_type signal,
++ bool enable_audio);
+
+ void dce110_stream_encoder_update_info_packets(
+ struct stream_encoder *enc,
+ enum signal_type signal,
+ const struct encoder_info_frame *info_frame);
+
++void dce110_stream_encoder_stop_info_packets(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal);
++
+ enum encoder_result dce110_stream_encoder_blank(
+ struct stream_encoder *enc,
+ enum signal_type signal);
+@@ -55,10 +61,4 @@ enum encoder_result dce110_stream_encoder_unblank(
+ struct stream_encoder *enc,
+ const struct encoder_unblank_param *param);
+
+-enum encoder_result dce110_stream_encoder_setup(
+- struct stream_encoder *enc,
+- struct dc_crtc_timing *crtc_timing,
+- enum signal_type signal,
+- bool enable_audio);
+-
+ #endif /* __DC_STREAM_ENCODER_DCE110_H__ */
+--
+2.7.4
+