From 2e6975280175f40d209cc2e86c1141a9a61fe23b Mon Sep 17 00:00:00 2001 From: Chris Park 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 Signed-off-by: Harry Wentland Acked-by: Harry Wentland --- .../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