diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link.c | 104 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 915 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/link/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c | 1055 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h | 33 |
6 files changed, 1090 insertions, 1023 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 79d25d3f2871..24daadf587fd 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -4095,110 +4095,6 @@ void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable) dc->hwss.set_avmute(pipe_ctx, enable); } -void dc_link_set_drive_settings(struct dc *dc, - struct link_training_settings *lt_settings, - const struct dc_link *link) -{ - - int i; - struct link_resource link_res; - - for (i = 0; i < dc->link_count; i++) - if (dc->links[i] == link) - break; - - if (i >= dc->link_count) - ASSERT_CRITICAL(false); - - dc_link_get_cur_link_res(link, &link_res); - dp_set_drive_settings(dc->links[i], &link_res, lt_settings); -} - -void dc_link_set_preferred_link_settings(struct dc *dc, - struct dc_link_settings *link_setting, - struct dc_link *link) -{ - int i; - struct pipe_ctx *pipe; - struct dc_stream_state *link_stream; - struct dc_link_settings store_settings = *link_setting; - - link->preferred_link_setting = store_settings; - - /* Retrain with preferred link settings only relevant for - * DP signal type - * Check for non-DP signal or if passive dongle present - */ - if (!dc_is_dp_signal(link->connector_signal) || - link->dongle_max_pix_clk > 0) - return; - - for (i = 0; i < MAX_PIPES; i++) { - pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->stream->link) { - if (pipe->stream->link == link) { - link_stream = pipe->stream; - break; - } - } - } - - /* Stream not found */ - if (i == MAX_PIPES) - return; - - /* Cannot retrain link if backend is off */ - if (link_stream->dpms_off) - return; - - if (link_decide_link_settings(link_stream, &store_settings)) - dp_retrain_link_dp_test(link, &store_settings, false); -} - -void dc_link_set_preferred_training_settings(struct dc *dc, - struct dc_link_settings *link_setting, - struct dc_link_training_overrides *lt_overrides, - struct dc_link *link, - bool skip_immediate_retrain) -{ - if (lt_overrides != NULL) - link->preferred_training_settings = *lt_overrides; - else - memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings)); - - if (link_setting != NULL) { - link->preferred_link_setting = *link_setting; - } else { - link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; - link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN; - } - - if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && - link->type == dc_connection_mst_branch) - dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link); - - /* Retrain now, or wait until next stream update to apply */ - if (skip_immediate_retrain == false) - dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); -} - -void dc_link_set_test_pattern(struct dc_link *link, - enum dp_test_pattern test_pattern, - enum dp_test_pattern_color_space test_pattern_color_space, - const struct link_training_settings *p_link_settings, - const unsigned char *p_custom_pattern, - unsigned int cust_pattern_size) -{ - if (link != NULL) - dc_link_dp_set_test_pattern( - link, - test_pattern, - test_pattern_color_space, - p_link_settings, - p_custom_pattern, - cust_pattern_size); -} - uint32_t dc_link_bandwidth_kbps( const struct dc_link *link, const struct dc_link_settings *link_setting) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 21cc51923782..6b87aa723d52 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -104,884 +104,6 @@ bool dp_validate_mode_timing( return false; } -static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate) -{ - switch (test_rate) { - case DP_TEST_LINK_RATE_RBR: - return LINK_RATE_LOW; - case DP_TEST_LINK_RATE_HBR: - return LINK_RATE_HIGH; - case DP_TEST_LINK_RATE_HBR2: - return LINK_RATE_HIGH2; - case DP_TEST_LINK_RATE_HBR3: - return LINK_RATE_HIGH3; - case DP_TEST_LINK_RATE_UHBR10: - return LINK_RATE_UHBR10; - case DP_TEST_LINK_RATE_UHBR20: - return LINK_RATE_UHBR20; - case DP_TEST_LINK_RATE_UHBR13_5: - return LINK_RATE_UHBR13_5; - default: - return LINK_RATE_UNKNOWN; - } -} - -static void dp_test_send_link_training(struct dc_link *link) -{ - struct dc_link_settings link_settings = {0}; - uint8_t test_rate = 0; - - core_link_read_dpcd( - link, - DP_TEST_LANE_COUNT, - (unsigned char *)(&link_settings.lane_count), - 1); - core_link_read_dpcd( - link, - DP_TEST_LINK_RATE, - &test_rate, - 1); - link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate); - - /* Set preferred link settings */ - link->verified_link_cap.lane_count = link_settings.lane_count; - link->verified_link_cap.link_rate = link_settings.link_rate; - - dp_retrain_link_dp_test(link, &link_settings, false); -} - -static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern) -{ - return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern && - test_pattern <= DP_TEST_PATTERN_SQUARE_END); -} - -/* TODO Raven hbr2 compliance eye output is unstable - * (toggling on and off) with debugger break - * This caueses intermittent PHY automation failure - * Need to look into the root cause */ -static void dp_test_send_phy_test_pattern(struct dc_link *link) -{ - union phy_test_pattern dpcd_test_pattern; - union lane_adjust dpcd_lane_adjustment[2]; - unsigned char dpcd_post_cursor_2_adjustment = 0; - unsigned char test_pattern_buffer[ - (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 - - DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0}; - unsigned int test_pattern_size = 0; - enum dp_test_pattern test_pattern; - union lane_adjust dpcd_lane_adjust; - unsigned int lane; - struct link_training_settings link_training_settings; - unsigned char no_preshoot = 0; - unsigned char no_deemphasis = 0; - - dpcd_test_pattern.raw = 0; - memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment)); - memset(&link_training_settings, 0, sizeof(link_training_settings)); - - /* get phy test pattern and pattern parameters from DP receiver */ - core_link_read_dpcd( - link, - DP_PHY_TEST_PATTERN, - &dpcd_test_pattern.raw, - sizeof(dpcd_test_pattern)); - core_link_read_dpcd( - link, - DP_ADJUST_REQUEST_LANE0_1, - &dpcd_lane_adjustment[0].raw, - sizeof(dpcd_lane_adjustment)); - - /* prepare link training settings */ - link_training_settings.link_settings = link->cur_link_settings; - - link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings); - - if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) - dp_fixed_vs_pe_read_lane_adjust( - link, - link_training_settings.dpcd_lane_settings); - - /*get post cursor 2 parameters - * For DP 1.1a or eariler, this DPCD register's value is 0 - * For DP 1.2 or later: - * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1 - * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3 - */ - core_link_read_dpcd( - link, - DP_ADJUST_REQUEST_POST_CURSOR2, - &dpcd_post_cursor_2_adjustment, - sizeof(dpcd_post_cursor_2_adjustment)); - - /* translate request */ - switch (dpcd_test_pattern.bits.PATTERN) { - case PHY_TEST_PATTERN_D10_2: - test_pattern = DP_TEST_PATTERN_D102; - break; - case PHY_TEST_PATTERN_SYMBOL_ERROR: - test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR; - break; - case PHY_TEST_PATTERN_PRBS7: - test_pattern = DP_TEST_PATTERN_PRBS7; - break; - case PHY_TEST_PATTERN_80BIT_CUSTOM: - test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM; - break; - case PHY_TEST_PATTERN_CP2520_1: - /* CP2520 pattern is unstable, temporarily use TPS4 instead */ - test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? - DP_TEST_PATTERN_TRAINING_PATTERN4 : - DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; - break; - case PHY_TEST_PATTERN_CP2520_2: - /* CP2520 pattern is unstable, temporarily use TPS4 instead */ - test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? - DP_TEST_PATTERN_TRAINING_PATTERN4 : - DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; - break; - case PHY_TEST_PATTERN_CP2520_3: - test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; - break; - case PHY_TEST_PATTERN_128b_132b_TPS1: - test_pattern = DP_TEST_PATTERN_128b_132b_TPS1; - break; - case PHY_TEST_PATTERN_128b_132b_TPS2: - test_pattern = DP_TEST_PATTERN_128b_132b_TPS2; - break; - case PHY_TEST_PATTERN_PRBS9: - test_pattern = DP_TEST_PATTERN_PRBS9; - break; - case PHY_TEST_PATTERN_PRBS11: - test_pattern = DP_TEST_PATTERN_PRBS11; - break; - case PHY_TEST_PATTERN_PRBS15: - test_pattern = DP_TEST_PATTERN_PRBS15; - break; - case PHY_TEST_PATTERN_PRBS23: - test_pattern = DP_TEST_PATTERN_PRBS23; - break; - case PHY_TEST_PATTERN_PRBS31: - test_pattern = DP_TEST_PATTERN_PRBS31; - break; - case PHY_TEST_PATTERN_264BIT_CUSTOM: - test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM; - break; - case PHY_TEST_PATTERN_SQUARE: - test_pattern = DP_TEST_PATTERN_SQUARE; - break; - case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: - test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; - no_preshoot = 1; - break; - case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: - test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; - no_deemphasis = 1; - break; - case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: - test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; - no_preshoot = 1; - no_deemphasis = 1; - break; - default: - test_pattern = DP_TEST_PATTERN_VIDEO_MODE; - break; - } - - if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { - test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 - - DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1; - core_link_read_dpcd( - link, - DP_TEST_80BIT_CUSTOM_PATTERN_7_0, - test_pattern_buffer, - test_pattern_size); - } - - if (is_dp_phy_sqaure_pattern(test_pattern)) { - test_pattern_size = 1; // Square pattern data is 1 byte (DP spec) - core_link_read_dpcd( - link, - DP_PHY_SQUARE_PATTERN, - test_pattern_buffer, - test_pattern_size); - } - - if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) { - test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256- - DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1; - core_link_read_dpcd( - link, - DP_TEST_264BIT_CUSTOM_PATTERN_7_0, - test_pattern_buffer, - test_pattern_size); - } - - for (lane = 0; lane < - (unsigned int)(link->cur_link_settings.lane_count); - lane++) { - dpcd_lane_adjust.raw = - dp_get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); - if (link_dp_get_encoding_format(&link->cur_link_settings) == - DP_8b_10b_ENCODING) { - link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING = - (enum dc_voltage_swing) - (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE); - link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS = - (enum dc_pre_emphasis) - (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE); - link_training_settings.hw_lane_settings[lane].POST_CURSOR2 = - (enum dc_post_cursor2) - ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); - } else if (link_dp_get_encoding_format(&link->cur_link_settings) == - DP_128b_132b_ENCODING) { - link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level = - dpcd_lane_adjust.tx_ffe.PRESET_VALUE; - link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot; - link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis; - } - } - - dp_hw_to_dpcd_lane_settings(&link_training_settings, - link_training_settings.hw_lane_settings, - link_training_settings.dpcd_lane_settings); - /*Usage: Measure DP physical lane signal - * by DP SI test equipment automatically. - * PHY test pattern request is generated by equipment via HPD interrupt. - * HPD needs to be active all the time. HPD should be active - * all the time. Do not touch it. - * forward request to DS - */ - dc_link_dp_set_test_pattern( - link, - test_pattern, - DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED, - &link_training_settings, - test_pattern_buffer, - test_pattern_size); -} - -static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video) -{ - union audio_test_mode dpcd_test_mode = {0}; - struct audio_test_pattern_type dpcd_pattern_type = {0}; - union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0}; - enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; - - struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; - struct pipe_ctx *pipe_ctx = &pipes[0]; - unsigned int channel_count; - unsigned int channel = 0; - unsigned int modes = 0; - unsigned int sampling_rate_in_hz = 0; - - // get audio test mode and test pattern parameters - core_link_read_dpcd( - link, - DP_TEST_AUDIO_MODE, - &dpcd_test_mode.raw, - sizeof(dpcd_test_mode)); - - core_link_read_dpcd( - link, - DP_TEST_AUDIO_PATTERN_TYPE, - &dpcd_pattern_type.value, - sizeof(dpcd_pattern_type)); - - channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT); - - // read pattern periods for requested channels when sawTooth pattern is requested - if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH || - dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) { - - test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ? - DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; - // read period for each channel - for (channel = 0; channel < channel_count; channel++) { - core_link_read_dpcd( - link, - DP_TEST_AUDIO_PERIOD_CH1 + channel, - &dpcd_pattern_period[channel].raw, - sizeof(dpcd_pattern_period[channel])); - } - } - - // translate sampling rate - switch (dpcd_test_mode.bits.sampling_rate) { - case AUDIO_SAMPLING_RATE_32KHZ: - sampling_rate_in_hz = 32000; - break; - case AUDIO_SAMPLING_RATE_44_1KHZ: - sampling_rate_in_hz = 44100; - break; - case AUDIO_SAMPLING_RATE_48KHZ: - sampling_rate_in_hz = 48000; - break; - case AUDIO_SAMPLING_RATE_88_2KHZ: - sampling_rate_in_hz = 88200; - break; - case AUDIO_SAMPLING_RATE_96KHZ: - sampling_rate_in_hz = 96000; - break; - case AUDIO_SAMPLING_RATE_176_4KHZ: - sampling_rate_in_hz = 176400; - break; - case AUDIO_SAMPLING_RATE_192KHZ: - sampling_rate_in_hz = 192000; - break; - default: - sampling_rate_in_hz = 0; - break; - } - - link->audio_test_data.flags.test_requested = 1; - link->audio_test_data.flags.disable_video = disable_video; - link->audio_test_data.sampling_rate = sampling_rate_in_hz; - link->audio_test_data.channel_count = channel_count; - link->audio_test_data.pattern_type = test_pattern; - - if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) { - for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) { - link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period; - } - } -} - -void dc_link_dp_handle_automated_test(struct dc_link *link) -{ - union test_request test_request; - union test_response test_response; - - memset(&test_request, 0, sizeof(test_request)); - memset(&test_response, 0, sizeof(test_response)); - - core_link_read_dpcd( - link, - DP_TEST_REQUEST, - &test_request.raw, - sizeof(union test_request)); - if (test_request.bits.LINK_TRAINING) { - /* ACK first to let DP RX test box monitor LT sequence */ - test_response.bits.ACK = 1; - core_link_write_dpcd( - link, - DP_TEST_RESPONSE, - &test_response.raw, - sizeof(test_response)); - dp_test_send_link_training(link); - /* no acknowledge request is needed again */ - test_response.bits.ACK = 0; - } - if (test_request.bits.LINK_TEST_PATTRN) { - union test_misc dpcd_test_params; - union link_test_pattern dpcd_test_pattern; - - memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern)); - memset(&dpcd_test_params, 0, sizeof(dpcd_test_params)); - - /* get link test pattern and pattern parameters */ - core_link_read_dpcd( - link, - DP_TEST_PATTERN, - &dpcd_test_pattern.raw, - sizeof(dpcd_test_pattern)); - core_link_read_dpcd( - link, - DP_TEST_MISC0, - &dpcd_test_params.raw, - sizeof(dpcd_test_params)); - test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link, - dpcd_test_pattern, dpcd_test_params) ? 1 : 0; - } - - if (test_request.bits.AUDIO_TEST_PATTERN) { - dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO); - test_response.bits.ACK = 1; - } - - if (test_request.bits.PHY_TEST_PATTERN) { - dp_test_send_phy_test_pattern(link); - test_response.bits.ACK = 1; - } - - /* send request acknowledgment */ - if (test_response.bits.ACK) - core_link_write_dpcd( - link, - DP_TEST_RESPONSE, - &test_response.raw, - sizeof(test_response)); -} - -static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) -{ - if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern && - test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) || - test_pattern == DP_TEST_PATTERN_VIDEO_MODE) - return true; - else - return false; -} - -static void set_crtc_test_pattern(struct dc_link *link, - struct pipe_ctx *pipe_ctx, - enum dp_test_pattern test_pattern, - enum dp_test_pattern_color_space test_pattern_color_space) -{ - enum controller_dp_test_pattern controller_test_pattern; - enum dc_color_depth color_depth = pipe_ctx-> - stream->timing.display_color_depth; - struct bit_depth_reduction_params params; - struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; - int width = pipe_ctx->stream->timing.h_addressable + - pipe_ctx->stream->timing.h_border_left + - pipe_ctx->stream->timing.h_border_right; - int height = pipe_ctx->stream->timing.v_addressable + - pipe_ctx->stream->timing.v_border_bottom + - pipe_ctx->stream->timing.v_border_top; - - memset(¶ms, 0, sizeof(params)); - - switch (test_pattern) { - case DP_TEST_PATTERN_COLOR_SQUARES: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; - break; - case DP_TEST_PATTERN_COLOR_SQUARES_CEA: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA; - break; - case DP_TEST_PATTERN_VERTICAL_BARS: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_VERTICALBARS; - break; - case DP_TEST_PATTERN_HORIZONTAL_BARS: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS; - break; - case DP_TEST_PATTERN_COLOR_RAMP: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_COLORRAMP; - break; - default: - controller_test_pattern = - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; - break; - } - - switch (test_pattern) { - case DP_TEST_PATTERN_COLOR_SQUARES: - case DP_TEST_PATTERN_COLOR_SQUARES_CEA: - case DP_TEST_PATTERN_VERTICAL_BARS: - case DP_TEST_PATTERN_HORIZONTAL_BARS: - case DP_TEST_PATTERN_COLOR_RAMP: - { - /* disable bit depth reduction */ - pipe_ctx->stream->bit_depth_params = params; - opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); - if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, - controller_test_pattern, color_depth); - else if (link->dc->hwss.set_disp_pattern_generator) { - struct pipe_ctx *odm_pipe; - enum controller_dp_color_space controller_color_space; - int opp_cnt = 1; - int offset = 0; - int dpg_width = width; - - switch (test_pattern_color_space) { - case DP_TEST_PATTERN_COLOR_SPACE_RGB: - controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; - break; - case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: - controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601; - break; - case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: - controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709; - break; - case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED: - default: - controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; - DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__); - ASSERT(0); - break; - } - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - dpg_width = width / opp_cnt; - offset = dpg_width; - - link->dc->hwss.set_disp_pattern_generator(link->dc, - pipe_ctx, - controller_test_pattern, - controller_color_space, - color_depth, - NULL, - dpg_width, - height, - 0); - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; - - odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); - link->dc->hwss.set_disp_pattern_generator(link->dc, - odm_pipe, - controller_test_pattern, - controller_color_space, - color_depth, - NULL, - dpg_width, - height, - offset); - offset += offset; - } - } - } - break; - case DP_TEST_PATTERN_VIDEO_MODE: - { - /* restore bitdepth reduction */ - resource_build_bit_depth_reduction_params(pipe_ctx->stream, ¶ms); - pipe_ctx->stream->bit_depth_params = params; - opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); - if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) - pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - color_depth); - else if (link->dc->hwss.set_disp_pattern_generator) { - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - int dpg_width; - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - - dpg_width = width / opp_cnt; - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { - struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; - - odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); - link->dc->hwss.set_disp_pattern_generator(link->dc, - odm_pipe, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - color_depth, - NULL, - dpg_width, - height, - 0); - } - link->dc->hwss.set_disp_pattern_generator(link->dc, - pipe_ctx, - CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, - CONTROLLER_DP_COLOR_SPACE_UDEFINED, - color_depth, - NULL, - dpg_width, - height, - 0); - } - } - break; - - default: - break; - } -} - -bool dc_link_dp_set_test_pattern( - struct dc_link *link, - enum dp_test_pattern test_pattern, - enum dp_test_pattern_color_space test_pattern_color_space, - const struct link_training_settings *p_link_settings, - const unsigned char *p_custom_pattern, - unsigned int cust_pattern_size) -{ - struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; - struct pipe_ctx *pipe_ctx = NULL; - unsigned int lane; - unsigned int i; - unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0}; - union dpcd_training_pattern training_pattern; - enum dpcd_phy_test_patterns pattern; - - memset(&training_pattern, 0, sizeof(training_pattern)); - - for (i = 0; i < MAX_PIPES; i++) { - if (pipes[i].stream == NULL) - continue; - - if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) { - pipe_ctx = &pipes[i]; - break; - } - } - - if (pipe_ctx == NULL) - return false; - - /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */ - if (link->test_pattern_enabled && test_pattern == - DP_TEST_PATTERN_VIDEO_MODE) { - /* Set CRTC Test Pattern */ - set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); - dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, - (uint8_t *)p_custom_pattern, - (uint32_t)cust_pattern_size); - - /* Unblank Stream */ - link->dc->hwss.unblank_stream( - pipe_ctx, - &link->verified_link_cap); - /* TODO:m_pHwss->MuteAudioEndpoint - * (pPathMode->pDisplayPath, false); - */ - - /* Reset Test Pattern state */ - link->test_pattern_enabled = false; - - return true; - } - - /* Check for PHY Test Patterns */ - if (is_dp_phy_pattern(test_pattern)) { - /* Set DPCD Lane Settings before running test pattern */ - if (p_link_settings != NULL) { - if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && - p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { - dp_fixed_vs_pe_set_retimer_lane_settings( - link, - p_link_settings->dpcd_lane_settings, - p_link_settings->link_settings.lane_count); - } else { - dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX); - } - dpcd_set_lane_settings(link, p_link_settings, DPRX); - } - - /* Blank stream if running test pattern */ - if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { - /*TODO: - * m_pHwss-> - * MuteAudioEndpoint(pPathMode->pDisplayPath, true); - */ - /* Blank stream */ - link->dc->hwss.blank_stream(pipe_ctx); - } - - dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, - (uint8_t *)p_custom_pattern, - (uint32_t)cust_pattern_size); - - if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { - /* Set Test Pattern state */ - link->test_pattern_enabled = true; - if (p_link_settings != NULL) - dpcd_set_link_settings(link, - p_link_settings); - } - - switch (test_pattern) { - case DP_TEST_PATTERN_VIDEO_MODE: - pattern = PHY_TEST_PATTERN_NONE; - break; - case DP_TEST_PATTERN_D102: - pattern = PHY_TEST_PATTERN_D10_2; - break; - case DP_TEST_PATTERN_SYMBOL_ERROR: - pattern = PHY_TEST_PATTERN_SYMBOL_ERROR; - break; - case DP_TEST_PATTERN_PRBS7: - pattern = PHY_TEST_PATTERN_PRBS7; - break; - case DP_TEST_PATTERN_80BIT_CUSTOM: - pattern = PHY_TEST_PATTERN_80BIT_CUSTOM; - break; - case DP_TEST_PATTERN_CP2520_1: - pattern = PHY_TEST_PATTERN_CP2520_1; - break; - case DP_TEST_PATTERN_CP2520_2: - pattern = PHY_TEST_PATTERN_CP2520_2; - break; - case DP_TEST_PATTERN_CP2520_3: - pattern = PHY_TEST_PATTERN_CP2520_3; - break; - case DP_TEST_PATTERN_128b_132b_TPS1: - pattern = PHY_TEST_PATTERN_128b_132b_TPS1; - break; - case DP_TEST_PATTERN_128b_132b_TPS2: - pattern = PHY_TEST_PATTERN_128b_132b_TPS2; - break; - case DP_TEST_PATTERN_PRBS9: - pattern = PHY_TEST_PATTERN_PRBS9; - break; - case DP_TEST_PATTERN_PRBS11: - pattern = PHY_TEST_PATTERN_PRBS11; - break; - case DP_TEST_PATTERN_PRBS15: - pattern = PHY_TEST_PATTERN_PRBS15; - break; - case DP_TEST_PATTERN_PRBS23: - pattern = PHY_TEST_PATTERN_PRBS23; - break; - case DP_TEST_PATTERN_PRBS31: - pattern = PHY_TEST_PATTERN_PRBS31; - break; - case DP_TEST_PATTERN_264BIT_CUSTOM: - pattern = PHY_TEST_PATTERN_264BIT_CUSTOM; - break; - case DP_TEST_PATTERN_SQUARE: - pattern = PHY_TEST_PATTERN_SQUARE; - break; - case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: - pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; - break; - case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: - pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; - break; - case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: - pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; - break; - default: - return false; - } - - if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE - /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/) - return false; - - if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { - if (is_dp_phy_sqaure_pattern(test_pattern)) - core_link_write_dpcd(link, - DP_LINK_SQUARE_PATTERN, - p_custom_pattern, - 1); - - /* tell receiver that we are sending qualification - * pattern DP 1.2 or later - DP receiver's link quality - * pattern is set using DPCD LINK_QUAL_LANEx_SET - * register (0x10B~0x10E)\ - */ - for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) - link_qual_pattern[lane] = - (unsigned char)(pattern); - - core_link_write_dpcd(link, - DP_LINK_QUAL_LANE0_SET, - link_qual_pattern, - sizeof(link_qual_pattern)); - } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 || - link->dpcd_caps.dpcd_rev.raw == 0) { - /* tell receiver that we are sending qualification - * pattern DP 1.1a or earlier - DP receiver's link - * quality pattern is set using - * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET - * register (0x102). We will use v_1.3 when we are - * setting test pattern for DP 1.1. - */ - core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET, - &training_pattern.raw, - sizeof(training_pattern)); - training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern; - core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET, - &training_pattern.raw, - sizeof(training_pattern)); - } - } else { - enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; - - switch (test_pattern_color_space) { - case DP_TEST_PATTERN_COLOR_SPACE_RGB: - color_space = COLOR_SPACE_SRGB; - if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) - color_space = COLOR_SPACE_SRGB_LIMITED; - break; - - case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: - color_space = COLOR_SPACE_YCBCR601; - if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) - color_space = COLOR_SPACE_YCBCR601_LIMITED; - break; - case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: - color_space = COLOR_SPACE_YCBCR709; - if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) - color_space = COLOR_SPACE_YCBCR709_LIMITED; - break; - default: - break; - } - - if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) { - if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { - union dmub_hw_lock_flags hw_locks = { 0 }; - struct dmub_hw_lock_inst_flags inst_flags = { 0 }; - - hw_locks.bits.lock_dig = 1; - inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; - - dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, - true, - &hw_locks, - &inst_flags); - } else - pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable( - pipe_ctx->stream_res.tg); - } - - pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); - /* update MSA to requested color space */ - pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc, - &pipe_ctx->stream->timing, - color_space, - pipe_ctx->stream->use_vsc_sdp_for_colorimetry, - link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP); - - if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) { - if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) - pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range - else - pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7); - resource_build_info_frame(pipe_ctx); - link->dc->hwss.update_info_frame(pipe_ctx); - } - - /* CRTC Patterns */ - set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); - pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, - CRTC_STATE_VACTIVE); - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, - CRTC_STATE_VBLANK); - pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, - CRTC_STATE_VACTIVE); - - if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) { - if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { - union dmub_hw_lock_flags hw_locks = { 0 }; - struct dmub_hw_lock_inst_flags inst_flags = { 0 }; - - hw_locks.bits.lock_dig = 1; - inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; - - dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, - false, - &hw_locks, - &inst_flags); - } else - pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable( - pipe_ctx->stream_res.tg); - } - - /* Set Test Pattern state */ - link->test_pattern_enabled = true; - } - - return true; -} - void dp_enable_mst_on_sink(struct dc_link *link, bool enable) { unsigned char mstmCntl; @@ -1281,43 +403,6 @@ void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) &dp_test_mode, sizeof(dp_test_mode)); } -void dp_retrain_link_dp_test(struct dc_link *link, - struct dc_link_settings *link_setting, - bool skip_video_pattern) -{ - struct pipe_ctx *pipe; - unsigned int i; - - udelay(100); - - for (i = 0; i < MAX_PIPES; i++) { - pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream != NULL && - pipe->stream->link == link && - !pipe->stream->dpms_off && - !pipe->top_pipe && !pipe->prev_odm_pipe) { - core_link_disable_stream(pipe); - pipe->link_config.dp_link_settings = *link_setting; - update_dp_encoder_resources_for_test_harness( - link->dc, - pipe->stream->ctx->dc->current_state, - pipe); - } - } - - for (i = 0; i < MAX_PIPES; i++) { - pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream != NULL && - pipe->stream->link == link && - !pipe->stream->dpms_off && - !pipe->top_pipe && !pipe->prev_odm_pipe) { - core_link_enable_stream( - pipe->stream->ctx->dc->current_state, - pipe); - } - } -} - #undef DC_LOGGER #define DC_LOGGER \ dsc->ctx->logger diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index 10bef15d980e..2440d2103e18 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -74,8 +74,6 @@ struct fixed31_32 calculate_sst_avg_time_slots_per_mtp( const struct dc_link *link); void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable); void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode); -void dp_retrain_link_dp_test(struct dc_link *link, - struct dc_link_settings *link_setting, - bool skip_video_pattern); + #endif /* __DC_LINK_DP_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 3ecb72be4dac..0f642cbac3d5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -26,7 +26,7 @@ ############################################################################### # accessories ############################################################################### -LINK_ACCESSORIES = link_dp_trace.o +LINK_ACCESSORIES = link_dp_trace.o link_dp_cts.o AMD_DAL_LINK_ACCESSORIES = $(addprefix $(AMDDALPATH)/dc/link/accessories/, \ $(LINK_ACCESSORIES)) diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c new file mode 100644 index 000000000000..7fb2c0b4c4bb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -0,0 +1,1055 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include "link_dp_cts.h" +#include "link/protocols/link_dpcd.h" +#include "link/protocols/link_dp_training.h" +#include "link/protocols/link_dp_phy.h" +#include "link/protocols/link_dp_training_fixed_vs_pe_retimer.h" +#include "resource.h" +#include "dm_helpers.h" +#include "dc_dmub_srv.h" +#include "dce/dmub_hw_lock_mgr.h" + +#define DC_LOGGER \ + link->ctx->logger + +static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate) +{ + switch (test_rate) { + case DP_TEST_LINK_RATE_RBR: + return LINK_RATE_LOW; + case DP_TEST_LINK_RATE_HBR: + return LINK_RATE_HIGH; + case DP_TEST_LINK_RATE_HBR2: + return LINK_RATE_HIGH2; + case DP_TEST_LINK_RATE_HBR3: + return LINK_RATE_HIGH3; + case DP_TEST_LINK_RATE_UHBR10: + return LINK_RATE_UHBR10; + case DP_TEST_LINK_RATE_UHBR20: + return LINK_RATE_UHBR20; + case DP_TEST_LINK_RATE_UHBR13_5: + return LINK_RATE_UHBR13_5; + default: + return LINK_RATE_UNKNOWN; + } +} + +static bool is_dp_phy_sqaure_pattern(enum dp_test_pattern test_pattern) +{ + return (DP_TEST_PATTERN_SQUARE_BEGIN <= test_pattern && + test_pattern <= DP_TEST_PATTERN_SQUARE_END); +} + +static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) +{ + if ((DP_TEST_PATTERN_PHY_PATTERN_BEGIN <= test_pattern && + test_pattern <= DP_TEST_PATTERN_PHY_PATTERN_END) || + test_pattern == DP_TEST_PATTERN_VIDEO_MODE) + return true; + else + return false; +} + +void dp_retrain_link_dp_test(struct dc_link *link, + struct dc_link_settings *link_setting, + bool skip_video_pattern) +{ + struct pipe_ctx *pipe; + unsigned int i; + + udelay(100); + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream != NULL && + pipe->stream->link == link && + !pipe->stream->dpms_off && + !pipe->top_pipe && !pipe->prev_odm_pipe) { + core_link_disable_stream(pipe); + pipe->link_config.dp_link_settings = *link_setting; + update_dp_encoder_resources_for_test_harness( + link->dc, + pipe->stream->ctx->dc->current_state, + pipe); + } + } + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream != NULL && + pipe->stream->link == link && + !pipe->stream->dpms_off && + !pipe->top_pipe && !pipe->prev_odm_pipe) { + core_link_enable_stream( + pipe->stream->ctx->dc->current_state, + pipe); + } + } +} + +static void dp_test_send_link_training(struct dc_link *link) +{ + struct dc_link_settings link_settings = {0}; + uint8_t test_rate = 0; + + core_link_read_dpcd( + link, + DP_TEST_LANE_COUNT, + (unsigned char *)(&link_settings.lane_count), + 1); + core_link_read_dpcd( + link, + DP_TEST_LINK_RATE, + &test_rate, + 1); + link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate); + + /* Set preferred link settings */ + link->verified_link_cap.lane_count = link_settings.lane_count; + link->verified_link_cap.link_rate = link_settings.link_rate; + + dp_retrain_link_dp_test(link, &link_settings, false); +} + +static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video) +{ + union audio_test_mode dpcd_test_mode = {0}; + struct audio_test_pattern_type dpcd_pattern_type = {0}; + union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0}; + enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; + + struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; + struct pipe_ctx *pipe_ctx = &pipes[0]; + unsigned int channel_count; + unsigned int channel = 0; + unsigned int modes = 0; + unsigned int sampling_rate_in_hz = 0; + + // get audio test mode and test pattern parameters + core_link_read_dpcd( + link, + DP_TEST_AUDIO_MODE, + &dpcd_test_mode.raw, + sizeof(dpcd_test_mode)); + + core_link_read_dpcd( + link, + DP_TEST_AUDIO_PATTERN_TYPE, + &dpcd_pattern_type.value, + sizeof(dpcd_pattern_type)); + + channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT); + + // read pattern periods for requested channels when sawTooth pattern is requested + if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH || + dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) { + + test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ? + DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED; + // read period for each channel + for (channel = 0; channel < channel_count; channel++) { + core_link_read_dpcd( + link, + DP_TEST_AUDIO_PERIOD_CH1 + channel, + &dpcd_pattern_period[channel].raw, + sizeof(dpcd_pattern_period[channel])); + } + } + + // translate sampling rate + switch (dpcd_test_mode.bits.sampling_rate) { + case AUDIO_SAMPLING_RATE_32KHZ: + sampling_rate_in_hz = 32000; + break; + case AUDIO_SAMPLING_RATE_44_1KHZ: + sampling_rate_in_hz = 44100; + break; + case AUDIO_SAMPLING_RATE_48KHZ: + sampling_rate_in_hz = 48000; + break; + case AUDIO_SAMPLING_RATE_88_2KHZ: + sampling_rate_in_hz = 88200; + break; + case AUDIO_SAMPLING_RATE_96KHZ: + sampling_rate_in_hz = 96000; + break; + case AUDIO_SAMPLING_RATE_176_4KHZ: + sampling_rate_in_hz = 176400; + break; + case AUDIO_SAMPLING_RATE_192KHZ: + sampling_rate_in_hz = 192000; + break; + default: + sampling_rate_in_hz = 0; + break; + } + + link->audio_test_data.flags.test_requested = 1; + link->audio_test_data.flags.disable_video = disable_video; + link->audio_test_data.sampling_rate = sampling_rate_in_hz; + link->audio_test_data.channel_count = channel_count; + link->audio_test_data.pattern_type = test_pattern; + + if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) { + for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) { + link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period; + } + } +} + +/* TODO Raven hbr2 compliance eye output is unstable + * (toggling on and off) with debugger break + * This caueses intermittent PHY automation failure + * Need to look into the root cause */ +static void dp_test_send_phy_test_pattern(struct dc_link *link) +{ + union phy_test_pattern dpcd_test_pattern; + union lane_adjust dpcd_lane_adjustment[2]; + unsigned char dpcd_post_cursor_2_adjustment = 0; + unsigned char test_pattern_buffer[ + (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 - + DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0}; + unsigned int test_pattern_size = 0; + enum dp_test_pattern test_pattern; + union lane_adjust dpcd_lane_adjust; + unsigned int lane; + struct link_training_settings link_training_settings; + unsigned char no_preshoot = 0; + unsigned char no_deemphasis = 0; + + dpcd_test_pattern.raw = 0; + memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment)); + memset(&link_training_settings, 0, sizeof(link_training_settings)); + + /* get phy test pattern and pattern parameters from DP receiver */ + core_link_read_dpcd( + link, + DP_PHY_TEST_PATTERN, + &dpcd_test_pattern.raw, + sizeof(dpcd_test_pattern)); + core_link_read_dpcd( + link, + DP_ADJUST_REQUEST_LANE0_1, + &dpcd_lane_adjustment[0].raw, + sizeof(dpcd_lane_adjustment)); + + /* prepare link training settings */ + link_training_settings.link_settings = link->cur_link_settings; + + link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings); + + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) + dp_fixed_vs_pe_read_lane_adjust( + link, + link_training_settings.dpcd_lane_settings); + + /*get post cursor 2 parameters + * For DP 1.1a or eariler, this DPCD register's value is 0 + * For DP 1.2 or later: + * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1 + * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3 + */ + core_link_read_dpcd( + link, + DP_ADJUST_REQUEST_POST_CURSOR2, + &dpcd_post_cursor_2_adjustment, + sizeof(dpcd_post_cursor_2_adjustment)); + + /* translate request */ + switch (dpcd_test_pattern.bits.PATTERN) { + case PHY_TEST_PATTERN_D10_2: + test_pattern = DP_TEST_PATTERN_D102; + break; + case PHY_TEST_PATTERN_SYMBOL_ERROR: + test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR; + break; + case PHY_TEST_PATTERN_PRBS7: + test_pattern = DP_TEST_PATTERN_PRBS7; + break; + case PHY_TEST_PATTERN_80BIT_CUSTOM: + test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM; + break; + case PHY_TEST_PATTERN_CP2520_1: + /* CP2520 pattern is unstable, temporarily use TPS4 instead */ + test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? + DP_TEST_PATTERN_TRAINING_PATTERN4 : + DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; + break; + case PHY_TEST_PATTERN_CP2520_2: + /* CP2520 pattern is unstable, temporarily use TPS4 instead */ + test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ? + DP_TEST_PATTERN_TRAINING_PATTERN4 : + DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE; + break; + case PHY_TEST_PATTERN_CP2520_3: + test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4; + break; + case PHY_TEST_PATTERN_128b_132b_TPS1: + test_pattern = DP_TEST_PATTERN_128b_132b_TPS1; + break; + case PHY_TEST_PATTERN_128b_132b_TPS2: + test_pattern = DP_TEST_PATTERN_128b_132b_TPS2; + break; + case PHY_TEST_PATTERN_PRBS9: + test_pattern = DP_TEST_PATTERN_PRBS9; + break; + case PHY_TEST_PATTERN_PRBS11: + test_pattern = DP_TEST_PATTERN_PRBS11; + break; + case PHY_TEST_PATTERN_PRBS15: + test_pattern = DP_TEST_PATTERN_PRBS15; + break; + case PHY_TEST_PATTERN_PRBS23: + test_pattern = DP_TEST_PATTERN_PRBS23; + break; + case PHY_TEST_PATTERN_PRBS31: + test_pattern = DP_TEST_PATTERN_PRBS31; + break; + case PHY_TEST_PATTERN_264BIT_CUSTOM: + test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM; + break; + case PHY_TEST_PATTERN_SQUARE: + test_pattern = DP_TEST_PATTERN_SQUARE; + break; + case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; + no_preshoot = 1; + break; + case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; + no_deemphasis = 1; + break; + case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: + test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; + no_preshoot = 1; + no_deemphasis = 1; + break; + default: + test_pattern = DP_TEST_PATTERN_VIDEO_MODE; + break; + } + + if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) { + test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 - + DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1; + core_link_read_dpcd( + link, + DP_TEST_80BIT_CUSTOM_PATTERN_7_0, + test_pattern_buffer, + test_pattern_size); + } + + if (is_dp_phy_sqaure_pattern(test_pattern)) { + test_pattern_size = 1; // Square pattern data is 1 byte (DP spec) + core_link_read_dpcd( + link, + DP_PHY_SQUARE_PATTERN, + test_pattern_buffer, + test_pattern_size); + } + + if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) { + test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256- + DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1; + core_link_read_dpcd( + link, + DP_TEST_264BIT_CUSTOM_PATTERN_7_0, + test_pattern_buffer, + test_pattern_size); + } + + for (lane = 0; lane < + (unsigned int)(link->cur_link_settings.lane_count); + lane++) { + dpcd_lane_adjust.raw = + dp_get_nibble_at_index(&dpcd_lane_adjustment[0].raw, lane); + if (link_dp_get_encoding_format(&link->cur_link_settings) == + DP_8b_10b_ENCODING) { + link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING = + (enum dc_voltage_swing) + (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE); + link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS = + (enum dc_pre_emphasis) + (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE); + link_training_settings.hw_lane_settings[lane].POST_CURSOR2 = + (enum dc_post_cursor2) + ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03); + } else if (link_dp_get_encoding_format(&link->cur_link_settings) == + DP_128b_132b_ENCODING) { + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level = + dpcd_lane_adjust.tx_ffe.PRESET_VALUE; + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot; + link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis; + } + } + + dp_hw_to_dpcd_lane_settings(&link_training_settings, + link_training_settings.hw_lane_settings, + link_training_settings.dpcd_lane_settings); + /*Usage: Measure DP physical lane signal + * by DP SI test equipment automatically. + * PHY test pattern request is generated by equipment via HPD interrupt. + * HPD needs to be active all the time. HPD should be active + * all the time. Do not touch it. + * forward request to DS + */ + dc_link_dp_set_test_pattern( + link, + test_pattern, + DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED, + &link_training_settings, + test_pattern_buffer, + test_pattern_size); +} + +static void set_crtc_test_pattern(struct dc_link *link, + struct pipe_ctx *pipe_ctx, + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space) +{ + enum controller_dp_test_pattern controller_test_pattern; + enum dc_color_depth color_depth = pipe_ctx-> + stream->timing.display_color_depth; + struct bit_depth_reduction_params params; + struct output_pixel_processor *opp = pipe_ctx->stream_res.opp; + int width = pipe_ctx->stream->timing.h_addressable + + pipe_ctx->stream->timing.h_border_left + + pipe_ctx->stream->timing.h_border_right; + int height = pipe_ctx->stream->timing.v_addressable + + pipe_ctx->stream->timing.v_border_bottom + + pipe_ctx->stream->timing.v_border_top; + + memset(¶ms, 0, sizeof(params)); + + switch (test_pattern) { + case DP_TEST_PATTERN_COLOR_SQUARES: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES; + break; + case DP_TEST_PATTERN_COLOR_SQUARES_CEA: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA; + break; + case DP_TEST_PATTERN_VERTICAL_BARS: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_VERTICALBARS; + break; + case DP_TEST_PATTERN_HORIZONTAL_BARS: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS; + break; + case DP_TEST_PATTERN_COLOR_RAMP: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_COLORRAMP; + break; + default: + controller_test_pattern = + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE; + break; + } + + switch (test_pattern) { + case DP_TEST_PATTERN_COLOR_SQUARES: + case DP_TEST_PATTERN_COLOR_SQUARES_CEA: + case DP_TEST_PATTERN_VERTICAL_BARS: + case DP_TEST_PATTERN_HORIZONTAL_BARS: + case DP_TEST_PATTERN_COLOR_RAMP: + { + /* disable bit depth reduction */ + pipe_ctx->stream->bit_depth_params = params; + opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + controller_test_pattern, color_depth); + else if (link->dc->hwss.set_disp_pattern_generator) { + struct pipe_ctx *odm_pipe; + enum controller_dp_color_space controller_color_space; + int opp_cnt = 1; + int offset = 0; + int dpg_width = width; + + switch (test_pattern_color_space) { + case DP_TEST_PATTERN_COLOR_SPACE_RGB: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_RGB; + break; + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR601; + break; + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_YCBCR709; + break; + case DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED: + default: + controller_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; + DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__); + ASSERT(0); + break; + } + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + dpg_width = width / opp_cnt; + offset = dpg_width; + + link->dc->hwss.set_disp_pattern_generator(link->dc, + pipe_ctx, + controller_test_pattern, + controller_color_space, + color_depth, + NULL, + dpg_width, + height, + 0); + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; + + odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); + link->dc->hwss.set_disp_pattern_generator(link->dc, + odm_pipe, + controller_test_pattern, + controller_color_space, + color_depth, + NULL, + dpg_width, + height, + offset); + offset += offset; + } + } + } + break; + case DP_TEST_PATTERN_VIDEO_MODE: + { + /* restore bitdepth reduction */ + resource_build_bit_depth_reduction_params(pipe_ctx->stream, ¶ms); + pipe_ctx->stream->bit_depth_params = params; + opp->funcs->opp_program_bit_depth_reduction(opp, ¶ms); + if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) + pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + color_depth); + else if (link->dc->hwss.set_disp_pattern_generator) { + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + int dpg_width; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + + dpg_width = width / opp_cnt; + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp; + + odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, ¶ms); + link->dc->hwss.set_disp_pattern_generator(link->dc, + odm_pipe, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + color_depth, + NULL, + dpg_width, + height, + 0); + } + link->dc->hwss.set_disp_pattern_generator(link->dc, + pipe_ctx, + CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, + CONTROLLER_DP_COLOR_SPACE_UDEFINED, + color_depth, + NULL, + dpg_width, + height, + 0); + } + } + break; + + default: + break; + } +} + +void dc_link_dp_handle_automated_test(struct dc_link *link) +{ + union test_request test_request; + union test_response test_response; + + memset(&test_request, 0, sizeof(test_request)); + memset(&test_response, 0, sizeof(test_response)); + + core_link_read_dpcd( + link, + DP_TEST_REQUEST, + &test_request.raw, + sizeof(union test_request)); + if (test_request.bits.LINK_TRAINING) { + /* ACK first to let DP RX test box monitor LT sequence */ + test_response.bits.ACK = 1; + core_link_write_dpcd( + link, + DP_TEST_RESPONSE, + &test_response.raw, + sizeof(test_response)); + dp_test_send_link_training(link); + /* no acknowledge request is needed again */ + test_response.bits.ACK = 0; + } + if (test_request.bits.LINK_TEST_PATTRN) { + union test_misc dpcd_test_params; + union link_test_pattern dpcd_test_pattern; + + memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern)); + memset(&dpcd_test_params, 0, sizeof(dpcd_test_params)); + + /* get link test pattern and pattern parameters */ + core_link_read_dpcd( + link, + DP_TEST_PATTERN, + &dpcd_test_pattern.raw, + sizeof(dpcd_test_pattern)); + core_link_read_dpcd( + link, + DP_TEST_MISC0, + &dpcd_test_params.raw, + sizeof(dpcd_test_params)); + test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(link->ctx, link, + dpcd_test_pattern, dpcd_test_params) ? 1 : 0; + } + + if (test_request.bits.AUDIO_TEST_PATTERN) { + dp_test_get_audio_test_data(link, test_request.bits.TEST_AUDIO_DISABLED_VIDEO); + test_response.bits.ACK = 1; + } + + if (test_request.bits.PHY_TEST_PATTERN) { + dp_test_send_phy_test_pattern(link); + test_response.bits.ACK = 1; + } + + /* send request acknowledgment */ + if (test_response.bits.ACK) + core_link_write_dpcd( + link, + DP_TEST_RESPONSE, + &test_response.raw, + sizeof(test_response)); +} + +bool dc_link_dp_set_test_pattern( + struct dc_link *link, + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size) +{ + struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx; + struct pipe_ctx *pipe_ctx = NULL; + unsigned int lane; + unsigned int i; + unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0}; + union dpcd_training_pattern training_pattern; + enum dpcd_phy_test_patterns pattern; + + memset(&training_pattern, 0, sizeof(training_pattern)); + + for (i = 0; i < MAX_PIPES; i++) { + if (pipes[i].stream == NULL) + continue; + + if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) { + pipe_ctx = &pipes[i]; + break; + } + } + + if (pipe_ctx == NULL) + return false; + + /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */ + if (link->test_pattern_enabled && test_pattern == + DP_TEST_PATTERN_VIDEO_MODE) { + /* Set CRTC Test Pattern */ + set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, + (uint8_t *)p_custom_pattern, + (uint32_t)cust_pattern_size); + + /* Unblank Stream */ + link->dc->hwss.unblank_stream( + pipe_ctx, + &link->verified_link_cap); + /* TODO:m_pHwss->MuteAudioEndpoint + * (pPathMode->pDisplayPath, false); + */ + + /* Reset Test Pattern state */ + link->test_pattern_enabled = false; + + return true; + } + + /* Check for PHY Test Patterns */ + if (is_dp_phy_pattern(test_pattern)) { + /* Set DPCD Lane Settings before running test pattern */ + if (p_link_settings != NULL) { + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) { + dp_fixed_vs_pe_set_retimer_lane_settings( + link, + p_link_settings->dpcd_lane_settings, + p_link_settings->link_settings.lane_count); + } else { + dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX); + } + dpcd_set_lane_settings(link, p_link_settings, DPRX); + } + + /* Blank stream if running test pattern */ + if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { + /*TODO: + * m_pHwss-> + * MuteAudioEndpoint(pPathMode->pDisplayPath, true); + */ + /* Blank stream */ + link->dc->hwss.blank_stream(pipe_ctx); + } + + dp_set_hw_test_pattern(link, &pipe_ctx->link_res, test_pattern, + (uint8_t *)p_custom_pattern, + (uint32_t)cust_pattern_size); + + if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) { + /* Set Test Pattern state */ + link->test_pattern_enabled = true; + if (p_link_settings != NULL) + dpcd_set_link_settings(link, + p_link_settings); + } + + switch (test_pattern) { + case DP_TEST_PATTERN_VIDEO_MODE: + pattern = PHY_TEST_PATTERN_NONE; + break; + case DP_TEST_PATTERN_D102: + pattern = PHY_TEST_PATTERN_D10_2; + break; + case DP_TEST_PATTERN_SYMBOL_ERROR: + pattern = PHY_TEST_PATTERN_SYMBOL_ERROR; + break; + case DP_TEST_PATTERN_PRBS7: + pattern = PHY_TEST_PATTERN_PRBS7; + break; + case DP_TEST_PATTERN_80BIT_CUSTOM: + pattern = PHY_TEST_PATTERN_80BIT_CUSTOM; + break; + case DP_TEST_PATTERN_CP2520_1: + pattern = PHY_TEST_PATTERN_CP2520_1; + break; + case DP_TEST_PATTERN_CP2520_2: + pattern = PHY_TEST_PATTERN_CP2520_2; + break; + case DP_TEST_PATTERN_CP2520_3: + pattern = PHY_TEST_PATTERN_CP2520_3; + break; + case DP_TEST_PATTERN_128b_132b_TPS1: + pattern = PHY_TEST_PATTERN_128b_132b_TPS1; + break; + case DP_TEST_PATTERN_128b_132b_TPS2: + pattern = PHY_TEST_PATTERN_128b_132b_TPS2; + break; + case DP_TEST_PATTERN_PRBS9: + pattern = PHY_TEST_PATTERN_PRBS9; + break; + case DP_TEST_PATTERN_PRBS11: + pattern = PHY_TEST_PATTERN_PRBS11; + break; + case DP_TEST_PATTERN_PRBS15: + pattern = PHY_TEST_PATTERN_PRBS15; + break; + case DP_TEST_PATTERN_PRBS23: + pattern = PHY_TEST_PATTERN_PRBS23; + break; + case DP_TEST_PATTERN_PRBS31: + pattern = PHY_TEST_PATTERN_PRBS31; + break; + case DP_TEST_PATTERN_264BIT_CUSTOM: + pattern = PHY_TEST_PATTERN_264BIT_CUSTOM; + break; + case DP_TEST_PATTERN_SQUARE: + pattern = PHY_TEST_PATTERN_SQUARE; + break; + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED; + break; + case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED; + break; + case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED: + pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED; + break; + default: + return false; + } + + if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE + /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/) + return false; + + if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) { + if (is_dp_phy_sqaure_pattern(test_pattern)) + core_link_write_dpcd(link, + DP_LINK_SQUARE_PATTERN, + p_custom_pattern, + 1); + + /* tell receiver that we are sending qualification + * pattern DP 1.2 or later - DP receiver's link quality + * pattern is set using DPCD LINK_QUAL_LANEx_SET + * register (0x10B~0x10E)\ + */ + for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) + link_qual_pattern[lane] = + (unsigned char)(pattern); + + core_link_write_dpcd(link, + DP_LINK_QUAL_LANE0_SET, + link_qual_pattern, + sizeof(link_qual_pattern)); + } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 || + link->dpcd_caps.dpcd_rev.raw == 0) { + /* tell receiver that we are sending qualification + * pattern DP 1.1a or earlier - DP receiver's link + * quality pattern is set using + * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET + * register (0x102). We will use v_1.3 when we are + * setting test pattern for DP 1.1. + */ + core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET, + &training_pattern.raw, + sizeof(training_pattern)); + training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern; + core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET, + &training_pattern.raw, + sizeof(training_pattern)); + } + } else { + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + + switch (test_pattern_color_space) { + case DP_TEST_PATTERN_COLOR_SPACE_RGB: + color_space = COLOR_SPACE_SRGB; + if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) + color_space = COLOR_SPACE_SRGB_LIMITED; + break; + + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601: + color_space = COLOR_SPACE_YCBCR601; + if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) + color_space = COLOR_SPACE_YCBCR601_LIMITED; + break; + case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709: + color_space = COLOR_SPACE_YCBCR709; + if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) + color_space = COLOR_SPACE_YCBCR709_LIMITED; + break; + default: + break; + } + + if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) { + if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { + union dmub_hw_lock_flags hw_locks = { 0 }; + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; + + hw_locks.bits.lock_dig = 1; + inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; + + dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, + true, + &hw_locks, + &inst_flags); + } else + pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable( + pipe_ctx->stream_res.tg); + } + + pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + /* update MSA to requested color space */ + pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(pipe_ctx->stream_res.stream_enc, + &pipe_ctx->stream->timing, + color_space, + pipe_ctx->stream->use_vsc_sdp_for_colorimetry, + link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP); + + if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) { + if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA) + pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range + else + pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7); + resource_build_info_frame(pipe_ctx); + link->dc->hwss.update_info_frame(pipe_ctx); + } + + /* CRTC Patterns */ + set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space); + pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, + CRTC_STATE_VACTIVE); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, + CRTC_STATE_VBLANK); + pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, + CRTC_STATE_VACTIVE); + + if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) { + if (pipe_ctx->stream && should_use_dmub_lock(pipe_ctx->stream->link)) { + union dmub_hw_lock_flags hw_locks = { 0 }; + struct dmub_hw_lock_inst_flags inst_flags = { 0 }; + + hw_locks.bits.lock_dig = 1; + inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst; + + dmub_hw_lock_mgr_cmd(link->ctx->dmub_srv, + false, + &hw_locks, + &inst_flags); + } else + pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable( + pipe_ctx->stream_res.tg); + } + + /* Set Test Pattern state */ + link->test_pattern_enabled = true; + } + + return true; +} + +void dc_link_set_drive_settings(struct dc *dc, + struct link_training_settings *lt_settings, + const struct dc_link *link) +{ + + int i; + struct link_resource link_res; + + for (i = 0; i < dc->link_count; i++) + if (dc->links[i] == link) + break; + + if (i >= dc->link_count) + ASSERT_CRITICAL(false); + + dc_link_get_cur_link_res(link, &link_res); + dp_set_drive_settings(dc->links[i], &link_res, lt_settings); +} + +void dc_link_set_preferred_link_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link *link) +{ + int i; + struct pipe_ctx *pipe; + struct dc_stream_state *link_stream; + struct dc_link_settings store_settings = *link_setting; + + link->preferred_link_setting = store_settings; + + /* Retrain with preferred link settings only relevant for + * DP signal type + * Check for non-DP signal or if passive dongle present + */ + if (!dc_is_dp_signal(link->connector_signal) || + link->dongle_max_pix_clk > 0) + return; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->stream->link) { + if (pipe->stream->link == link) { + link_stream = pipe->stream; + break; + } + } + } + + /* Stream not found */ + if (i == MAX_PIPES) + return; + + /* Cannot retrain link if backend is off */ + if (link_stream->dpms_off) + return; + + if (link_decide_link_settings(link_stream, &store_settings)) + dp_retrain_link_dp_test(link, &store_settings, false); +} + +void dc_link_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain) +{ + if (lt_overrides != NULL) + link->preferred_training_settings = *lt_overrides; + else + memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings)); + + if (link_setting != NULL) { + link->preferred_link_setting = *link_setting; + } else { + link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; + link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN; + } + + if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && + link->type == dc_connection_mst_branch) + dm_helpers_dp_mst_update_branch_bandwidth(dc->ctx, link); + + /* Retrain now, or wait until next stream update to apply */ + if (skip_immediate_retrain == false) + dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); +} + +void dc_link_set_test_pattern(struct dc_link *link, + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size) +{ + if (link != NULL) + dc_link_dp_set_test_pattern( + link, + test_pattern, + test_pattern_color_space, + p_link_settings, + p_custom_pattern, + cust_pattern_size); +} diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h new file mode 100644 index 000000000000..7f17838b653b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h @@ -0,0 +1,33 @@ +/* + * Copyright 2023 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef __LINK_DP_CTS_H__ +#define __LINK_DP_CTS_H__ +#include "link.h" + +void dp_retrain_link_dp_test(struct dc_link *link, + struct dc_link_settings *link_setting, + bool skip_video_pattern); + +#endif /* __LINK_DP_CTS_H__ */ |