File Index
Files and directories
Sign in
FILE

link_dp_training_128b_132b.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_128b_132b.c 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 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			(uint8_t *)(link_training_setting->dpcd_lane_settings),
 46			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			&dpcd_interval.raw, 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, lt_settings->pattern_for_cr, DPRX);
 87
 88	/* Set TRAINING_PATTERN_SET to 01h */
 89	dpcd_set_training_pattern(link, 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, &aux_rd_interval);
 93	dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
 94			&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
 95	dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
 96			lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
 97	dp_set_hw_lane_settings(link, link_res, lt_settings, DPRX);
 98	dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_eq, 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			lt_settings->pattern_for_eq, DPRX);
106
107	/* poll for channel EQ done */
108	while (result == LINK_TRAINING_SUCCESS) {
109		dp_wait_for_training_aux_rd_interval(link, aux_rd_interval);
110		wait_time += aux_rd_interval;
111		status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
112				&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
113		dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
114				lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
115		dpcd_128b_132b_get_aux_rd_interval(link, &aux_rd_interval);
116		if (status != DC_OK) {
117			result = LINK_TRAINING_ABORT;
118		} else if (dp_is_ch_eq_done(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, lt_settings, DPRX);
128			dpcd_128b_132b_set_lane_settings(link, 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					lt_settings->eq_pattern_time);
147			wait_time += lt_settings->eq_pattern_time;
148			status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
149					&dpcd_lane_status_updated, dpcd_lane_adjust, 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, 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				lt_settings->cds_pattern_time);
176		wait_time += lt_settings->cds_pattern_time;
177		status = dp_get_lane_status_and_lane_adjust(link, lt_settings, dpcd_lane_status,
178						&dpcd_lane_status_updated, dpcd_lane_adjust, DPRX);
179		if (status != DC_OK) {
180			result = LINK_TRAINING_ABORT;
181		} else if (dp_is_symbol_locked(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_res,
208				&lt_settings->link_settings,
209				&legacy_settings);
210		return dp_perform_8b_10b_link_training(link, link_res, &legacy_settings);
211	}
212
213	dpcd_set_link_settings(link, lt_settings);
214
215	if (result == LINK_TRAINING_SUCCESS) {
216		result = dp_perform_128b_132b_channel_eq_done_sequence(link, link_res, lt_settings);
217		if (result == LINK_TRAINING_SUCCESS)
218			DC_LOG_HW_LINK_TRAINING("%s: Channel EQ done.\n", __func__);
219	}
220
221	if (result == LINK_TRAINING_SUCCESS) {
222		result = dp_perform_128b_132b_cds_done_sequence(link, link_res, lt_settings);
223		if (result == LINK_TRAINING_SUCCESS)
224			DC_LOG_HW_LINK_TRAINING("%s: CDS done.\n", __func__);
225	}
226
227	return result;
228}
229
230void decide_128b_132b_training_settings(struct dc_link *link,
231		const struct link_resource *link_res,
232		const struct dc_link_settings *link_settings,
233		struct link_training_settings *lt_settings)
234{
235	memset(lt_settings, 0, sizeof(*lt_settings));
236
237	lt_settings->link_settings = *link_settings;
238	/* TODO: should decide link spread when populating link_settings */
239	lt_settings->link_settings.link_spread = link->dp_ss_off ? LINK_SPREAD_DISABLED :
240			LINK_SPREAD_05_DOWNSPREAD_30KHZ;
241
242	lt_settings->pattern_for_cr = decide_cr_training_pattern(link_settings);
243	lt_settings->pattern_for_eq = decide_eq_training_pattern(link, link_res, link_settings);
244	lt_settings->eq_pattern_time = 2500;
245	lt_settings->eq_wait_time_limit = 400000;
246	lt_settings->eq_loop_count_limit = 20;
247	lt_settings->pattern_for_cds = DP_128b_132b_TPS2_CDS;
248	lt_settings->cds_pattern_time = 2500;
249	lt_settings->cds_wait_time_limit = (dp_parse_lttpr_repeater_count(
250			link->dpcd_caps.lttpr_caps.phy_repeater_cnt) + 1) * 20000;
251	lt_settings->disallow_per_lane_settings = true;
252	lt_settings->lttpr_mode = dp_decide_128b_132b_lttpr_mode(link);
253	dp_hw_to_dpcd_lane_settings(lt_settings,
254			lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
255}
256
257enum lttpr_mode dp_decide_128b_132b_lttpr_mode(struct dc_link *link)
258{
259	enum lttpr_mode mode = LTTPR_MODE_NON_LTTPR;
260
261	if (dp_is_lttpr_present(link))
262		mode = LTTPR_MODE_NON_TRANSPARENT;
263
264	DC_LOG_DC("128b_132b chose LTTPR_MODE %d.\n", mode);
265	return mode;
266}
267
~/ Read-only file preview.