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 <_settings->link_settings, 208 &legacy_settings); 209 return dp_perform_8b_10b_link_training(link, link_res, &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 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 lt_settings->hw_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