1/*
2 * Copyright 2022 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25#include "link_dp_cts.h"
26#include "link/link_resource.h"
27#include "link/protocols/link_dpcd.h"
28#include "link/protocols/link_dp_training.h"
29#include "link/protocols/link_dp_phy.h"
30#include "link/protocols/link_dp_training_fixed_vs_pe_retimer.h"
31#include "link/protocols/link_dp_capability.h"
32#include "link/link_dpms.h"
33#include "resource.h"
34#include "dm_helpers.h"
35#include "dc_dmub_srv.h"
36#include "dce/dmub_hw_lock_mgr.h"
37
38#define DC_LOGGER \
39 link->ctx->logger
40
41static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
42{
43 switch (test_rate) {
44 case DP_TEST_LINK_RATE_RBR:
45 return LINK_RATE_LOW;
46 case DP_TEST_LINK_RATE_HBR:
47 return LINK_RATE_HIGH;
48 case DP_TEST_LINK_RATE_HBR2:
49 return LINK_RATE_HIGH2;
50 case DP_TEST_LINK_RATE_HBR3:
51 return LINK_RATE_HIGH3;
52 case DP_TEST_LINK_RATE_UHBR10:
53 return LINK_RATE_UHBR10;
54 case DP_TEST_LINK_RATE_UHBR20:
55 return LINK_RATE_UHBR20;
56 case DP_TEST_LINK_RATE_UHBR13_5_LEGACY:
57 case DP_TEST_LINK_RATE_UHBR13_5:
58 return LINK_RATE_UHBR13_5;
59 default:
60 return LINK_RATE_UNKNOWN;
61 }
62}
63
64static void dp_retrain_link_dp_test(struct dc_link *link,
65 struct dc_link_settings *link_setting,
66 bool skip_video_pattern)
67{
68 struct pipe_ctx *pipes[MAX_PIPES];
69 struct dc_state *state = link->dc->current_state;
70 uint8_t count;
71 int i;
72
73 udelay(100);
74
75 link_get_master_pipes_with_dpms_on(link, state, count: &count, pipes);
76
77 for (i = 0; i < count; i++) {
78 link_set_dpms_off(pipe_ctx: pipes[i]);
79 pipes[i]->link_config.dp_link_settings = *link_setting;
80 update_dp_encoder_resources_for_test_harness(
81 dc: link->dc,
82 context: state,
83 pipe_ctx: pipes[i]);
84 }
85
86 for (i = count-1; i >= 0; i--)
87 link_set_dpms_on(state, pipe_ctx: pipes[i]);
88}
89
90static void dp_test_send_link_training(struct dc_link *link)
91{
92 struct dc_link_settings link_settings = {0};
93 uint8_t test_rate = 0;
94
95 core_link_read_dpcd(
96 link,
97 DP_TEST_LANE_COUNT,
98 data: (unsigned char *)(&link_settings.lane_count),
99 size: 1);
100 core_link_read_dpcd(
101 link,
102 DP_TEST_LINK_RATE,
103 data: &test_rate,
104 size: 1);
105 link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
106
107 if (link_settings.link_rate == LINK_RATE_UNKNOWN) {
108 DC_LOG_ERROR("%s: Invalid test link rate.", __func__);
109 ASSERT(0);
110 }
111
112 /* Set preferred link settings */
113 link->verified_link_cap.lane_count = link_settings.lane_count;
114 link->verified_link_cap.link_rate = link_settings.link_rate;
115
116 dp_retrain_link_dp_test(link, link_setting: &link_settings, skip_video_pattern: false);
117}
118
119static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video)
120{
121 union audio_test_mode dpcd_test_mode = {0};
122 struct audio_test_pattern_type dpcd_pattern_type = {0};
123 union audio_test_pattern_period dpcd_pattern_period[AUDIO_CHANNELS_COUNT] = {0};
124 enum dp_test_pattern test_pattern = DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
125
126 struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
127 struct pipe_ctx *pipe_ctx = &pipes[0];
128 unsigned int channel_count;
129 unsigned int channel = 0;
130 unsigned int modes = 0;
131 unsigned int sampling_rate_in_hz = 0;
132
133 // get audio test mode and test pattern parameters
134 core_link_read_dpcd(
135 link,
136 DP_TEST_AUDIO_MODE,
137 data: &dpcd_test_mode.raw,
138 size: sizeof(dpcd_test_mode));
139
140 core_link_read_dpcd(
141 link,
142 DP_TEST_AUDIO_PATTERN_TYPE,
143 data: &dpcd_pattern_type.value,
144 size: sizeof(dpcd_pattern_type));
145
146 channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
147
148 // read pattern periods for requested channels when sawTooth pattern is requested
149 if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
150 dpcd_pattern_type.value == AUDIO_TEST_PATTERN_OPERATOR_DEFINED) {
151
152 test_pattern = (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH) ?
153 DP_TEST_PATTERN_AUDIO_SAWTOOTH : DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED;
154 // read period for each channel
155 for (channel = 0; channel < channel_count; channel++) {
156 core_link_read_dpcd(
157 link,
158 DP_TEST_AUDIO_PERIOD_CH1 + channel,
159 data: &dpcd_pattern_period[channel].raw,
160 size: sizeof(dpcd_pattern_period[channel]));
161 }
162 }
163
164 // translate sampling rate
165 switch (dpcd_test_mode.bits.sampling_rate) {
166 case AUDIO_SAMPLING_RATE_32KHZ:
167 sampling_rate_in_hz = 32000;
168 break;
169 case AUDIO_SAMPLING_RATE_44_1KHZ:
170 sampling_rate_in_hz = 44100;
171 break;
172 case AUDIO_SAMPLING_RATE_48KHZ:
173 sampling_rate_in_hz = 48000;
174 break;
175 case AUDIO_SAMPLING_RATE_88_2KHZ:
176 sampling_rate_in_hz = 88200;
177 break;
178 case AUDIO_SAMPLING_RATE_96KHZ:
179 sampling_rate_in_hz = 96000;
180 break;
181 case AUDIO_SAMPLING_RATE_176_4KHZ:
182 sampling_rate_in_hz = 176400;
183 break;
184 case AUDIO_SAMPLING_RATE_192KHZ:
185 sampling_rate_in_hz = 192000;
186 break;
187 default:
188 sampling_rate_in_hz = 0;
189 break;
190 }
191
192 link->audio_test_data.flags.test_requested = 1;
193 link->audio_test_data.flags.disable_video = disable_video;
194 link->audio_test_data.sampling_rate = sampling_rate_in_hz;
195 link->audio_test_data.channel_count = channel_count;
196 link->audio_test_data.pattern_type = test_pattern;
197
198 if (test_pattern == DP_TEST_PATTERN_AUDIO_SAWTOOTH) {
199 for (modes = 0; modes < pipe_ctx->stream->audio_info.mode_count; modes++) {
200 link->audio_test_data.pattern_period[modes] = dpcd_pattern_period[modes].bits.pattern_period;
201 }
202 }
203}
204
205/* TODO Raven hbr2 compliance eye output is unstable
206 * (toggling on and off) with debugger break
207 * This caueses intermittent PHY automation failure
208 * Need to look into the root cause */
209static void dp_test_send_phy_test_pattern(struct dc_link *link)
210{
211 union phy_test_pattern dpcd_test_pattern;
212 union lane_adjust dpcd_lane_adjustment[2];
213 unsigned char dpcd_post_cursor_2_adjustment = 0;
214 unsigned char test_pattern_buffer[
215 (DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
216 DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
217 unsigned int test_pattern_size = 0;
218 enum dp_test_pattern test_pattern;
219 union lane_adjust dpcd_lane_adjust;
220 unsigned int lane;
221 struct link_training_settings link_training_settings;
222 unsigned char no_preshoot = 0;
223 unsigned char no_deemphasis = 0;
224
225 dpcd_test_pattern.raw = 0;
226 memset(dpcd_lane_adjustment, 0, sizeof(dpcd_lane_adjustment));
227 memset(&link_training_settings, 0, sizeof(link_training_settings));
228
229 /* get phy test pattern and pattern parameters from DP receiver */
230 core_link_read_dpcd(
231 link,
232 DP_PHY_TEST_PATTERN,
233 data: &dpcd_test_pattern.raw,
234 size: sizeof(dpcd_test_pattern));
235 core_link_read_dpcd(
236 link,
237 DP_ADJUST_REQUEST_LANE0_1,
238 data: &dpcd_lane_adjustment[0].raw,
239 size: sizeof(dpcd_lane_adjustment));
240
241 /* prepare link training settings */
242 link_training_settings.link_settings = link->cur_link_settings;
243
244 link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, link_setting: &link->cur_link_settings);
245
246 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
247 link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT)
248 dp_fixed_vs_pe_read_lane_adjust(
249 link,
250 dpcd_lane_adjust: link_training_settings.dpcd_lane_settings);
251
252 /*get post cursor 2 parameters
253 * For DP 1.1a or eariler, this DPCD register's value is 0
254 * For DP 1.2 or later:
255 * Bits 1:0 = POST_CURSOR2_LANE0; Bits 3:2 = POST_CURSOR2_LANE1
256 * Bits 5:4 = POST_CURSOR2_LANE2; Bits 7:6 = POST_CURSOR2_LANE3
257 */
258 core_link_read_dpcd(
259 link,
260 DP_ADJUST_REQUEST_POST_CURSOR2,
261 data: &dpcd_post_cursor_2_adjustment,
262 size: sizeof(dpcd_post_cursor_2_adjustment));
263
264 /* translate request */
265 switch (dpcd_test_pattern.bits.PATTERN) {
266 case PHY_TEST_PATTERN_D10_2:
267 test_pattern = DP_TEST_PATTERN_D102;
268 break;
269 case PHY_TEST_PATTERN_SYMBOL_ERROR:
270 test_pattern = DP_TEST_PATTERN_SYMBOL_ERROR;
271 break;
272 case PHY_TEST_PATTERN_PRBS7:
273 test_pattern = DP_TEST_PATTERN_PRBS7;
274 break;
275 case PHY_TEST_PATTERN_80BIT_CUSTOM:
276 test_pattern = DP_TEST_PATTERN_80BIT_CUSTOM;
277 break;
278 case PHY_TEST_PATTERN_CP2520_1:
279 /* CP2520 pattern is unstable, temporarily use TPS4 instead */
280 test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
281 DP_TEST_PATTERN_TRAINING_PATTERN4 :
282 DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
283 break;
284 case PHY_TEST_PATTERN_CP2520_2:
285 /* CP2520 pattern is unstable, temporarily use TPS4 instead */
286 test_pattern = (link->dc->caps.force_dp_tps4_for_cp2520 == 1) ?
287 DP_TEST_PATTERN_TRAINING_PATTERN4 :
288 DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE;
289 break;
290 case PHY_TEST_PATTERN_CP2520_3:
291 test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
292 break;
293 case PHY_TEST_PATTERN_128b_132b_TPS1:
294 test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
295 break;
296 case PHY_TEST_PATTERN_128b_132b_TPS2:
297 test_pattern = DP_TEST_PATTERN_128b_132b_TPS2;
298 break;
299 case PHY_TEST_PATTERN_PRBS9:
300 test_pattern = DP_TEST_PATTERN_PRBS9;
301 break;
302 case PHY_TEST_PATTERN_PRBS11:
303 test_pattern = DP_TEST_PATTERN_PRBS11;
304 break;
305 case PHY_TEST_PATTERN_PRBS15:
306 test_pattern = DP_TEST_PATTERN_PRBS15;
307 break;
308 case PHY_TEST_PATTERN_PRBS23:
309 test_pattern = DP_TEST_PATTERN_PRBS23;
310 break;
311 case PHY_TEST_PATTERN_PRBS31:
312 test_pattern = DP_TEST_PATTERN_PRBS31;
313 break;
314 case PHY_TEST_PATTERN_264BIT_CUSTOM:
315 test_pattern = DP_TEST_PATTERN_264BIT_CUSTOM;
316 break;
317 case PHY_TEST_PATTERN_SQUARE:
318 test_pattern = DP_TEST_PATTERN_SQUARE;
319 break;
320 case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
321 test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
322 no_preshoot = 1;
323 break;
324 case PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
325 test_pattern = DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
326 no_deemphasis = 1;
327 break;
328 case PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
329 test_pattern = DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
330 no_preshoot = 1;
331 no_deemphasis = 1;
332 break;
333 default:
334 test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
335 break;
336 }
337
338 if (test_pattern == DP_TEST_PATTERN_80BIT_CUSTOM) {
339 test_pattern_size = (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
340 DP_TEST_80BIT_CUSTOM_PATTERN_7_0) + 1;
341 core_link_read_dpcd(
342 link,
343 DP_TEST_80BIT_CUSTOM_PATTERN_7_0,
344 data: test_pattern_buffer,
345 size: test_pattern_size);
346 }
347
348 if (IS_DP_PHY_SQUARE_PATTERN(test_pattern)) {
349 test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
350 core_link_read_dpcd(
351 link,
352 DP_PHY_SQUARE_PATTERN,
353 data: test_pattern_buffer,
354 size: test_pattern_size);
355 }
356
357 if (test_pattern == DP_TEST_PATTERN_264BIT_CUSTOM) {
358 test_pattern_size = (DP_TEST_264BIT_CUSTOM_PATTERN_263_256-
359 DP_TEST_264BIT_CUSTOM_PATTERN_7_0) + 1;
360 core_link_read_dpcd(
361 link,
362 DP_TEST_264BIT_CUSTOM_PATTERN_7_0,
363 data: test_pattern_buffer,
364 size: test_pattern_size);
365 }
366
367 for (lane = 0; lane <
368 (unsigned int)(link->cur_link_settings.lane_count);
369 lane++) {
370 dpcd_lane_adjust.raw =
371 dp_get_nibble_at_index(buf: &dpcd_lane_adjustment[0].raw, index: lane);
372 if (link_dp_get_encoding_format(link_settings: &link->cur_link_settings) ==
373 DP_8b_10b_ENCODING) {
374 link_training_settings.hw_lane_settings[lane].VOLTAGE_SWING =
375 (enum dc_voltage_swing)
376 (dpcd_lane_adjust.bits.VOLTAGE_SWING_LANE);
377 link_training_settings.hw_lane_settings[lane].PRE_EMPHASIS =
378 (enum dc_pre_emphasis)
379 (dpcd_lane_adjust.bits.PRE_EMPHASIS_LANE);
380 link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
381 (enum dc_post_cursor2)
382 ((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
383 } else if (link_dp_get_encoding_format(link_settings: &link->cur_link_settings) ==
384 DP_128b_132b_ENCODING) {
385 link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.level =
386 dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
387 link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_preshoot = no_preshoot;
388 link_training_settings.hw_lane_settings[lane].FFE_PRESET.settings.no_deemphasis = no_deemphasis;
389 }
390 }
391
392 dp_hw_to_dpcd_lane_settings(lt_settings: &link_training_settings,
393 hw_lane_settings: link_training_settings.hw_lane_settings,
394 dpcd_lane_settings: link_training_settings.dpcd_lane_settings);
395 /*Usage: Measure DP physical lane signal
396 * by DP SI test equipment automatically.
397 * PHY test pattern request is generated by equipment via HPD interrupt.
398 * HPD needs to be active all the time. HPD should be active
399 * all the time. Do not touch it.
400 * forward request to DS
401 */
402 dp_set_test_pattern(
403 link,
404 test_pattern,
405 test_pattern_color_space: DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED,
406 p_link_settings: &link_training_settings,
407 p_custom_pattern: test_pattern_buffer,
408 cust_pattern_size: test_pattern_size);
409}
410
411static void set_crtc_test_pattern(struct dc_link *link,
412 struct pipe_ctx *pipe_ctx,
413 enum dp_test_pattern test_pattern,
414 enum dp_test_pattern_color_space test_pattern_color_space)
415{
416 enum controller_dp_test_pattern controller_test_pattern;
417 enum dc_color_depth color_depth = pipe_ctx->
418 stream->timing.display_color_depth;
419 struct bit_depth_reduction_params params;
420 struct output_pixel_processor *opp = pipe_ctx->stream_res.opp;
421 struct pipe_ctx *odm_pipe;
422 struct test_pattern_params *tp_params;
423
424 memset(&params, 0, sizeof(params));
425
426 resource_build_test_pattern_params(res_ctx: &link->dc->current_state->res_ctx,
427 pipe_ctx);
428 controller_test_pattern = pipe_ctx->stream_res.test_pattern_params.test_pattern;
429
430 switch (test_pattern) {
431 case DP_TEST_PATTERN_COLOR_SQUARES:
432 case DP_TEST_PATTERN_COLOR_SQUARES_CEA:
433 case DP_TEST_PATTERN_VERTICAL_BARS:
434 case DP_TEST_PATTERN_HORIZONTAL_BARS:
435 case DP_TEST_PATTERN_COLOR_RAMP:
436 {
437 /* disable bit depth reduction */
438 pipe_ctx->stream->bit_depth_params = params;
439 if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) {
440 opp->funcs->opp_program_bit_depth_reduction(opp, &params);
441 pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
442 controller_test_pattern, color_depth);
443 } else if (link->dc->hwss.set_disp_pattern_generator) {
444 enum controller_dp_color_space controller_color_space;
445 struct output_pixel_processor *odm_opp;
446
447 controller_color_space = pipe_ctx->stream_res.test_pattern_params.color_space;
448
449 if (controller_color_space == CONTROLLER_DP_COLOR_SPACE_UDEFINED) {
450 DC_LOG_ERROR("%s: Color space must be defined for test pattern", __func__);
451 ASSERT(0);
452 }
453
454 odm_pipe = pipe_ctx;
455 while (odm_pipe) {
456 tp_params = &odm_pipe->stream_res.test_pattern_params;
457 odm_opp = odm_pipe->stream_res.opp;
458 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
459 link->dc->hwss.set_disp_pattern_generator(link->dc,
460 odm_pipe,
461 tp_params->test_pattern,
462 tp_params->color_space,
463 tp_params->color_depth,
464 NULL,
465 tp_params->width,
466 tp_params->height,
467 tp_params->offset);
468 odm_pipe = odm_pipe->next_odm_pipe;
469 }
470 }
471 }
472 break;
473 case DP_TEST_PATTERN_VIDEO_MODE:
474 {
475 /* restore bitdepth reduction */
476 resource_build_bit_depth_reduction_params(stream: pipe_ctx->stream, fmt_bit_depth: &params);
477 pipe_ctx->stream->bit_depth_params = params;
478 if (pipe_ctx->stream_res.tg->funcs->set_test_pattern) {
479 opp->funcs->opp_program_bit_depth_reduction(opp, &params);
480 pipe_ctx->stream_res.tg->funcs->set_test_pattern(pipe_ctx->stream_res.tg,
481 CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
482 color_depth);
483 } else if (link->dc->hwss.set_disp_pattern_generator) {
484 struct output_pixel_processor *odm_opp;
485
486 odm_pipe = pipe_ctx;
487 while (odm_pipe) {
488 tp_params = &odm_pipe->stream_res.test_pattern_params;
489 odm_opp = odm_pipe->stream_res.opp;
490 odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
491 link->dc->hwss.set_disp_pattern_generator(link->dc,
492 odm_pipe,
493 tp_params->test_pattern,
494 tp_params->color_space,
495 tp_params->color_depth,
496 NULL,
497 tp_params->width,
498 tp_params->height,
499 tp_params->offset);
500 odm_pipe = odm_pipe->next_odm_pipe;
501 }
502 }
503 }
504 break;
505
506 default:
507 break;
508 }
509}
510
511void dp_handle_automated_test(struct dc_link *link)
512{
513 union test_request test_request;
514 union test_response test_response;
515
516 memset(&test_request, 0, sizeof(test_request));
517 memset(&test_response, 0, sizeof(test_response));
518
519 core_link_read_dpcd(
520 link,
521 DP_TEST_REQUEST,
522 data: &test_request.raw,
523 size: sizeof(union test_request));
524 if (test_request.bits.LINK_TRAINING) {
525 /* ACK first to let DP RX test box monitor LT sequence */
526 test_response.bits.ACK = 1;
527 core_link_write_dpcd(
528 link,
529 DP_TEST_RESPONSE,
530 data: &test_response.raw,
531 size: sizeof(test_response));
532 dp_test_send_link_training(link);
533 /* no acknowledge request is needed again */
534 test_response.bits.ACK = 0;
535 }
536 if (test_request.bits.LINK_TEST_PATTRN) {
537 union test_misc dpcd_test_params;
538 union link_test_pattern dpcd_test_pattern;
539
540 memset(&dpcd_test_pattern, 0, sizeof(dpcd_test_pattern));
541 memset(&dpcd_test_params, 0, sizeof(dpcd_test_params));
542
543 /* get link test pattern and pattern parameters */
544 core_link_read_dpcd(
545 link,
546 DP_TEST_PATTERN,
547 data: &dpcd_test_pattern.raw,
548 size: sizeof(dpcd_test_pattern));
549 core_link_read_dpcd(
550 link,
551 DP_TEST_MISC0,
552 data: &dpcd_test_params.raw,
553 size: sizeof(dpcd_test_params));
554 test_response.bits.ACK = dm_helpers_dp_handle_test_pattern_request(ctx: link->ctx, link,
555 dpcd_test_pattern, dpcd_test_params) ? 1 : 0;
556 }
557
558 if (test_request.bits.AUDIO_TEST_PATTERN) {
559 dp_test_get_audio_test_data(link, disable_video: test_request.bits.TEST_AUDIO_DISABLED_VIDEO);
560 test_response.bits.ACK = 1;
561 }
562
563 if (test_request.bits.PHY_TEST_PATTERN) {
564 dp_test_send_phy_test_pattern(link);
565 test_response.bits.ACK = 1;
566 }
567
568 /* send request acknowledgment */
569 if (test_response.bits.ACK)
570 core_link_write_dpcd(
571 link,
572 DP_TEST_RESPONSE,
573 data: &test_response.raw,
574 size: sizeof(test_response));
575}
576
577bool dp_set_test_pattern(
578 struct dc_link *link,
579 enum dp_test_pattern test_pattern,
580 enum dp_test_pattern_color_space test_pattern_color_space,
581 const struct link_training_settings *p_link_settings,
582 const unsigned char *p_custom_pattern,
583 unsigned int cust_pattern_size)
584{
585 const struct link_hwss *link_hwss;
586 struct pipe_ctx *pipes = link->dc->current_state->res_ctx.pipe_ctx;
587 struct pipe_ctx *pipe_ctx = NULL;
588 unsigned int lane;
589 unsigned int i;
590 unsigned char link_qual_pattern[LANE_COUNT_DP_MAX] = {0};
591 union dpcd_training_pattern training_pattern;
592 enum dpcd_phy_test_patterns pattern;
593
594 memset(&training_pattern, 0, sizeof(training_pattern));
595
596 for (i = 0; i < MAX_PIPES; i++) {
597 if (pipes[i].stream == NULL)
598 continue;
599
600 if (resource_is_pipe_type(pipe_ctx: &pipes[i], type: OTG_MASTER) &&
601 pipes[i].stream->link == link) {
602 pipe_ctx = &pipes[i];
603 break;
604 }
605 }
606
607 if (pipe_ctx == NULL)
608 return false;
609
610 link->pending_test_pattern = test_pattern;
611
612 /* Reset CRTC Test Pattern if it is currently running and request is VideoMode */
613 if (link->test_pattern_enabled && test_pattern ==
614 DP_TEST_PATTERN_VIDEO_MODE) {
615 /* Set CRTC Test Pattern */
616 set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
617 dp_set_hw_test_pattern(link, link_res: &pipe_ctx->link_res, test_pattern,
618 custom_pattern: (uint8_t *)p_custom_pattern,
619 custom_pattern_size: (uint32_t)cust_pattern_size);
620
621 /* Unblank Stream */
622 link->dc->hwss.unblank_stream(
623 pipe_ctx,
624 &link->verified_link_cap);
625 /* TODO:m_pHwss->MuteAudioEndpoint
626 * (pPathMode->pDisplayPath, false);
627 */
628
629 /* Reset Test Pattern state */
630 link->test_pattern_enabled = false;
631 link->current_test_pattern = test_pattern;
632 link->pending_test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
633
634 return true;
635 }
636
637 /* Check for PHY Test Patterns */
638 if (IS_DP_PHY_PATTERN(test_pattern)) {
639 /* Set DPCD Lane Settings before running test pattern */
640 if (p_link_settings != NULL) {
641 if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
642 p_link_settings->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
643 dp_fixed_vs_pe_set_retimer_lane_settings(
644 link,
645 dpcd_lane_adjust: p_link_settings->dpcd_lane_settings,
646 lane_count: p_link_settings->link_settings.lane_count);
647 } else {
648 dp_set_hw_lane_settings(link, link_res: &pipe_ctx->link_res, link_settings: p_link_settings, offset: DPRX);
649 }
650 dpcd_set_lane_settings(link, link_training_setting: p_link_settings, offset: DPRX);
651 }
652
653 /* Blank stream if running test pattern */
654 if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
655 /*TODO:
656 * m_pHwss->
657 * MuteAudioEndpoint(pPathMode->pDisplayPath, true);
658 */
659 /* Blank stream */
660 link->dc->hwss.blank_stream(pipe_ctx);
661 }
662
663 dp_set_hw_test_pattern(link, link_res: &pipe_ctx->link_res, test_pattern,
664 custom_pattern: (uint8_t *)p_custom_pattern,
665 custom_pattern_size: (uint32_t)cust_pattern_size);
666
667 if (test_pattern != DP_TEST_PATTERN_VIDEO_MODE) {
668 /* Set Test Pattern state */
669 link->test_pattern_enabled = true;
670 link->current_test_pattern = test_pattern;
671 link->pending_test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
672 if (p_link_settings != NULL)
673 dpcd_set_link_settings(link,
674 lt_settings: p_link_settings);
675 }
676
677 switch (test_pattern) {
678 case DP_TEST_PATTERN_VIDEO_MODE:
679 pattern = PHY_TEST_PATTERN_NONE;
680 break;
681 case DP_TEST_PATTERN_D102:
682 pattern = PHY_TEST_PATTERN_D10_2;
683 break;
684 case DP_TEST_PATTERN_SYMBOL_ERROR:
685 pattern = PHY_TEST_PATTERN_SYMBOL_ERROR;
686 break;
687 case DP_TEST_PATTERN_PRBS7:
688 pattern = PHY_TEST_PATTERN_PRBS7;
689 break;
690 case DP_TEST_PATTERN_80BIT_CUSTOM:
691 pattern = PHY_TEST_PATTERN_80BIT_CUSTOM;
692 break;
693 case DP_TEST_PATTERN_CP2520_1:
694 pattern = PHY_TEST_PATTERN_CP2520_1;
695 break;
696 case DP_TEST_PATTERN_CP2520_2:
697 pattern = PHY_TEST_PATTERN_CP2520_2;
698 break;
699 case DP_TEST_PATTERN_CP2520_3:
700 pattern = PHY_TEST_PATTERN_CP2520_3;
701 break;
702 case DP_TEST_PATTERN_128b_132b_TPS1:
703 pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
704 break;
705 case DP_TEST_PATTERN_128b_132b_TPS2:
706 pattern = PHY_TEST_PATTERN_128b_132b_TPS2;
707 break;
708 case DP_TEST_PATTERN_PRBS9:
709 pattern = PHY_TEST_PATTERN_PRBS9;
710 break;
711 case DP_TEST_PATTERN_PRBS11:
712 pattern = PHY_TEST_PATTERN_PRBS11;
713 break;
714 case DP_TEST_PATTERN_PRBS15:
715 pattern = PHY_TEST_PATTERN_PRBS15;
716 break;
717 case DP_TEST_PATTERN_PRBS23:
718 pattern = PHY_TEST_PATTERN_PRBS23;
719 break;
720 case DP_TEST_PATTERN_PRBS31:
721 pattern = PHY_TEST_PATTERN_PRBS31;
722 break;
723 case DP_TEST_PATTERN_264BIT_CUSTOM:
724 pattern = PHY_TEST_PATTERN_264BIT_CUSTOM;
725 break;
726 case DP_TEST_PATTERN_SQUARE:
727 pattern = PHY_TEST_PATTERN_SQUARE;
728 break;
729 case DP_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED:
730 pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DISABLED;
731 break;
732 case DP_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED:
733 pattern = PHY_TEST_PATTERN_SQUARE_DEEMPHASIS_DISABLED;
734 break;
735 case DP_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED:
736 pattern = PHY_TEST_PATTERN_SQUARE_PRESHOOT_DEEMPHASIS_DISABLED;
737 break;
738 default:
739 return false;
740 }
741
742 if (test_pattern == DP_TEST_PATTERN_VIDEO_MODE
743 /*TODO:&& !pPathMode->pDisplayPath->IsTargetPoweredOn()*/)
744 return false;
745
746 if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
747 if (IS_DP_PHY_SQUARE_PATTERN(test_pattern))
748 core_link_write_dpcd(link,
749 DP_LINK_SQUARE_PATTERN,
750 data: p_custom_pattern,
751 size: 1);
752
753 /* tell receiver that we are sending qualification
754 * pattern DP 1.2 or later - DP receiver's link quality
755 * pattern is set using DPCD LINK_QUAL_LANEx_SET
756 * register (0x10B~0x10E)\
757 */
758 for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++)
759 link_qual_pattern[lane] =
760 (unsigned char)(pattern);
761
762 core_link_write_dpcd(link,
763 DP_LINK_QUAL_LANE0_SET,
764 data: link_qual_pattern,
765 size: sizeof(link_qual_pattern));
766 } else if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_10 ||
767 link->dpcd_caps.dpcd_rev.raw == 0) {
768 /* tell receiver that we are sending qualification
769 * pattern DP 1.1a or earlier - DP receiver's link
770 * quality pattern is set using
771 * DPCD TRAINING_PATTERN_SET -> LINK_QUAL_PATTERN_SET
772 * register (0x102). We will use v_1.3 when we are
773 * setting test pattern for DP 1.1.
774 */
775 core_link_read_dpcd(link, DP_TRAINING_PATTERN_SET,
776 data: &training_pattern.raw,
777 size: sizeof(training_pattern));
778 training_pattern.v1_3.LINK_QUAL_PATTERN_SET = pattern;
779 core_link_write_dpcd(link, DP_TRAINING_PATTERN_SET,
780 data: &training_pattern.raw,
781 size: sizeof(training_pattern));
782 }
783 } else {
784 enum dc_color_space color_space = COLOR_SPACE_UNKNOWN;
785
786 switch (test_pattern_color_space) {
787 case DP_TEST_PATTERN_COLOR_SPACE_RGB:
788 color_space = COLOR_SPACE_SRGB;
789 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
790 color_space = COLOR_SPACE_SRGB_LIMITED;
791 break;
792
793 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR601:
794 color_space = COLOR_SPACE_YCBCR601;
795 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
796 color_space = COLOR_SPACE_YCBCR601_LIMITED;
797 break;
798 case DP_TEST_PATTERN_COLOR_SPACE_YCBCR709:
799 color_space = COLOR_SPACE_YCBCR709;
800 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
801 color_space = COLOR_SPACE_YCBCR709_LIMITED;
802 break;
803 default:
804 break;
805 }
806
807 if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable) {
808 if (pipe_ctx->stream && should_use_dmub_lock(link: pipe_ctx->stream->link)) {
809 union dmub_hw_lock_flags hw_locks = { 0 };
810 struct dmub_hw_lock_inst_flags inst_flags = { 0 };
811
812 hw_locks.bits.lock_dig = 1;
813 inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
814
815 dmub_hw_lock_mgr_cmd(dmub_srv: link->ctx->dmub_srv,
816 lock: true,
817 hw_locks: &hw_locks,
818 inst_flags: &inst_flags);
819 } else
820 pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_enable(
821 pipe_ctx->stream_res.tg);
822 }
823
824 pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg);
825 /* update MSA to requested color space */
826 link_hwss = get_link_hwss(link, link_res: &pipe_ctx->link_res);
827 pipe_ctx->stream->output_color_space = color_space;
828 link_hwss->setup_stream_attribute(pipe_ctx);
829
830 if (pipe_ctx->stream->use_vsc_sdp_for_colorimetry) {
831 if (test_pattern == DP_TEST_PATTERN_COLOR_SQUARES_CEA)
832 pipe_ctx->stream->vsc_infopacket.sb[17] |= (1 << 7); // sb17 bit 7 Dynamic Range: 0 = VESA range, 1 = CTA range
833 else
834 pipe_ctx->stream->vsc_infopacket.sb[17] &= ~(1 << 7);
835
836 if (color_space == COLOR_SPACE_YCBCR601_LIMITED)
837 pipe_ctx->stream->vsc_infopacket.sb[16] &= 0xf0;
838 else if (color_space == COLOR_SPACE_YCBCR709_LIMITED)
839 pipe_ctx->stream->vsc_infopacket.sb[16] |= 1;
840
841 resource_build_info_frame(pipe_ctx);
842 link->dc->hwss.update_info_frame(pipe_ctx);
843 }
844
845 /* CRTC Patterns */
846 set_crtc_test_pattern(link, pipe_ctx, test_pattern, test_pattern_color_space);
847 pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
848 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
849 CRTC_STATE_VACTIVE);
850 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
851 CRTC_STATE_VBLANK);
852 pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg,
853 CRTC_STATE_VACTIVE);
854
855 if (pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable) {
856 if (pipe_ctx->stream && should_use_dmub_lock(link: pipe_ctx->stream->link)) {
857 union dmub_hw_lock_flags hw_locks = { 0 };
858 struct dmub_hw_lock_inst_flags inst_flags = { 0 };
859
860 hw_locks.bits.lock_dig = 1;
861 inst_flags.dig_inst = pipe_ctx->stream_res.tg->inst;
862
863 dmub_hw_lock_mgr_cmd(dmub_srv: link->ctx->dmub_srv,
864 lock: false,
865 hw_locks: &hw_locks,
866 inst_flags: &inst_flags);
867 } else
868 pipe_ctx->stream_res.tg->funcs->lock_doublebuffer_disable(
869 pipe_ctx->stream_res.tg);
870 }
871
872 /* Set Test Pattern state */
873 link->test_pattern_enabled = true;
874 link->current_test_pattern = test_pattern;
875 link->pending_test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
876 }
877
878 return true;
879}
880
881void dp_set_preferred_link_settings(struct dc *dc,
882 struct dc_link_settings *link_setting,
883 struct dc_link *link)
884{
885 int i;
886 struct pipe_ctx *pipe;
887 struct dc_stream_state *link_stream;
888 struct dc_link_settings store_settings = *link_setting;
889
890 link->preferred_link_setting = store_settings;
891
892 /* Retrain with preferred link settings only relevant for
893 * DP signal type
894 * Check for non-DP signal or if passive dongle present
895 */
896 if (!dc_is_dp_signal(signal: link->connector_signal) ||
897 link->dongle_max_pix_clk > 0)
898 return;
899
900 for (i = 0; i < MAX_PIPES; i++) {
901 pipe = &dc->current_state->res_ctx.pipe_ctx[i];
902 if (pipe->stream && pipe->stream->link) {
903 if (pipe->stream->link == link) {
904 link_stream = pipe->stream;
905 break;
906 }
907 }
908 }
909
910 /* Stream not found */
911 if (i == MAX_PIPES)
912 return;
913
914 /* Cannot retrain link if backend is off */
915 if (link_stream->dpms_off)
916 return;
917
918 if (link_decide_link_settings(stream: link_stream, link_setting: &store_settings))
919 dp_retrain_link_dp_test(link, link_setting: &store_settings, skip_video_pattern: false);
920}
921
922void dp_set_preferred_training_settings(struct dc *dc,
923 struct dc_link_settings *link_setting,
924 struct dc_link_training_overrides *lt_overrides,
925 struct dc_link *link,
926 bool skip_immediate_retrain)
927{
928 if (lt_overrides != NULL)
929 link->preferred_training_settings = *lt_overrides;
930 else
931 memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
932
933 if (link_setting != NULL) {
934 link->preferred_link_setting = *link_setting;
935 } else {
936 link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
937 link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
938 }
939
940 if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT &&
941 link->type == dc_connection_mst_branch)
942 dm_helpers_dp_mst_update_branch_bandwidth(ctx: dc->ctx, link);
943
944 /* Retrain now, or wait until next stream update to apply */
945 if (skip_immediate_retrain == false)
946 dp_set_preferred_link_settings(dc, link_setting: &link->preferred_link_setting, link);
947}
948

source code of linux/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c