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