Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / dc / link / protocols / link_dp_training_8b_10b.c
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
26 /* FILE POLICY AND INTENDED USAGE:
27  * This file implements dp 8b/10b link training software policies and
28  * sequences.
29  */
30 #include "link_dp_training_8b_10b.h"
31 #include "link_dpcd.h"
32 #include "link_dp_phy.h"
33 #include "link_dp_capability.h"
34
35 #define DC_LOGGER \
36         link->ctx->logger
37
38 static int32_t get_cr_training_aux_rd_interval(struct dc_link *link,
39                 const struct dc_link_settings *link_settings)
40 {
41         union training_aux_rd_interval training_rd_interval;
42         uint32_t wait_in_micro_secs = 100;
43
44         memset(&training_rd_interval, 0, sizeof(training_rd_interval));
45         if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
46                         link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
47                 core_link_read_dpcd(
48                                 link,
49                                 DP_TRAINING_AUX_RD_INTERVAL,
50                                 (uint8_t *)&training_rd_interval,
51                                 sizeof(training_rd_interval));
52                 if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
53                         wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
54         }
55         return wait_in_micro_secs;
56 }
57
58 static uint32_t get_eq_training_aux_rd_interval(
59         struct dc_link *link,
60         const struct dc_link_settings *link_settings)
61 {
62         union training_aux_rd_interval training_rd_interval;
63
64         memset(&training_rd_interval, 0, sizeof(training_rd_interval));
65         if (link_dp_get_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
66                 core_link_read_dpcd(
67                                 link,
68                                 DP_128B132B_TRAINING_AUX_RD_INTERVAL,
69                                 (uint8_t *)&training_rd_interval,
70                                 sizeof(training_rd_interval));
71         } else if (link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
72                         link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
73                 core_link_read_dpcd(
74                                 link,
75                                 DP_TRAINING_AUX_RD_INTERVAL,
76                                 (uint8_t *)&training_rd_interval,
77                                 sizeof(training_rd_interval));
78         }
79
80         switch (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL) {
81         case 0: return 400;
82         case 1: return 4000;
83         case 2: return 8000;
84         case 3: return 12000;
85         case 4: return 16000;
86         case 5: return 32000;
87         case 6: return 64000;
88         default: return 400;
89         }
90 }
91
92 void decide_8b_10b_training_settings(
93          struct dc_link *link,
94         const struct dc_link_settings *link_setting,
95         struct link_training_settings *lt_settings)
96 {
97         memset(lt_settings, '\0', sizeof(struct link_training_settings));
98
99         /* Initialize link settings */
100         lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
101         lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
102         lt_settings->link_settings.link_rate = link_setting->link_rate;
103         lt_settings->link_settings.lane_count = link_setting->lane_count;
104         /* TODO hard coded to SS for now
105          * lt_settings.link_settings.link_spread =
106          * dal_display_path_is_ss_supported(
107          * path_mode->display_path) ?
108          * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
109          * LINK_SPREAD_DISABLED;
110          */
111         lt_settings->link_settings.link_spread = link->dp_ss_off ?
112                         LINK_SPREAD_DISABLED : LINK_SPREAD_05_DOWNSPREAD_30KHZ;
113         lt_settings->cr_pattern_time = get_cr_training_aux_rd_interval(link, link_setting);
114         lt_settings->eq_pattern_time = get_eq_training_aux_rd_interval(link, link_setting);
115         lt_settings->pattern_for_cr = decide_cr_training_pattern(link_setting);
116         lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_setting);
117         lt_settings->enhanced_framing = 1;
118         lt_settings->should_set_fec_ready = true;
119         lt_settings->disallow_per_lane_settings = true;
120         lt_settings->always_match_dpcd_with_hw_lane_settings = true;
121         lt_settings->lttpr_mode = dp_decide_8b_10b_lttpr_mode(link);
122         dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
123 }
124
125 enum lttpr_mode dp_decide_8b_10b_lttpr_mode(struct dc_link *link)
126 {
127         bool is_lttpr_present = dp_is_lttpr_present(link);
128         bool vbios_lttpr_force_non_transparent = link->dc->caps.vbios_lttpr_enable;
129         bool vbios_lttpr_aware = link->dc->caps.vbios_lttpr_aware;
130
131         if (!is_lttpr_present)
132                 return LTTPR_MODE_NON_LTTPR;
133
134         if (vbios_lttpr_aware) {
135                 if (vbios_lttpr_force_non_transparent) {
136                         DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT due to VBIOS DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
137                         return LTTPR_MODE_NON_TRANSPARENT;
138                 } else {
139                         DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default due to VBIOS not set DCE_INFO_CAPS_LTTPR_SUPPORT_ENABLE set to 1.\n");
140                         return LTTPR_MODE_TRANSPARENT;
141                 }
142         }
143
144         if (link->dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A &&
145                         link->dc->caps.extended_aux_timeout_support) {
146                 DC_LOG_DC("chose LTTPR_MODE_NON_TRANSPARENT by default and dc->config.allow_lttpr_non_transparent_mode.bits.DP1_4A set to 1.\n");
147                 return LTTPR_MODE_NON_TRANSPARENT;
148         }
149
150         DC_LOG_DC("chose LTTPR_MODE_NON_LTTPR.\n");
151         return LTTPR_MODE_NON_LTTPR;
152 }
153
154 enum link_training_result perform_8b_10b_clock_recovery_sequence(
155         struct dc_link *link,
156         const struct link_resource *link_res,
157         struct link_training_settings *lt_settings,
158         uint32_t offset)
159 {
160         uint32_t retries_cr;
161         uint32_t retry_count;
162         uint32_t wait_time_microsec;
163         enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
164         union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
165         union lane_align_status_updated dpcd_lane_status_updated;
166         union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
167
168         retries_cr = 0;
169         retry_count = 0;
170
171         memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
172         memset(&dpcd_lane_status_updated, '\0',
173         sizeof(dpcd_lane_status_updated));
174
175         if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
176                 dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
177
178         /* najeeb - The synaptics MST hub can put the LT in
179         * infinite loop by switching the VS
180         */
181         /* between level 0 and level 1 continuously, here
182         * we try for CR lock for LinkTrainingMaxCRRetry count*/
183         while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
184                 (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
185
186
187                 /* 1. call HWSS to set lane settings*/
188                 dp_set_hw_lane_settings(
189                                 link,
190                                 link_res,
191                                 lt_settings,
192                                 offset);
193
194                 /* 2. update DPCD of the receiver*/
195                 if (!retry_count)
196                         /* EPR #361076 - write as a 5-byte burst,
197                          * but only for the 1-st iteration.*/
198                         dpcd_set_lt_pattern_and_lane_settings(
199                                         link,
200                                         lt_settings,
201                                         lt_settings->pattern_for_cr,
202                                         offset);
203                 else
204                         dpcd_set_lane_settings(
205                                         link,
206                                         lt_settings,
207                                         offset);
208
209                 /* 3. wait receiver to lock-on*/
210                 wait_time_microsec = lt_settings->cr_pattern_time;
211
212                 dp_wait_for_training_aux_rd_interval(
213                                 link,
214                                 wait_time_microsec);
215
216                 /* 4. Read lane status and requested drive
217                 * settings as set by the sink
218                 */
219                 dp_get_lane_status_and_lane_adjust(
220                                 link,
221                                 lt_settings,
222                                 dpcd_lane_status,
223                                 &dpcd_lane_status_updated,
224                                 dpcd_lane_adjust,
225                                 offset);
226
227                 /* 5. check CR done*/
228                 if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
229                         DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__);
230                         return LINK_TRAINING_SUCCESS;
231                 }
232
233                 /* 6. max VS reached*/
234                 if ((link_dp_get_encoding_format(&lt_settings->link_settings) ==
235                                 DP_8b_10b_ENCODING) &&
236                                 dp_is_max_vs_reached(lt_settings))
237                         break;
238
239                 /* 7. same lane settings*/
240                 /* Note: settings are the same for all lanes,
241                  * so comparing first lane is sufficient*/
242                 if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING) &&
243                                 lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
244                                                 dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
245                         retries_cr++;
246                 else if ((link_dp_get_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
247                                 lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
248                                                 dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
249                         retries_cr++;
250                 else
251                         retries_cr = 0;
252
253                 /* 8. update VS/PE/PC2 in lt_settings*/
254                 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
255                                 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
256                 retry_count++;
257         }
258
259         if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
260                 ASSERT(0);
261                 DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
262                         __func__,
263                         LINK_TRAINING_MAX_CR_RETRY);
264
265         }
266
267         return dp_get_cr_failure(lane_count, dpcd_lane_status);
268 }
269
270 enum link_training_result perform_8b_10b_channel_equalization_sequence(
271         struct dc_link *link,
272         const struct link_resource *link_res,
273         struct link_training_settings *lt_settings,
274         uint32_t offset)
275 {
276         enum dc_dp_training_pattern tr_pattern;
277         uint32_t retries_ch_eq;
278         uint32_t wait_time_microsec;
279         enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
280         union lane_align_status_updated dpcd_lane_status_updated = {0};
281         union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
282         union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
283
284         /* Note: also check that TPS4 is a supported feature*/
285         tr_pattern = lt_settings->pattern_for_eq;
286
287         if (is_repeater(lt_settings, offset) && link_dp_get_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
288                 tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
289
290         dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
291
292         for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
293                 retries_ch_eq++) {
294
295                 dp_set_hw_lane_settings(link, link_res, lt_settings, offset);
296
297                 /* 2. update DPCD*/
298                 if (!retries_ch_eq)
299                         /* EPR #361076 - write as a 5-byte burst,
300                          * but only for the 1-st iteration
301                          */
302
303                         dpcd_set_lt_pattern_and_lane_settings(
304                                 link,
305                                 lt_settings,
306                                 tr_pattern, offset);
307                 else
308                         dpcd_set_lane_settings(link, lt_settings, offset);
309
310                 /* 3. wait for receiver to lock-on*/
311                 wait_time_microsec = lt_settings->eq_pattern_time;
312
313                 if (is_repeater(lt_settings, offset))
314                         wait_time_microsec =
315                                         dp_translate_training_aux_read_interval(
316                                                 link->dpcd_caps.lttpr_caps.aux_rd_interval[offset - 1]);
317
318                 dp_wait_for_training_aux_rd_interval(
319                                 link,
320                                 wait_time_microsec);
321
322                 /* 4. Read lane status and requested
323                  * drive settings as set by the sink*/
324
325                 dp_get_lane_status_and_lane_adjust(
326                         link,
327                         lt_settings,
328                         dpcd_lane_status,
329                         &dpcd_lane_status_updated,
330                         dpcd_lane_adjust,
331                         offset);
332
333                 /* 5. check CR done*/
334                 if (!dp_is_cr_done(lane_count, dpcd_lane_status))
335                         return dpcd_lane_status[0].bits.CR_DONE_0 ?
336                                         LINK_TRAINING_EQ_FAIL_CR_PARTIAL :
337                                         LINK_TRAINING_EQ_FAIL_CR;
338
339                 /* 6. check CHEQ done*/
340                 if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
341                                 dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
342                                 dp_is_interlane_aligned(dpcd_lane_status_updated))
343                         return LINK_TRAINING_SUCCESS;
344
345                 /* 7. update VS/PE/PC2 in lt_settings*/
346                 dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
347                                 lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
348         }
349
350         return LINK_TRAINING_EQ_FAIL_EQ;
351
352 }
353
354 enum link_training_result dp_perform_8b_10b_link_training(
355                 struct dc_link *link,
356                 const struct link_resource *link_res,
357                 struct link_training_settings *lt_settings)
358 {
359         enum link_training_result status = LINK_TRAINING_SUCCESS;
360
361         uint8_t repeater_cnt;
362         uint8_t repeater_id;
363         uint8_t lane = 0;
364
365         if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
366                 start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
367
368         /* 1. set link rate, lane count and spread. */
369         dpcd_set_link_settings(link, lt_settings);
370
371         if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
372
373                 /* 2. perform link training (set link training done
374                  *  to false is done as well)
375                  */
376                 repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
377
378                 for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
379                                 repeater_id--) {
380                         status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
381
382                         if (status != LINK_TRAINING_SUCCESS) {
383                                 repeater_training_done(link, repeater_id);
384                                 break;
385                         }
386
387                         status = perform_8b_10b_channel_equalization_sequence(link,
388                                         link_res,
389                                         lt_settings,
390                                         repeater_id);
391                         if (status == LINK_TRAINING_SUCCESS)
392                                 DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
393
394                         repeater_training_done(link, repeater_id);
395
396                         if (status != LINK_TRAINING_SUCCESS)
397                                 break;
398
399                         for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
400                                 lt_settings->dpcd_lane_settings[lane].raw = 0;
401                                 lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
402                                 lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
403                         }
404                 }
405         }
406
407         if (status == LINK_TRAINING_SUCCESS) {
408                 status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
409                 if (status == LINK_TRAINING_SUCCESS) {
410                         status = perform_8b_10b_channel_equalization_sequence(link,
411                                         link_res,
412                                         lt_settings,
413                                         DPRX);
414                         if (status == LINK_TRAINING_SUCCESS)
415                                 DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
416                 }
417         }
418
419         return status;
420 }