drm/amd/display: Add ability to set preferred link training parameters.
authorDavid Galiffi <David.Galiffi@amd.com>
Thu, 30 May 2019 15:56:39 +0000 (11:56 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 18 Jul 2019 19:18:08 +0000 (14:18 -0500)
[WHY]
To add support for OS requirement to set preferred link training
parameters.

[HOW]
Create new structure of dp link training overrides. During link training
processes, these values should be used instead of the default training
parameters.

Signed-off-by: David Galiffi <David.Galiffi@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Anthony Koo <Anthony.Koo@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drivers/gpu/drm/amd/display/dc/dc_dp_types.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
drivers/gpu/drm/amd/display/include/link_service_types.h

index 8dbf759eba45339e37b0265c334bf9fe7c0d6525..b4293dca16c8ed462abc4837a0459fe43162f51e 100644 (file)
@@ -1189,6 +1189,9 @@ static bool construct(
        link->ctx = dc_ctx;
        link->link_index = init_params->link_index;
 
+       memset(&link->preferred_training_settings, 0, sizeof(struct dc_link_training_overrides));
+       memset(&link->preferred_link_setting, 0, sizeof(struct dc_link_settings));
+
        link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index);
 
        if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
@@ -1467,6 +1470,9 @@ static enum dc_status enable_link_dp(
        struct dc_link *link = stream->link;
        struct dc_link_settings link_settings = {0};
        enum dp_panel_mode panel_mode;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+       bool fec_enable;
+#endif
 
        /* get link settings for video mode timing */
        decide_link_settings(stream, &link_settings);
@@ -1511,10 +1517,20 @@ static enum dc_status enable_link_dp(
                        skip_video_pattern = false;
 
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
-       dp_set_fec_ready(link, true);
+       if (link->preferred_training_settings.fec_enable != NULL)
+               fec_enable = *link->preferred_training_settings.fec_enable;
+       else
+               fec_enable = true;
+
+       dp_set_fec_ready(link, fec_enable);
 #endif
 
-       if (perform_link_training_with_retries(
+       if (link->aux_access_disabled) {
+               dc_link_dp_perform_link_training_skip_aux(link, &link_settings);
+
+               link->cur_link_settings = link_settings;
+               status = DC_OK;
+       } else if (perform_link_training_with_retries(
                        link,
                        &link_settings,
                        skip_video_pattern,
@@ -1526,7 +1542,7 @@ static enum dc_status enable_link_dp(
                status = DC_FAIL_DP_LINK_TRAINING;
 
 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
-       dp_set_fec_enable(link, true);
+       dp_set_fec_enable(link, fec_enable);
 #endif
        return status;
 }
@@ -3014,6 +3030,29 @@ void dc_link_set_preferred_link_settings(struct dc *dc,
                dp_retrain_link_dp_test(link, &store_settings, false);
 }
 
+void dc_link_set_preferred_training_settings(struct dc *dc,
+                                                struct dc_link_settings *link_setting,
+                                                struct dc_link_training_overrides *lt_overrides,
+                                                struct dc_link *link,
+                                                bool skip_immediate_retrain)
+{
+       if (lt_overrides != NULL)
+               link->preferred_training_settings = *lt_overrides;
+       else
+               memset(&link->preferred_training_settings, 0, sizeof(link->preferred_training_settings));
+
+       if (link_setting != NULL) {
+               link->preferred_link_setting = *link_setting;
+       } else {
+               link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
+               link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
+       }
+
+       /* Retrain now, or wait until next stream update to apply */
+       if (skip_immediate_retrain == false)
+               dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link);
+}
+
 void dc_link_enable_hpd(const struct dc_link *link)
 {
        dc_link_dp_enable_hpd(link);
@@ -3024,7 +3063,6 @@ void dc_link_disable_hpd(const struct dc_link *link)
        dc_link_dp_disable_hpd(link);
 }
 
-
 void dc_link_set_test_pattern(struct dc_link *link,
                              enum dp_test_pattern test_pattern,
                              const struct link_training_settings *p_link_settings,
index 056be4c34a98d95608ba857bf789d7cec4761645..3f8a8f61cd7645e02ced5ebd9840c1459d7f809d 100644 (file)
@@ -49,7 +49,7 @@ static struct dc_link_settings get_common_supported_link_settings(
                struct dc_link_settings link_setting_a,
                struct dc_link_settings link_setting_b);
 
-static void wait_for_training_aux_rd_interval(
+static uint32_t get_training_aux_rd_interval(
        struct dc_link *link,
        uint32_t default_wait_in_micro_secs)
 {
@@ -68,15 +68,21 @@ static void wait_for_training_aux_rd_interval(
                        sizeof(training_rd_interval));
 
                if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
-                       default_wait_in_micro_secs =
-                               training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
+                       default_wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
        }
 
-       udelay(default_wait_in_micro_secs);
+       return default_wait_in_micro_secs;
+}
+
+static void wait_for_training_aux_rd_interval(
+       struct dc_link *link,
+       uint32_t wait_in_micro_secs)
+{
+       udelay(wait_in_micro_secs);
 
        DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
                __func__,
-               default_wait_in_micro_secs);
+               wait_in_micro_secs);
 }
 
 static void dpcd_set_training_pattern(
@@ -95,27 +101,27 @@ static void dpcd_set_training_pattern(
                dpcd_pattern.v1_4.TRAINING_PATTERN_SET);
 }
 
-static enum hw_dp_training_pattern get_supported_tp(struct dc_link *link)
+static enum dc_dp_training_pattern get_supported_tp(struct dc_link *link)
 {
-       enum hw_dp_training_pattern highest_tp = HW_DP_TRAINING_PATTERN_2;
+       enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
        struct encoder_feature_support *features = &link->link_enc->features;
        struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
 
        if (features->flags.bits.IS_TPS3_CAPABLE)
-               highest_tp = HW_DP_TRAINING_PATTERN_3;
+               highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3;
 
        if (features->flags.bits.IS_TPS4_CAPABLE)
-               highest_tp = HW_DP_TRAINING_PATTERN_4;
+               highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4;
 
        if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED &&
-               highest_tp >= HW_DP_TRAINING_PATTERN_4)
-               return HW_DP_TRAINING_PATTERN_4;
+               highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4)
+               return DP_TRAINING_PATTERN_SEQUENCE_4;
 
        if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED &&
-               highest_tp >= HW_DP_TRAINING_PATTERN_3)
-               return HW_DP_TRAINING_PATTERN_3;
+               highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3)
+               return DP_TRAINING_PATTERN_SEQUENCE_3;
 
-       return HW_DP_TRAINING_PATTERN_2;
+       return DP_TRAINING_PATTERN_SEQUENCE_2;
 }
 
 static void dpcd_set_link_settings(
@@ -126,7 +132,7 @@ static void dpcd_set_link_settings(
 
        union down_spread_ctrl downspread = { {0} };
        union lane_count_set lane_count_set = { {0} };
-       enum hw_dp_training_pattern hw_tr_pattern;
+       enum dc_dp_training_pattern dp_tr_pattern;
 
        downspread.raw = (uint8_t)
        (lt_settings->link_settings.link_spread);
@@ -134,21 +140,21 @@ static void dpcd_set_link_settings(
        lane_count_set.bits.LANE_COUNT_SET =
        lt_settings->link_settings.lane_count;
 
-       lane_count_set.bits.ENHANCED_FRAMING = 1;
-
+       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
        lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
 
-       hw_tr_pattern = get_supported_tp(link);
-       if (hw_tr_pattern != HW_DP_TRAINING_PATTERN_4) {
+       dp_tr_pattern = get_supported_tp(link);
+
+       if (dp_tr_pattern != 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));
+               &downspread.raw, sizeof(downspread));
 
        core_link_write_dpcd(link, DP_LANE_COUNT_SET,
-       &lane_count_set.raw, 1);
+               &lane_count_set.raw, 1);
 
        if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
                        lt_settings->link_settings.use_link_rate_set == true) {
@@ -162,46 +168,47 @@ static void dpcd_set_link_settings(
        }
 
        if (rate) {
-               DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n",
+               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);
        } else {
-               DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x\n %x spread = %x\n",
+               DC_LOG_HW_LINK_TRAINING("%s\n %x rate set = %x\n %x lane = %x framing = %x\n %x spread = %x\n",
                        __func__,
                        DP_LINK_RATE_SET,
                        lt_settings->link_settings.link_rate_set,
                        DP_LANE_COUNT_SET,
                        lt_settings->link_settings.lane_count,
+                       lt_settings->enhanced_framing,
                        DP_DOWNSPREAD_CTRL,
                        lt_settings->link_settings.link_spread);
        }
-
 }
 
 static enum dpcd_training_patterns
-       hw_training_pattern_to_dpcd_training_pattern(
+       dc_dp_training_pattern_to_dpcd_training_pattern(
        struct dc_link *link,
-       enum hw_dp_training_pattern pattern)
+       enum dc_dp_training_pattern pattern)
 {
        enum dpcd_training_patterns dpcd_tr_pattern =
        DPCD_TRAINING_PATTERN_VIDEOIDLE;
 
        switch (pattern) {
-       case HW_DP_TRAINING_PATTERN_1:
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
                dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
                break;
-       case HW_DP_TRAINING_PATTERN_2:
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
                dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
                break;
-       case HW_DP_TRAINING_PATTERN_3:
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
                dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
                break;
-       case HW_DP_TRAINING_PATTERN_4:
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
                dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
                break;
        default:
@@ -212,13 +219,12 @@ static enum dpcd_training_patterns
        }
 
        return dpcd_tr_pattern;
-
 }
 
 static void dpcd_set_lt_pattern_and_lane_settings(
        struct dc_link *link,
        const struct link_training_settings *lt_settings,
-       enum hw_dp_training_pattern pattern)
+       enum dc_dp_training_pattern pattern)
 {
        union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = { { {0} } };
        const uint32_t dpcd_base_lt_offset =
@@ -233,7 +239,7 @@ static void dpcd_set_lt_pattern_and_lane_settings(
        * DpcdAddress_TrainingPatternSet
        *****************************************************************/
        dpcd_pattern.v1_4.TRAINING_PATTERN_SET =
-               hw_training_pattern_to_dpcd_training_pattern(link, pattern);
+               dc_dp_training_pattern_to_dpcd_training_pattern(link, pattern);
 
        dpcd_lt_buffer[DP_TRAINING_PATTERN_SET - dpcd_base_lt_offset]
                = dpcd_pattern.raw;
@@ -346,12 +352,20 @@ static void update_drive_settings(
 {
        uint32_t lane;
        for (lane = 0; lane < src.link_settings.lane_count; lane++) {
-               dest->lane_settings[lane].VOLTAGE_SWING =
-                       src.lane_settings[lane].VOLTAGE_SWING;
-               dest->lane_settings[lane].PRE_EMPHASIS =
-                       src.lane_settings[lane].PRE_EMPHASIS;
-               dest->lane_settings[lane].POST_CURSOR2 =
-                       src.lane_settings[lane].POST_CURSOR2;
+               if (dest->voltage_swing == NULL)
+                       dest->lane_settings[lane].VOLTAGE_SWING = src.lane_settings[lane].VOLTAGE_SWING;
+               else
+                       dest->lane_settings[lane].VOLTAGE_SWING = *dest->voltage_swing;
+
+               if (dest->pre_emphasis == NULL)
+                       dest->lane_settings[lane].PRE_EMPHASIS = src.lane_settings[lane].PRE_EMPHASIS;
+               else
+                       dest->lane_settings[lane].PRE_EMPHASIS = *dest->pre_emphasis;
+
+               if (dest->post_cursor2 == NULL)
+                       dest->lane_settings[lane].POST_CURSOR2 = src.lane_settings[lane].POST_CURSOR2;
+               else
+                       dest->lane_settings[lane].POST_CURSOR2 = *dest->post_cursor2;
        }
 }
 
@@ -754,15 +768,15 @@ static enum link_training_result perform_channel_equalization_sequence(
        struct link_training_settings *lt_settings)
 {
        struct link_training_settings req_settings;
-       enum hw_dp_training_pattern hw_tr_pattern;
+       enum dc_dp_training_pattern tr_pattern;
        uint32_t retries_ch_eq;
        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} } };
 
-       hw_tr_pattern = get_supported_tp(link);
+       tr_pattern = lt_settings->pattern_for_eq;
 
-       dp_set_hw_training_pattern(link, hw_tr_pattern);
+       dp_set_hw_training_pattern(link, tr_pattern);
 
        for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
                retries_ch_eq++) {
@@ -776,12 +790,12 @@ static enum link_training_result perform_channel_equalization_sequence(
                        dpcd_set_lt_pattern_and_lane_settings(
                                link,
                                lt_settings,
-                               hw_tr_pattern);
+                               tr_pattern);
                else
                        dpcd_set_lane_settings(link, lt_settings);
 
                /* 3. wait for receiver to lock-on*/
-               wait_for_training_aux_rd_interval(link, 400);
+               wait_for_training_aux_rd_interval(link, lt_settings->eq_pattern_time);
 
                /* 4. Read lane status and requested
                 * drive settings as set by the sink*/
@@ -817,27 +831,16 @@ static enum link_training_result perform_clock_recovery_sequence(
 {
        uint32_t retries_cr;
        uint32_t retry_count;
-       uint32_t lane;
        struct link_training_settings req_settings;
-       enum dc_lane_count lane_count =
-       lt_settings->link_settings.lane_count;
-       enum hw_dp_training_pattern hw_tr_pattern = HW_DP_TRAINING_PATTERN_1;
+       enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
+       enum dc_dp_training_pattern tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_1;
        union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
        union lane_align_status_updated dpcd_lane_status_updated;
 
        retries_cr = 0;
        retry_count = 0;
-       /* initial drive setting (VS/PE/PC2)*/
-       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
-               lt_settings->lane_settings[lane].VOLTAGE_SWING =
-               VOLTAGE_SWING_LEVEL0;
-               lt_settings->lane_settings[lane].PRE_EMPHASIS =
-               PRE_EMPHASIS_DISABLED;
-               lt_settings->lane_settings[lane].POST_CURSOR2 =
-               POST_CURSOR2_DISABLED;
-       }
 
-       dp_set_hw_training_pattern(link, hw_tr_pattern);
+       dp_set_hw_training_pattern(link, tr_pattern);
 
        /* najeeb - The synaptics MST hub can put the LT in
        * infinite loop by switching the VS
@@ -845,7 +848,7 @@ static enum link_training_result perform_clock_recovery_sequence(
        /* between level 0 and level 1 continuously, here
        * we try for CR lock for LinkTrainingMaxCRRetry count*/
        while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
-       (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
+               (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
 
                memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
                memset(&dpcd_lane_status_updated, '\0',
@@ -863,7 +866,7 @@ static enum link_training_result perform_clock_recovery_sequence(
                        dpcd_set_lt_pattern_and_lane_settings(
                                        link,
                                        lt_settings,
-                                       hw_tr_pattern);
+                                       tr_pattern);
                else
                        dpcd_set_lane_settings(
                                        link,
@@ -872,7 +875,7 @@ static enum link_training_result perform_clock_recovery_sequence(
                /* 3. wait receiver to lock-on*/
                wait_for_training_aux_rd_interval(
                                link,
-                               100);
+                               lt_settings->cr_pattern_time);
 
                /* 4. Read lane status and requested drive
                * settings as set by the sink
@@ -939,7 +942,7 @@ static inline enum link_training_result perform_link_training_int(
         * TPS4 must be used instead of POST_LT_ADJ_REQ.
         */
        if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
-                       get_supported_tp(link) == HW_DP_TRAINING_PATTERN_4)
+                       get_supported_tp(link) == DP_TRAINING_PATTERN_SEQUENCE_4)
                return status;
 
        if (status == LINK_TRAINING_SUCCESS &&
@@ -947,7 +950,7 @@ static inline enum link_training_result perform_link_training_int(
                status = LINK_TRAINING_LQA_FAIL;
 
        lane_count_set.bits.LANE_COUNT_SET = lt_settings->link_settings.lane_count;
-       lane_count_set.bits.ENHANCED_FRAMING = 1;
+       lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing;
        lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
 
        core_link_write_dpcd(
@@ -959,24 +962,28 @@ static inline enum link_training_result perform_link_training_int(
        return status;
 }
 
-enum link_training_result dc_link_dp_perform_link_training(
-       struct dc_link *link,
+static void initialize_training_settings(
+        struct dc_link *link,
        const struct dc_link_settings *link_setting,
-       bool skip_video_pattern)
+       struct link_training_settings *lt_settings)
 {
-       enum link_training_result status = LINK_TRAINING_SUCCESS;
+       uint32_t lane;
 
-       char *link_rate = "Unknown";
-       char *lt_result = "Unknown";
+       memset(lt_settings, '\0', sizeof(struct link_training_settings));
 
-       struct link_training_settings lt_settings;
+       /* Initialize link settings */
+       lt_settings->link_settings.use_link_rate_set = link_setting->use_link_rate_set;
+       lt_settings->link_settings.link_rate_set = link_setting->link_rate_set;
 
-       memset(&lt_settings, '\0', sizeof(lt_settings));
+       if (link->preferred_link_setting.link_rate != LINK_RATE_UNKNOWN)
+               lt_settings->link_settings.link_rate = link->preferred_link_setting.link_rate;
+       else
+               lt_settings->link_settings.link_rate = link_setting->link_rate;
 
-       lt_settings.link_settings.link_rate = link_setting->link_rate;
-       lt_settings.link_settings.lane_count = link_setting->lane_count;
-       lt_settings.link_settings.use_link_rate_set = link_setting->use_link_rate_set;
-       lt_settings.link_settings.link_rate_set = link_setting->link_rate_set;
+       if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN)
+               lt_settings->link_settings.lane_count = link->preferred_link_setting.lane_count;
+       else
+               lt_settings->link_settings.lane_count = link_setting->lane_count;
 
        /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/
 
@@ -987,31 +994,75 @@ enum link_training_result dc_link_dp_perform_link_training(
         * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
         * LINK_SPREAD_DISABLED;
         */
+       /* Initialize link spread */
        if (link->dp_ss_off)
-               lt_settings.link_settings.link_spread = LINK_SPREAD_DISABLED;
+               lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED;
+       else if (link->preferred_training_settings.downspread != NULL)
+               lt_settings->link_settings.link_spread
+                       = *link->preferred_training_settings.downspread
+                       ? LINK_SPREAD_05_DOWNSPREAD_30KHZ
+                       : LINK_SPREAD_DISABLED;
        else
-               lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
+               lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
 
-       /* 1. set link rate, lane count and spread*/
-       dpcd_set_link_settings(link, &lt_settings);
+       /* Initialize lane settings overrides */
+       if (link->preferred_training_settings.voltage_swing != NULL)
+               lt_settings->voltage_swing = link->preferred_training_settings.voltage_swing;
 
-       /* 2. perform link training (set link training done
-        *  to false is done as well)*/
-       status = perform_clock_recovery_sequence(link, &lt_settings);
-       if (status == LINK_TRAINING_SUCCESS) {
-               status = perform_channel_equalization_sequence(link,
-                               &lt_settings);
-       }
+       if (link->preferred_training_settings.pre_emphasis != NULL)
+               lt_settings->pre_emphasis = link->preferred_training_settings.pre_emphasis;
 
-       if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
-               status = perform_link_training_int(link,
-                               &lt_settings,
-                               status);
+       if (link->preferred_training_settings.post_cursor2 != NULL)
+               lt_settings->post_cursor2 = link->preferred_training_settings.post_cursor2;
+
+       /* Initialize lane settings (VS/PE/PC2) */
+       for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+               lt_settings->lane_settings[lane].VOLTAGE_SWING =
+                       lt_settings->voltage_swing != NULL ?
+                       *lt_settings->voltage_swing :
+                       VOLTAGE_SWING_LEVEL0;
+               lt_settings->lane_settings[lane].PRE_EMPHASIS =
+                       lt_settings->pre_emphasis != NULL ?
+                       *lt_settings->pre_emphasis
+                       : PRE_EMPHASIS_DISABLED;
+               lt_settings->lane_settings[lane].POST_CURSOR2 =
+                       lt_settings->post_cursor2 != NULL ?
+                       *lt_settings->post_cursor2
+                       : POST_CURSOR2_DISABLED;
        }
 
-       /* 6. print status message*/
-       switch (lt_settings.link_settings.link_rate) {
+       /* Initialize training timings */
+       if (link->preferred_training_settings.cr_pattern_time != NULL)
+               lt_settings->cr_pattern_time = *link->preferred_training_settings.cr_pattern_time;
+       else
+               lt_settings->cr_pattern_time = get_training_aux_rd_interval(link, 100);
+
+       if (link->preferred_training_settings.eq_pattern_time != NULL)
+               lt_settings->eq_pattern_time = *link->preferred_training_settings.eq_pattern_time;
+       else
+               lt_settings->eq_pattern_time = get_training_aux_rd_interval(link, 400);
+
+       if (link->preferred_training_settings.pattern_for_eq != NULL)
+               lt_settings->pattern_for_eq = *link->preferred_training_settings.pattern_for_eq;
+       else
+               lt_settings->pattern_for_eq = get_supported_tp(link);
+
+       if (link->preferred_training_settings.enhanced_framing != NULL)
+               lt_settings->enhanced_framing = *link->preferred_training_settings.enhanced_framing;
+       else
+               lt_settings->enhanced_framing = 1;
+}
+
+static void print_status_message(
+       struct dc_link *link,
+       const struct link_training_settings *lt_settings,
+       enum link_training_result status)
+{
+       char *link_rate = "Unknown";
+       char *lt_result = "Unknown";
+       char *lt_spread = "Disabled";
 
+       switch (lt_settings->link_settings.link_rate) {
        case LINK_RATE_LOW:
                link_rate = "RBR";
                break;
@@ -1057,13 +1108,102 @@ enum link_training_result dc_link_dp_perform_link_training(
                break;
        }
 
+       switch (lt_settings->link_settings.link_spread) {
+       case LINK_SPREAD_DISABLED:
+               lt_spread = "Disabled";
+               break;
+       case LINK_SPREAD_05_DOWNSPREAD_30KHZ:
+               lt_spread = "0.5% 30KHz";
+               break;
+       case LINK_SPREAD_05_DOWNSPREAD_33KHZ:
+               lt_spread = "0.5% 33KHz";
+               break;
+       default:
+               break;
+       }
+
        /* Connectivity log: link training */
-       CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d",
-                       link_rate,
-                       lt_settings.link_settings.lane_count,
-                       lt_result,
-                       lt_settings.lane_settings[0].VOLTAGE_SWING,
-                       lt_settings.lane_settings[0].PRE_EMPHASIS);
+       CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
+                               link_rate,
+                               lt_settings->link_settings.lane_count,
+                               lt_result,
+                               lt_settings->lane_settings[0].VOLTAGE_SWING,
+                               lt_settings->lane_settings[0].PRE_EMPHASIS,
+                               lt_spread);
+}
+
+bool dc_link_dp_perform_link_training_skip_aux(
+       struct dc_link *link,
+       const struct dc_link_settings *link_setting)
+{
+       struct link_training_settings lt_settings;
+       enum dc_dp_training_pattern pattern_for_cr = DP_TRAINING_PATTERN_SEQUENCE_1;
+
+       initialize_training_settings(link, link_setting, &lt_settings);
+
+       /* 1. Perform_clock_recovery_sequence. */
+
+       /* transmit training pattern for clock recovery */
+       dp_set_hw_training_pattern(link, pattern_for_cr);
+
+       /* call HWSS to set lane settings*/
+       dp_set_hw_lane_settings(link, &lt_settings);
+
+       /* wait receiver to lock-on*/
+       wait_for_training_aux_rd_interval(link, lt_settings.cr_pattern_time);
+
+       /* 2. Perform_channel_equalization_sequence. */
+
+       /* transmit training pattern for channel equalization. */
+       dp_set_hw_training_pattern(link, lt_settings.pattern_for_eq);
+
+       /* call HWSS to set lane settings*/
+       dp_set_hw_lane_settings(link, &lt_settings);
+
+       /* wait receiver to lock-on. */
+       wait_for_training_aux_rd_interval(link, lt_settings.eq_pattern_time);
+
+       /* 3. Perform_link_training_int. */
+
+       /* Mainlink output idle pattern. */
+       dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+       print_status_message(link, &lt_settings, LINK_TRAINING_SUCCESS);
+
+       return true;
+}
+
+enum link_training_result dc_link_dp_perform_link_training(
+       struct dc_link *link,
+       const struct dc_link_settings *link_setting,
+       bool skip_video_pattern)
+{
+       enum link_training_result status = LINK_TRAINING_SUCCESS;
+
+       struct link_training_settings lt_settings;
+
+       initialize_training_settings(link, link_setting, &lt_settings);
+
+       /* 1. set link rate, lane count and spread. */
+       dpcd_set_link_settings(link, &lt_settings);
+
+       /* 2. perform link training (set link training done
+        *  to false is done as well)
+        */
+       status = perform_clock_recovery_sequence(link, &lt_settings);
+       if (status == LINK_TRAINING_SUCCESS) {
+               status = perform_channel_equalization_sequence(link,
+                               &lt_settings);
+       }
+
+       if ((status == LINK_TRAINING_SUCCESS) || !skip_video_pattern) {
+               status = perform_link_training_int(link,
+                               &lt_settings,
+                               status);
+       }
+
+       /* 6. print status message*/
+       print_status_message(link, &lt_settings, status);
 
        if (status != LINK_TRAINING_SUCCESS)
                link->ctx->dc->debug_data.ltFailCount++;
@@ -1071,7 +1211,6 @@ enum link_training_result dc_link_dp_perform_link_training(
        return status;
 }
 
-
 bool perform_link_training_with_retries(
        struct dc_link *link,
        const struct dc_link_settings *link_setting,
index 2d019e1f613526d30f3c8b1d9dd54d7071247b30..211fadefe2f5ee5a4ade46b18831c8563130faf4 100644 (file)
@@ -25,10 +25,11 @@ enum dc_status core_link_read_dpcd(
        uint8_t *data,
        uint32_t size)
 {
-       if (!dm_helpers_dp_read_dpcd(link->ctx,
-                       link,
-                       address, data, size))
-                       return DC_ERROR_UNEXPECTED;
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_read_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
 
        return DC_OK;
 }
@@ -39,10 +40,11 @@ enum dc_status core_link_write_dpcd(
        const uint8_t *data,
        uint32_t size)
 {
-       if (!dm_helpers_dp_write_dpcd(link->ctx,
-                       link,
-                       address, data, size))
-                               return DC_ERROR_UNEXPECTED;
+       if (!link->aux_access_disabled &&
+                       !dm_helpers_dp_write_dpcd(link->ctx,
+                       link, address, data, size)) {
+               return DC_ERROR_UNEXPECTED;
+       }
 
        return DC_OK;
 }
@@ -203,21 +205,21 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal)
 
 bool dp_set_hw_training_pattern(
        struct dc_link *link,
-       enum hw_dp_training_pattern pattern)
+       enum dc_dp_training_pattern pattern)
 {
        enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
 
        switch (pattern) {
-       case HW_DP_TRAINING_PATTERN_1:
+       case DP_TRAINING_PATTERN_SEQUENCE_1:
                test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
                break;
-       case HW_DP_TRAINING_PATTERN_2:
+       case DP_TRAINING_PATTERN_SEQUENCE_2:
                test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
                break;
-       case HW_DP_TRAINING_PATTERN_3:
+       case DP_TRAINING_PATTERN_SEQUENCE_3:
                test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
                break;
-       case HW_DP_TRAINING_PATTERN_4:
+       case DP_TRAINING_PATTERN_SEQUENCE_4:
                test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
                break;
        default:
index dfcec4d3e9c0e4d20f1b52dcd1a23f9bf98bbb91..efa7a47f6b7ea547f193e8f0cf40a4d50aeb9a23 100644 (file)
@@ -90,6 +90,13 @@ enum dc_post_cursor2 {
        POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
 };
 
+enum dc_dp_training_pattern {
+       DP_TRAINING_PATTERN_SEQUENCE_1 = 0,
+       DP_TRAINING_PATTERN_SEQUENCE_2,
+       DP_TRAINING_PATTERN_SEQUENCE_3,
+       DP_TRAINING_PATTERN_SEQUENCE_4,
+};
+
 struct dc_link_settings {
        enum dc_lane_count lane_count;
        enum dc_link_rate link_rate;
@@ -109,6 +116,20 @@ struct dc_link_training_settings {
        struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX];
 };
 
+struct dc_link_training_overrides {
+       enum dc_voltage_swing *voltage_swing;
+       enum dc_pre_emphasis *pre_emphasis;
+       enum dc_post_cursor2 *post_cursor2;
+
+       uint16_t *cr_pattern_time;
+       uint16_t *eq_pattern_time;
+       enum dc_dp_training_pattern *pattern_for_eq;
+
+       enum dc_link_spread *downspread;
+       bool *alternate_scrambler_reset;
+       bool *enhanced_framing;
+       bool *fec_enable;
+};
 
 union dpcd_rev {
        struct {
index 6f0b80111e58c298e69f624d265b146d7585d2d5..d6ff5af70c71f7783b4182dfa6e8fa9d83a2568f 100644 (file)
@@ -83,6 +83,7 @@ struct dc_link {
        bool is_hpd_filter_disabled;
        bool dp_ss_off;
        bool link_state_valid;
+       bool aux_access_disabled;
 
        /* caps is the same as reported_link_cap. link_traing use
         * reported_link_cap. Will clean up.  TODO
@@ -92,6 +93,7 @@ struct dc_link {
        struct dc_link_settings cur_link_settings;
        struct dc_lane_settings cur_lane_setting;
        struct dc_link_settings preferred_link_setting;
+       struct dc_link_training_overrides preferred_training_settings;
 
        uint8_t ddc_hw_inst;
 
@@ -217,6 +219,10 @@ void dc_link_dp_set_drive_settings(
        struct dc_link *link,
        struct link_training_settings *lt_settings);
 
+bool dc_link_dp_perform_link_training_skip_aux(
+       struct dc_link *link,
+       const struct dc_link_settings *link_setting);
+
 enum link_training_result dc_link_dp_perform_link_training(
        struct dc_link *link,
        const struct dc_link_settings *link_setting,
@@ -251,6 +257,11 @@ void dc_link_perform_link_training(struct dc *dc,
 void dc_link_set_preferred_link_settings(struct dc *dc,
                                         struct dc_link_settings *link_setting,
                                         struct dc_link *link);
+void dc_link_set_preferred_training_settings(struct dc *dc,
+                                       struct dc_link_settings *link_setting,
+                                       struct dc_link_training_overrides *lt_overrides,
+                                       struct dc_link *link,
+                                       bool skip_immediate_retrain);
 void dc_link_enable_hpd(const struct dc_link *link);
 void dc_link_disable_hpd(const struct dc_link *link);
 void dc_link_set_test_pattern(struct dc_link *link,
index 30be7bb4a01a1b4455443ee1ea994b1f00186764..3680846674e8d381561d4499cec27204cc84d13e 100644 (file)
@@ -60,7 +60,7 @@ void dp_disable_link_phy_mst(struct dc_link *link, enum signal_type signal);
 
 bool dp_set_hw_training_pattern(
        struct dc_link *link,
-       enum hw_dp_training_pattern pattern);
+       enum dc_dp_training_pattern pattern);
 
 void dp_set_hw_lane_settings(
        struct dc_link *link,
index 80f0d93cfd946de274c011d8aa3cfb2f0da04f0f..876b0b3e1a9c9193bd93736138ae333365ba0552 100644 (file)
@@ -71,14 +71,17 @@ enum link_training_result {
 struct link_training_settings {
        struct dc_link_settings link_settings;
        struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX];
-       bool allow_invalid_msa_timing_param;
-};
 
-enum hw_dp_training_pattern {
-       HW_DP_TRAINING_PATTERN_1 = 0,
-       HW_DP_TRAINING_PATTERN_2,
-       HW_DP_TRAINING_PATTERN_3,
-       HW_DP_TRAINING_PATTERN_4
+       enum dc_voltage_swing *voltage_swing;
+       enum dc_pre_emphasis *pre_emphasis;
+       enum dc_post_cursor2 *post_cursor2;
+
+       uint16_t cr_pattern_time;
+       uint16_t eq_pattern_time;
+       enum dc_dp_training_pattern pattern_for_eq;
+
+       bool enhanced_framing;
+       bool allow_invalid_msa_timing_param;
 };
 
 /*TODO: Move this enum test harness*/