Skip to content

Commit 21bf3e6

Browse files
Shen, Georgealexdeucher
authored andcommitted
drm/amd/display: Refactor vendor specific link training sequence
[Why] Current implementation is not scalable and retrofits the existing standard link training code for purposes outside of its original design. [How] Refactor vendor specific link training sequence into its own separate function to be called instead of the standard link training function. Tested-by: Daniel Wheeler <[email protected]> Reviewed-by: Wenjing Liu <[email protected]> Acked-by: Rodrigo Siqueira <[email protected]> Signed-off-by: George Shen <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent fddb024 commit 21bf3e6

File tree

1 file changed

+337
-1
lines changed

1 file changed

+337
-1
lines changed

drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c

Lines changed: 337 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,338 @@ static enum link_training_result dp_perform_128b_132b_link_training(
24272427
}
24282428
#endif
24292429

2430+
static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequence(
2431+
struct dc_link *link,
2432+
struct link_training_settings *lt_settings)
2433+
{
2434+
const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
2435+
const uint8_t offset = dp_convert_to_count(
2436+
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
2437+
const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
2438+
const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x68};
2439+
uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
2440+
uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
2441+
uint32_t vendor_lttpr_write_address = 0xF004F;
2442+
enum link_training_result status = LINK_TRAINING_SUCCESS;
2443+
uint8_t lane = 0;
2444+
union down_spread_ctrl downspread = {0};
2445+
union lane_count_set lane_count_set = {0};
2446+
uint8_t toggle_rate;
2447+
uint8_t rate;
2448+
2449+
/* Only 8b/10b is supported */
2450+
ASSERT(dp_get_link_encoding_format(&lt_settings->link_settings) ==
2451+
DP_8b_10b_ENCODING);
2452+
2453+
if (offset != 0xFF) {
2454+
vendor_lttpr_write_address +=
2455+
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
2456+
}
2457+
2458+
/* Vendor specific: Reset lane settings */
2459+
core_link_write_dpcd(
2460+
link,
2461+
vendor_lttpr_write_address,
2462+
&vendor_lttpr_write_data_reset[0],
2463+
sizeof(vendor_lttpr_write_data_reset));
2464+
core_link_write_dpcd(
2465+
link,
2466+
vendor_lttpr_write_address,
2467+
&vendor_lttpr_write_data_vs[0],
2468+
sizeof(vendor_lttpr_write_data_vs));
2469+
core_link_write_dpcd(
2470+
link,
2471+
vendor_lttpr_write_address,
2472+
&vendor_lttpr_write_data_pe[0],
2473+
sizeof(vendor_lttpr_write_data_pe));
2474+
2475+
/* Vendor specific: Enable intercept */
2476+
core_link_write_dpcd(
2477+
link,
2478+
vendor_lttpr_write_address,
2479+
&vendor_lttpr_write_data_intercept_en[0],
2480+
sizeof(vendor_lttpr_write_data_intercept_en));
2481+
2482+
/* 1. set link rate, lane count and spread. */
2483+
2484+
downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);
2485+
2486+
lane_count_set.bits.LANE_COUNT_SET =
2487+
lt_settings->link_settings.lane_count;
2488+
2489+
lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
2490+
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
2491+
2492+
2493+
if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
2494+
lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
2495+
link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
2496+
}
2497+
2498+
core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
2499+
&downspread.raw, sizeof(downspread));
2500+
2501+
core_link_write_dpcd(link, DP_LANE_COUNT_SET,
2502+
&lane_count_set.raw, 1);
2503+
2504+
#if defined(CONFIG_DRM_AMD_DC_DCN)
2505+
rate = get_dpcd_link_rate(&lt_settings->link_settings);
2506+
#else
2507+
rate = (uint8_t) (lt_settings->link_settings.link_rate);
2508+
#endif
2509+
2510+
/* Vendor specific: Toggle link rate */
2511+
toggle_rate = (rate == 0x6) ? 0xA : 0x6;
2512+
2513+
if (link->vendor_specific_lttpr_link_rate_wa == rate) {
2514+
core_link_write_dpcd(
2515+
link,
2516+
DP_LINK_BW_SET,
2517+
&toggle_rate,
2518+
1);
2519+
}
2520+
2521+
link->vendor_specific_lttpr_link_rate_wa = rate;
2522+
2523+
core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);
2524+
2525+
DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
2526+
__func__,
2527+
DP_LINK_BW_SET,
2528+
lt_settings->link_settings.link_rate,
2529+
DP_LANE_COUNT_SET,
2530+
lt_settings->link_settings.lane_count,
2531+
lt_settings->enhanced_framing,
2532+
DP_DOWNSPREAD_CTRL,
2533+
lt_settings->link_settings.link_spread);
2534+
2535+
/* 2. Perform link training */
2536+
2537+
/* Perform Clock Recovery Sequence */
2538+
if (status == LINK_TRAINING_SUCCESS) {
2539+
uint32_t retries_cr;
2540+
uint32_t retry_count;
2541+
uint32_t wait_time_microsec;
2542+
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
2543+
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
2544+
union lane_align_status_updated dpcd_lane_status_updated;
2545+
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
2546+
2547+
retries_cr = 0;
2548+
retry_count = 0;
2549+
2550+
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
2551+
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
2552+
2553+
memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
2554+
memset(&dpcd_lane_status_updated, '\0',
2555+
sizeof(dpcd_lane_status_updated));
2556+
2557+
/* 1. call HWSS to set lane settings */
2558+
dp_set_hw_lane_settings(
2559+
link,
2560+
lt_settings,
2561+
0);
2562+
2563+
/* 2. update DPCD of the receiver */
2564+
if (!retry_count) {
2565+
/* EPR #361076 - write as a 5-byte burst,
2566+
* but only for the 1-st iteration.
2567+
*/
2568+
dpcd_set_lt_pattern_and_lane_settings(
2569+
link,
2570+
lt_settings,
2571+
lt_settings->pattern_for_cr,
2572+
0);
2573+
/* Vendor specific: Disable intercept */
2574+
core_link_write_dpcd(
2575+
link,
2576+
vendor_lttpr_write_address,
2577+
&vendor_lttpr_write_data_intercept_dis[0],
2578+
sizeof(vendor_lttpr_write_data_intercept_dis));
2579+
} else {
2580+
vendor_lttpr_write_data_vs[3] = 0;
2581+
vendor_lttpr_write_data_pe[3] = 0;
2582+
2583+
for (lane = 0; lane < lane_count; lane++) {
2584+
vendor_lttpr_write_data_vs[3] |=
2585+
lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
2586+
vendor_lttpr_write_data_pe[3] |=
2587+
lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
2588+
}
2589+
2590+
/* Vendor specific: Update VS and PE to DPRX requested value */
2591+
core_link_write_dpcd(
2592+
link,
2593+
vendor_lttpr_write_address,
2594+
&vendor_lttpr_write_data_vs[0],
2595+
sizeof(vendor_lttpr_write_data_vs));
2596+
core_link_write_dpcd(
2597+
link,
2598+
vendor_lttpr_write_address,
2599+
&vendor_lttpr_write_data_pe[0],
2600+
sizeof(vendor_lttpr_write_data_pe));
2601+
2602+
dpcd_set_lane_settings(
2603+
link,
2604+
lt_settings,
2605+
0);
2606+
}
2607+
2608+
/* 3. wait receiver to lock-on*/
2609+
wait_time_microsec = lt_settings->cr_pattern_time;
2610+
2611+
dp_wait_for_training_aux_rd_interval(
2612+
link,
2613+
wait_time_microsec);
2614+
2615+
/* 4. Read lane status and requested drive
2616+
* settings as set by the sink
2617+
*/
2618+
dp_get_lane_status_and_lane_adjust(
2619+
link,
2620+
lt_settings,
2621+
dpcd_lane_status,
2622+
&dpcd_lane_status_updated,
2623+
dpcd_lane_adjust,
2624+
0);
2625+
2626+
/* 5. check CR done*/
2627+
if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
2628+
status = LINK_TRAINING_SUCCESS;
2629+
break;
2630+
}
2631+
2632+
/* 6. max VS reached*/
2633+
if (dp_is_max_vs_reached(lt_settings))
2634+
break;
2635+
2636+
/* 7. same lane settings */
2637+
/* Note: settings are the same for all lanes,
2638+
* so comparing first lane is sufficient
2639+
*/
2640+
if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
2641+
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
2642+
retries_cr++;
2643+
else
2644+
retries_cr = 0;
2645+
2646+
/* 8. update VS/PE/PC2 in lt_settings*/
2647+
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
2648+
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
2649+
retry_count++;
2650+
}
2651+
2652+
if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
2653+
ASSERT(0);
2654+
DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
2655+
__func__,
2656+
LINK_TRAINING_MAX_CR_RETRY);
2657+
2658+
}
2659+
2660+
status = dp_get_cr_failure(lane_count, dpcd_lane_status);
2661+
}
2662+
2663+
/* Perform Channel EQ Sequence */
2664+
if (status == LINK_TRAINING_SUCCESS) {
2665+
enum dc_dp_training_pattern tr_pattern;
2666+
uint32_t retries_ch_eq;
2667+
uint32_t wait_time_microsec;
2668+
enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
2669+
union lane_align_status_updated dpcd_lane_status_updated = {0};
2670+
union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
2671+
union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
2672+
2673+
/* Note: also check that TPS4 is a supported feature*/
2674+
tr_pattern = lt_settings->pattern_for_eq;
2675+
2676+
dp_set_hw_training_pattern(link, tr_pattern, 0);
2677+
2678+
status = LINK_TRAINING_EQ_FAIL_EQ;
2679+
2680+
for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
2681+
retries_ch_eq++) {
2682+
2683+
dp_set_hw_lane_settings(link, lt_settings, 0);
2684+
2685+
vendor_lttpr_write_data_vs[3] = 0;
2686+
vendor_lttpr_write_data_pe[3] = 0;
2687+
2688+
for (lane = 0; lane < lane_count; lane++) {
2689+
vendor_lttpr_write_data_vs[3] |=
2690+
lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
2691+
vendor_lttpr_write_data_pe[3] |=
2692+
lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
2693+
}
2694+
2695+
/* Vendor specific: Update VS and PE to DPRX requested value */
2696+
core_link_write_dpcd(
2697+
link,
2698+
vendor_lttpr_write_address,
2699+
&vendor_lttpr_write_data_vs[0],
2700+
sizeof(vendor_lttpr_write_data_vs));
2701+
core_link_write_dpcd(
2702+
link,
2703+
vendor_lttpr_write_address,
2704+
&vendor_lttpr_write_data_pe[0],
2705+
sizeof(vendor_lttpr_write_data_pe));
2706+
2707+
/* 2. update DPCD*/
2708+
if (!retries_ch_eq)
2709+
/* EPR #361076 - write as a 5-byte burst,
2710+
* but only for the 1-st iteration
2711+
*/
2712+
2713+
dpcd_set_lt_pattern_and_lane_settings(
2714+
link,
2715+
lt_settings,
2716+
tr_pattern, 0);
2717+
else
2718+
dpcd_set_lane_settings(link, lt_settings, 0);
2719+
2720+
/* 3. wait for receiver to lock-on*/
2721+
wait_time_microsec = lt_settings->eq_pattern_time;
2722+
2723+
dp_wait_for_training_aux_rd_interval(
2724+
link,
2725+
wait_time_microsec);
2726+
2727+
/* 4. Read lane status and requested
2728+
* drive settings as set by the sink
2729+
*/
2730+
dp_get_lane_status_and_lane_adjust(
2731+
link,
2732+
lt_settings,
2733+
dpcd_lane_status,
2734+
&dpcd_lane_status_updated,
2735+
dpcd_lane_adjust,
2736+
0);
2737+
2738+
/* 5. check CR done*/
2739+
if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
2740+
status = LINK_TRAINING_EQ_FAIL_CR;
2741+
break;
2742+
}
2743+
2744+
/* 6. check CHEQ done*/
2745+
if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
2746+
dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
2747+
dp_is_interlane_aligned(dpcd_lane_status_updated)) {
2748+
status = LINK_TRAINING_SUCCESS;
2749+
break;
2750+
}
2751+
2752+
/* 7. update VS/PE/PC2 in lt_settings*/
2753+
dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
2754+
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
2755+
}
2756+
}
2757+
2758+
return status;
2759+
}
2760+
2761+
24302762
enum link_training_result dc_link_dp_perform_link_training(
24312763
struct dc_link *link,
24322764
const struct dc_link_settings *link_settings,
@@ -2466,7 +2798,11 @@ enum link_training_result dc_link_dp_perform_link_training(
24662798
* Per DP specs starting from here, DPTX device shall not issue
24672799
* Non-LT AUX transactions inside training mode.
24682800
*/
2469-
if (encoding == DP_8b_10b_ENCODING)
2801+
if (!link->dc->debug.apply_vendor_specific_lttpr_wa &&
2802+
(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
2803+
link->lttpr_mode == LTTPR_MODE_TRANSPARENT)
2804+
status = dc_link_dp_perform_fixed_vs_pe_training_sequence(link, &lt_settings);
2805+
else if (encoding == DP_8b_10b_ENCODING)
24702806
status = dp_perform_8b_10b_link_training(link, &lt_settings);
24712807
#if defined(CONFIG_DRM_AMD_DC_DCN)
24722808
else if (encoding == DP_128b_132b_ENCODING)

0 commit comments

Comments
 (0)