diff options
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.patch | 1691 |
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 + |