root/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c
/*
 * Copyright 2022 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: AMD
 *
 */

/* FILE POLICY AND INTENDED USAGE:
 * This file implements 8b/10b link training specially modified to support an
 * embedded retimer chip. This retimer chip is referred as fixed vs pe retimer.
 * Unlike native dp connection this chip requires a modified link training
 * protocol based on 8b/10b link training. Since this is a non standard sequence
 * and we must support this hardware, we decided to isolate it in its own
 * training sequence inside its own file.
 */
#include "link_dp_training_fixed_vs_pe_retimer.h"
#include "link_dp_training_8b_10b.h"
#include "link_dpcd.h"
#include "link_dp_phy.h"
#include "link_dp_capability.h"
#include "link_ddc.h"

#define DC_LOGGER \
        link->ctx->logger

void dp_fixed_vs_pe_read_lane_adjust(
        struct dc_link *link,
        union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
{
        const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
        const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
        uint8_t dprx_vs = 0;
        uint8_t dprx_pe = 0;
        uint8_t lane;

        /* W/A to read lane settings requested by DPRX */
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));

        link_query_fixed_vs_pe_retimer(link->ddc, &dprx_vs, 1);

        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));

        link_query_fixed_vs_pe_retimer(link->ddc, &dprx_pe, 1);

        for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
                dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET  = (dprx_vs >> (2 * lane)) & 0x3;
                dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
        }
}


void dp_fixed_vs_pe_set_retimer_lane_settings(
        struct dc_link *link,
        const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
        uint8_t lane_count)
{
        const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
        uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
        uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
        uint8_t lane = 0;

        for (lane = 0; lane < lane_count; lane++) {
                vendor_lttpr_write_data_vs[3] |=
                                dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
                vendor_lttpr_write_data_pe[3] |=
                                dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
        }

        /* Force LTTPR to output desired VS and PE */
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));

        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));

        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));
}

static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
                struct dc_link *link,
                const struct link_resource *link_res,
                struct link_training_settings *lt_settings)
{
        enum link_training_result status = LINK_TRAINING_SUCCESS;
        uint8_t lane = 0;
        uint8_t toggle_rate = 0x6;
        uint8_t target_rate = 0x6;
        bool apply_toggle_rate_wa = false;
        uint8_t repeater_cnt;
        uint8_t repeater_id;

        /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
        if (lt_settings->cr_pattern_time < 16000)
                lt_settings->cr_pattern_time = 16000;

        /* Fixed VS/PE specific: Toggle link rate */
        apply_toggle_rate_wa = ((link->vendor_specific_lttpr_link_rate_wa == target_rate) || (link->vendor_specific_lttpr_link_rate_wa == 0));
        target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
        toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;

        if (apply_toggle_rate_wa)
                lt_settings->link_settings.link_rate = toggle_rate;

        if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
                start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);

        /* 1. set link rate, lane count and spread. */
        dpcd_set_link_settings(link, lt_settings);

        /* Fixed VS/PE specific: Toggle link rate back*/
        if (apply_toggle_rate_wa) {
                core_link_write_dpcd(
                                link,
                                DP_LINK_BW_SET,
                                &target_rate,
                                1);
        }

        link->vendor_specific_lttpr_link_rate_wa = target_rate;

        if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {

                /* 2. perform link training (set link training done
                 *  to false is done as well)
                 */
                repeater_cnt = dp_parse_lttpr_repeater_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);

                for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
                                repeater_id--) {
                        status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);

                        if (status != LINK_TRAINING_SUCCESS) {
                                repeater_training_done(link, repeater_id);
                                break;
                        }

                        status = perform_8b_10b_channel_equalization_sequence(link,
                                        link_res,
                                        lt_settings,
                                        repeater_id);

                        repeater_training_done(link, repeater_id);

                        if (status != LINK_TRAINING_SUCCESS)
                                break;

                        for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
                                lt_settings->dpcd_lane_settings[lane].raw = 0;
                                lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
                                lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
                        }
                }
        }

        if (status == LINK_TRAINING_SUCCESS) {
                status = perform_8b_10b_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
                if (status == LINK_TRAINING_SUCCESS) {
                        status = perform_8b_10b_channel_equalization_sequence(link,
                                                                       link_res,
                                                                       lt_settings,
                                                                       DPRX);
                }
        }

        return status;
}

enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
        struct dc_link *link,
        const struct link_resource *link_res,
        struct link_training_settings *lt_settings)
{
        const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
        const uint8_t offset = dp_parse_lttpr_repeater_count(
                        link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
        const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0};
        const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E};
        const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E};
        const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01};
        const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68};
        uint32_t pre_disable_intercept_delay_ms = 0;
        uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
        uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
        const uint8_t vendor_lttpr_write_data_4lane_1[4] = {0x1, 0x6E, 0xF2, 0x19};
        const uint8_t vendor_lttpr_write_data_4lane_2[4] = {0x1, 0x6B, 0xF2, 0x01};
        const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18};
        const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03};
        const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06};
        const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87};
        enum link_training_result status = LINK_TRAINING_SUCCESS;
        uint8_t lane = 0;
        union down_spread_ctrl downspread = {0};
        union lane_count_set lane_count_set = {0};
        uint8_t toggle_rate;
        uint8_t rate;

        /* Only 8b/10b is supported */
        ASSERT(link_dp_get_encoding_format(&lt_settings->link_settings) ==
                        DP_8b_10b_ENCODING);

        if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
                status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
                return status;
        }

        if (offset != 0xFF) {
                if (offset == 2) {
                        pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa;

                /* Certain display and cable configuration require extra delay */
                } else if (offset > 2) {
                        pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2;
                }
        }

        /* Vendor specific: Reset lane settings */
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_reset[0], sizeof(vendor_lttpr_write_data_reset));
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));

        /* Vendor specific: Enable intercept */
        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_intercept_en[0], sizeof(vendor_lttpr_write_data_intercept_en));

        /* 1. set link rate, lane count and spread. */

        downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread);

        lane_count_set.bits.LANE_COUNT_SET =
        lt_settings->link_settings.lane_count;

        lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
        lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;


        if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) {
                lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
                                link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
        }

        core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL,
                &downspread.raw, sizeof(downspread));

        core_link_write_dpcd(link, DP_LANE_COUNT_SET,
                &lane_count_set.raw, 1);

        rate = get_dpcd_link_rate(&lt_settings->link_settings);

        // Only perform toggle if FIXED_VS LTTPR reports no IEEE OUI
        if (memcmp("\x00\x00\x00", &link->dpcd_caps.lttpr_caps.lttpr_ieee_oui[0], 3) == 0) {
                /* Vendor specific: Toggle link rate */
                toggle_rate = (rate == 0x6) ? 0xA : 0x6;

                if (link->vendor_specific_lttpr_link_rate_wa == rate || link->vendor_specific_lttpr_link_rate_wa == 0) {
                        core_link_write_dpcd(
                                        link,
                                        DP_LINK_BW_SET,
                                        &toggle_rate,
                                        1);
                }

                link->vendor_specific_lttpr_link_rate_wa = rate;
        }

        core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1);

        DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
                __func__,
                DP_LINK_BW_SET,
                lt_settings->link_settings.link_rate,
                DP_LANE_COUNT_SET,
                lt_settings->link_settings.lane_count,
                lt_settings->enhanced_framing,
                DP_DOWNSPREAD_CTRL,
                lt_settings->link_settings.link_spread);

        link_configure_fixed_vs_pe_retimer(link->ddc,
                        &vendor_lttpr_write_data_dpmf[0],
                        sizeof(vendor_lttpr_write_data_dpmf));

        if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) {
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1));
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_4lane_2[0], sizeof(vendor_lttpr_write_data_4lane_2));
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_4lane_3[0], sizeof(vendor_lttpr_write_data_4lane_3));
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_4lane_4[0], sizeof(vendor_lttpr_write_data_4lane_4));
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_4lane_5[0], sizeof(vendor_lttpr_write_data_4lane_5));
        }

        /* 2. Perform link training */

        /* Perform Clock Recovery Sequence */
        if (status == LINK_TRAINING_SUCCESS) {
                const uint8_t max_vendor_dpcd_retries = 10;
                uint32_t retries_cr;
                uint32_t retry_count;
                uint32_t wait_time_microsec;
                enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
                union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
                union lane_align_status_updated dpcd_lane_status_updated;
                union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
                uint8_t i = 0;

                retries_cr = 0;
                retry_count = 0;

                memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
                memset(&dpcd_lane_status_updated, '\0',
                sizeof(dpcd_lane_status_updated));

                while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
                        (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {


                        /* 1. call HWSS to set lane settings */
                        dp_set_hw_lane_settings(
                                        link,
                                        link_res,
                                        lt_settings,
                                        0);

                        /* 2. update DPCD of the receiver */
                        if (!retry_count) {
                                /* EPR #361076 - write as a 5-byte burst,
                                 * but only for the 1-st iteration.
                                 */
                                dpcd_set_lt_pattern_and_lane_settings(
                                                link,
                                                lt_settings,
                                                lt_settings->pattern_for_cr,
                                                0);
                                /* Vendor specific: Disable intercept */
                                for (i = 0; i < max_vendor_dpcd_retries; i++) {
                                        if (pre_disable_intercept_delay_ms != 0)
                                                msleep(pre_disable_intercept_delay_ms);
                                        if (link_configure_fixed_vs_pe_retimer(link->ddc,
                                                        &vendor_lttpr_write_data_intercept_dis[0],
                                                        sizeof(vendor_lttpr_write_data_intercept_dis)))
                                                break;

                                        link_configure_fixed_vs_pe_retimer(link->ddc,
                                                        &vendor_lttpr_write_data_intercept_en[0],
                                                        sizeof(vendor_lttpr_write_data_intercept_en));
                                }
                        } else {
                                vendor_lttpr_write_data_vs[3] = 0;
                                vendor_lttpr_write_data_pe[3] = 0;

                                for (lane = 0; lane < lane_count; lane++) {
                                        vendor_lttpr_write_data_vs[3] |=
                                                        lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
                                        vendor_lttpr_write_data_pe[3] |=
                                                        lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
                                }

                                /* Vendor specific: Update VS and PE to DPRX requested value */
                                link_configure_fixed_vs_pe_retimer(link->ddc,
                                                &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
                                link_configure_fixed_vs_pe_retimer(link->ddc,
                                                &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));

                                dpcd_set_lane_settings(
                                                link,
                                                lt_settings,
                                                0);
                        }

                        /* 3. wait receiver to lock-on*/
                        wait_time_microsec = lt_settings->cr_pattern_time;

                        dp_wait_for_training_aux_rd_interval(
                                        link,
                                        wait_time_microsec);

                        /* 4. Read lane status and requested drive
                         * settings as set by the sink
                         */
                        dp_get_lane_status_and_lane_adjust(
                                        link,
                                        lt_settings,
                                        dpcd_lane_status,
                                        &dpcd_lane_status_updated,
                                        dpcd_lane_adjust,
                                        0);

                        /* 5. check CR done*/
                        if (dp_is_cr_done(lane_count, dpcd_lane_status)) {
                                break;
                        }

                        /* 6. max VS reached*/
                        if (dp_is_max_vs_reached(lt_settings))
                                break;

                        /* 7. same lane settings */
                        /* Note: settings are the same for all lanes,
                         * so comparing first lane is sufficient
                         */
                        if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
                                        dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
                                retries_cr++;
                        else
                                retries_cr = 0;

                        /* 8. update VS/PE/PC2 in lt_settings*/
                        dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
                                        lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
                        retry_count++;
                }

                if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
                        ASSERT(0);
                        DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue",
                                __func__,
                                LINK_TRAINING_MAX_CR_RETRY);

                }

                status = dp_get_cr_failure(lane_count, dpcd_lane_status);
        }

        /* Perform Channel EQ Sequence */
        if (status == LINK_TRAINING_SUCCESS) {
                enum dc_dp_training_pattern tr_pattern;
                uint32_t retries_ch_eq;
                uint32_t wait_time_microsec;
                enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
                union lane_align_status_updated dpcd_lane_status_updated = {0};
                union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
                union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};

                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_adicora_eq1[0],
                                sizeof(vendor_lttpr_write_data_adicora_eq1));
                link_configure_fixed_vs_pe_retimer(link->ddc,
                                &vendor_lttpr_write_data_adicora_eq2[0],
                                sizeof(vendor_lttpr_write_data_adicora_eq2));


                /* Note: also check that TPS4 is a supported feature*/
                tr_pattern = lt_settings->pattern_for_eq;

                dp_set_hw_training_pattern(link, link_res, tr_pattern, 0);

                status = LINK_TRAINING_EQ_FAIL_EQ;

                for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
                        retries_ch_eq++) {

                        dp_set_hw_lane_settings(link, link_res, lt_settings, 0);

                        vendor_lttpr_write_data_vs[3] = 0;
                        vendor_lttpr_write_data_pe[3] = 0;

                        for (lane = 0; lane < lane_count; lane++) {
                                vendor_lttpr_write_data_vs[3] |=
                                                lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
                                vendor_lttpr_write_data_pe[3] |=
                                                lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane);
                        }

                        /* Vendor specific: Update VS and PE to DPRX requested value */
                        link_configure_fixed_vs_pe_retimer(link->ddc,
                                        &vendor_lttpr_write_data_vs[0], sizeof(vendor_lttpr_write_data_vs));
                        link_configure_fixed_vs_pe_retimer(link->ddc,
                                        &vendor_lttpr_write_data_pe[0], sizeof(vendor_lttpr_write_data_pe));

                        /* 2. update DPCD*/
                        if (!retries_ch_eq) {
                                /* EPR #361076 - write as a 5-byte burst,
                                 * but only for the 1-st iteration
                                 */

                                dpcd_set_lt_pattern_and_lane_settings(
                                        link,
                                        lt_settings,
                                        tr_pattern, 0);

                                link_configure_fixed_vs_pe_retimer(link->ddc,
                                                &vendor_lttpr_write_data_adicora_eq3[0],
                                                sizeof(vendor_lttpr_write_data_adicora_eq3));

                        } else
                                dpcd_set_lane_settings(link, lt_settings, 0);

                        /* 3. wait for receiver to lock-on*/
                        wait_time_microsec = lt_settings->eq_pattern_time;

                        dp_wait_for_training_aux_rd_interval(
                                        link,
                                        wait_time_microsec);

                        /* 4. Read lane status and requested
                         * drive settings as set by the sink
                         */
                        dp_get_lane_status_and_lane_adjust(
                                link,
                                lt_settings,
                                dpcd_lane_status,
                                &dpcd_lane_status_updated,
                                dpcd_lane_adjust,
                                0);

                        /* 5. check CR done*/
                        if (!dp_is_cr_done(lane_count, dpcd_lane_status)) {
                                status = LINK_TRAINING_EQ_FAIL_CR;
                                break;
                        }

                        /* 6. check CHEQ done*/
                        if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) &&
                                        dp_is_symbol_locked(lane_count, dpcd_lane_status) &&
                                        dp_is_interlane_aligned(dpcd_lane_status_updated)) {
                                status = LINK_TRAINING_SUCCESS;
                                break;
                        }

                        /* 7. update VS/PE/PC2 in lt_settings*/
                        dp_decide_lane_settings(lt_settings, dpcd_lane_adjust,
                                        lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
                }
        }

        return status;
}