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 128b/132b link training software policies and
28 * sequences.
29 */
30#include "link_dp_training_128b_132b.h"
31#include "link_dp_training_8b_10b.h"
32#include "link_dpcd.h"
33#include "link_dp_phy.h"
34#include "link_dp_capability.h"
35
36#define DC_LOGGER \
37 link->ctx->logger
38
39static enum dc_status dpcd_128b_132b_set_lane_settings(
40 struct dc_link *link,
41 const struct link_training_settings *link_training_setting)
42{
43 enum dc_status status = core_link_write_dpcd(link,
44 DP_TRAINING_LANE0_SET,
45 data: (uint8_t *)(link_training_setting->dpcd_lane_settings),
46 size: sizeof(link_training_setting->dpcd_lane_settings));
47
48 DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
49 __func__,
50 DP_TRAINING_LANE0_SET,
51 link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
52 return status;
53}
54
55static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
56 uint32_t *interval_in_us)
57{
58 union dp_128b_132b_training_aux_rd_interval dpcd_interval;
59 uint32_t interval_unit = 0;
60
61 dpcd_interval.raw = 0;
62 core_link_read_dpcd(link, DP_128B132B_TRAINING_AUX_RD_INTERVAL,
63 data: &dpcd_interval.raw, size: sizeof(dpcd_interval.raw));
64 interval_unit = dpcd_interval.bits.UNIT ? 1 : 2; /* 0b = 2 ms, 1b = 1 ms */
65 /* (128b/132b_TRAINING_AUX_RD_INTERVAL value + 1) *
66 * INTERVAL_UNIT. The maximum is 256 ms
67 */
68 *interval_in_us = (dpcd_interval.bits.VALUE + 1) * interval_unit * 1000;
69}
70
71static enum link_training_result dp_perform_128b_132b_channel_eq_done_sequence(
72 struct dc_link *link,
73 const struct link_resource *link_res,
74 struct link_training_settings *lt_settings)
75{
76 uint8_t loop_count;
77 uint32_t aux_rd_interval = 0;
78 uint32_t wait_time = 0;
79 union lane_align_status_updated dpcd_lane_status_updated = {0};
80 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
81 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
82 enum dc_status status = DC_OK;
83 enum link_training_result result = LINK_TRAINING_SUCCESS;
84
85 /* Transmit 128b/132b_TPS1 over Main-Link */
86 dp_set_hw_training_pattern(link, link_res, pattern: lt_settings->pattern_for_cr, offset: DPRX);
87
88 /* Set TRAINING_PATTERN_SET to 01h */
89 dpcd_set_training_pattern(link, training_pattern: lt_settings->pattern_for_cr);
90
91 /* Adjust TX_FFE_PRESET_VALUE and Transmit 128b/132b_TPS2 over Main-Link */
92 dpcd_128b_132b_get_aux_rd_interval(link, interval_in_us: &aux_rd_interval);
93 dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status,
94 ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX);
95 dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust,
96 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
97 dp_set_hw_lane_settings(link, link_res, link_settings: lt_settings, offset: DPRX);
98 dp_set_hw_training_pattern(link, link_res, pattern: lt_settings->pattern_for_eq, offset: DPRX);
99
100 /* Set loop counter to start from 1 */
101 loop_count = 1;
102
103 /* Set TRAINING_PATTERN_SET to 02h and TX_FFE_PRESET_VALUE in one AUX transaction */
104 dpcd_set_lt_pattern_and_lane_settings(link, lt_settings,
105 pattern: lt_settings->pattern_for_eq, offset: DPRX);
106
107 /* poll for channel EQ done */
108 while (result == LINK_TRAINING_SUCCESS) {
109 dp_wait_for_training_aux_rd_interval(link, wait_in_micro_secs: aux_rd_interval);
110 wait_time += aux_rd_interval;
111 status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status,
112 ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX);
113 dp_decide_lane_settings(lt_settings, ln_adjust: dpcd_lane_adjust,
114 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
115 dpcd_128b_132b_get_aux_rd_interval(link, interval_in_us: &aux_rd_interval);
116 if (status != DC_OK) {
117 result = LINK_TRAINING_ABORT;
118 } else if (dp_is_ch_eq_done(ln_count: lt_settings->link_settings.lane_count,
119 dpcd_lane_status)) {
120 /* pass */
121 break;
122 } else if (loop_count >= lt_settings->eq_loop_count_limit) {
123 result = DP_128b_132b_MAX_LOOP_COUNT_REACHED;
124 } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
125 result = DP_128b_132b_LT_FAILED;
126 } else {
127 dp_set_hw_lane_settings(link, link_res, link_settings: lt_settings, offset: DPRX);
128 dpcd_128b_132b_set_lane_settings(link, link_training_setting: lt_settings);
129 }
130 loop_count++;
131 }
132
133 /* poll for EQ interlane align done */
134 while (result == LINK_TRAINING_SUCCESS) {
135 if (status != DC_OK) {
136 result = LINK_TRAINING_ABORT;
137 } else if (dpcd_lane_status_updated.bits.EQ_INTERLANE_ALIGN_DONE_128b_132b) {
138 /* pass */
139 break;
140 } else if (wait_time >= lt_settings->eq_wait_time_limit) {
141 result = DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT;
142 } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
143 result = DP_128b_132b_LT_FAILED;
144 } else {
145 dp_wait_for_training_aux_rd_interval(link,
146 wait_in_micro_secs: lt_settings->eq_pattern_time);
147 wait_time += lt_settings->eq_pattern_time;
148 status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status,
149 ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX);
150 }
151 }
152
153 return result;
154}
155
156static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
157 struct dc_link *link,
158 const struct link_resource *link_res,
159 struct link_training_settings *lt_settings)
160{
161 /* Assumption: assume hardware has transmitted eq pattern */
162 enum dc_status status = DC_OK;
163 enum link_training_result result = LINK_TRAINING_SUCCESS;
164 union lane_align_status_updated dpcd_lane_status_updated = {0};
165 union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
166 union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
167 uint32_t wait_time = 0;
168
169 /* initiate CDS done sequence */
170 dpcd_set_training_pattern(link, training_pattern: lt_settings->pattern_for_cds);
171
172 /* poll for CDS interlane align done and symbol lock */
173 while (result == LINK_TRAINING_SUCCESS) {
174 dp_wait_for_training_aux_rd_interval(link,
175 wait_in_micro_secs: lt_settings->cds_pattern_time);
176 wait_time += lt_settings->cds_pattern_time;
177 status = dp_get_lane_status_and_lane_adjust(link, link_training_setting: lt_settings, ln_status: dpcd_lane_status,
178 ln_align: &dpcd_lane_status_updated, ln_adjust: dpcd_lane_adjust, offset: DPRX);
179 if (status != DC_OK) {
180 result = LINK_TRAINING_ABORT;
181 } else if (dp_is_symbol_locked(ln_count: lt_settings->link_settings.lane_count, dpcd_lane_status) &&
182 dpcd_lane_status_updated.bits.CDS_INTERLANE_ALIGN_DONE_128b_132b) {
183 /* pass */
184 break;
185 } else if (dpcd_lane_status_updated.bits.LT_FAILED_128b_132b) {
186 result = DP_128b_132b_LT_FAILED;
187 } else if (wait_time >= lt_settings->cds_wait_time_limit) {
188 result = DP_128b_132b_CDS_DONE_TIMEOUT;
189 }
190 }
191
192 return result;
193}
194
195enum link_training_result dp_perform_128b_132b_link_training(
196 struct dc_link *link,
197 const struct link_resource *link_res,
198 struct link_training_settings *lt_settings)
199{
200 enum link_training_result result = LINK_TRAINING_SUCCESS;
201
202 /* TODO - DP2.0 Link: remove legacy_dp2_lt logic */
203 if (link->dc->debug.legacy_dp2_lt) {
204 struct link_training_settings legacy_settings;
205
206 decide_8b_10b_training_settings(link,
207 link_setting: &lt_settings->link_settings,
208 lt_settings: &legacy_settings);
209 return dp_perform_8b_10b_link_training(link, link_res, lt_settings: &legacy_settings);
210 }
211
212 dpcd_set_link_settings(link, lt_settings);
213
214 if (result == LINK_TRAINING_SUCCESS) {
215 result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
216 if (result == LINK_TRAINING_SUCCESS)
217 DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
218 }
219
220 if (result == LINK_TRAINING_SUCCESS) {
221 result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
222 if (result == LINK_TRAINING_SUCCESS)
223 DC_LOG_HW_LINK_TRAINING("%s: CDS done.\n", __func__);
224 }
225
226 return result;
227}
228
229void decide_128b_132b_training_settings(struct dc_link *link,
230 const struct dc_link_settings *link_settings,
231 struct link_training_settings *lt_settings)
232{
233 memset(lt_settings, 0, sizeof(*lt_settings));
234
235 lt_settings->link_settings = *link_settings;
236 /* TODO: should decide link spread when populating link_settings */
237 lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
238 LINK_SPREAD_05_DOWNSPREAD_30KHZ;
239
240 lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
241 lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_settings);
242 lt_settings->eq_pattern_time = 2500;
243 lt_settings->eq_wait_time_limit = 400000;
244 lt_settings->eq_loop_count_limit = 20;
245 lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
246 lt_settings->cds_pattern_time = 2500;
247 lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
248 lttpr_repeater_count: link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
249 lt_settings->disallow_per_lane_settings = true;
250 lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
251 dp_hw_to_dpcd_lane_settings(lt_settings,
252 hw_lane_settings: lt_settings->hw_lane_settings, dpcd_lane_settings: lt_settings->dpcd_lane_settings);
253}
254
255enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
256{
257 enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
258
259 if (dp_is_lttpr_present(link))
260 mode = LTTPR_MODE_NON_TRANSPARENT;
261
262 DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
263 return mode;
264}
265
266

source code of linux/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c