static void initialize_training_settings(
struct dc_link *link,
const struct dc_link_settings *link_setting,
+ const struct dc_link_training_overrides *overrides,
struct link_training_settings *lt_settings)
{
uint32_t lane;
/* Initialize link spread */
if (link->dp_ss_off)
lt_settings->link_settings.link_spread = LINK_SPREAD_DISABLED;
- else if (link->preferred_training_settings.downspread != NULL)
+ else if (overrides->downspread != NULL)
lt_settings->link_settings.link_spread
- = *link->preferred_training_settings.downspread
+ = *overrides->downspread
? LINK_SPREAD_05_DOWNSPREAD_30KHZ
: LINK_SPREAD_DISABLED;
else
lt_settings->link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
/* Initialize lane settings overrides */
- if (link->preferred_training_settings.voltage_swing != NULL)
- lt_settings->voltage_swing = link->preferred_training_settings.voltage_swing;
+ if (overrides->voltage_swing != NULL)
+ lt_settings->voltage_swing = overrides->voltage_swing;
- if (link->preferred_training_settings.pre_emphasis != NULL)
- lt_settings->pre_emphasis = link->preferred_training_settings.pre_emphasis;
+ if (overrides->pre_emphasis != NULL)
+ lt_settings->pre_emphasis = overrides->pre_emphasis;
- if (link->preferred_training_settings.post_cursor2 != NULL)
- lt_settings->post_cursor2 = link->preferred_training_settings.post_cursor2;
+ if (overrides->post_cursor2 != NULL)
+ lt_settings->post_cursor2 = overrides->post_cursor2;
/* Initialize lane settings (VS/PE/PC2) */
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
}
/* Initialize training timings */
- if (link->preferred_training_settings.cr_pattern_time != NULL)
- lt_settings->cr_pattern_time = *link->preferred_training_settings.cr_pattern_time;
+ if (overrides->cr_pattern_time != NULL)
+ lt_settings->cr_pattern_time = *overrides->cr_pattern_time;
else
- lt_settings->cr_pattern_time = 100;
+ 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;
+ if (overrides->eq_pattern_time != NULL)
+ lt_settings->eq_pattern_time = *overrides->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;
+ if (overrides->pattern_for_eq != NULL)
+ lt_settings->pattern_for_eq = *overrides->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;
+ if (overrides->enhanced_framing != NULL)
+ lt_settings->enhanced_framing = *overrides->enhanced_framing;
else
lt_settings->enhanced_framing = 1;
}
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, <_settings);
+ initialize_training_settings(
+ link,
+ link_setting,
+ &link->preferred_training_settings,
+ <_settings);
/* 1. Perform_clock_recovery_sequence. */
bool fec_enable;
#endif
- initialize_training_settings(link, link_setting, <_settings);
+ initialize_training_settings(
+ link,
+ link_setting,
+ &link->preferred_training_settings,
+ <_settings);
/* 1. set link rate, lane count and spread. */
dpcd_set_link_settings(link, <_settings);
return false;
}
+static enum clock_source_id get_clock_source_id(struct dc_link *link)
+{
+ enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_UNDEFINED;
+ struct clock_source *dp_cs = link->dc->res_pool->dp_clock_source;
+
+ if (dp_cs != NULL) {
+ dp_cs_id = dp_cs->id;
+ } else {
+ /*
+ * dp clock source is not initialized for some reason.
+ * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
+ */
+ ASSERT(dp_cs);
+ }
+
+ return dp_cs_id;
+}
+
+static void set_dp_mst_mode(struct dc_link *link, bool mst_enable)
+{
+ if (mst_enable == false &&
+ link->type == dc_connection_mst_branch) {
+ /* Disable MST on link. Use only local sink. */
+ dp_disable_link_phy_mst(link, link->connector_signal);
+
+ link->type = dc_connection_single;
+ link->local_sink = link->remote_sinks[0];
+ link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT;
+ } else if (mst_enable == true &&
+ link->type == dc_connection_single &&
+ link->remote_sinks[0] != NULL) {
+ /* Re-enable MST on link. */
+ dp_disable_link_phy(link, link->connector_signal);
+ dp_enable_mst_on_sink(link, true);
+
+ link->type = dc_connection_mst_branch;
+ link->local_sink->sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
+ }
+}
+
+bool dc_link_dp_sync_lt_begin(struct dc_link *link)
+{
+ /* Begin Sync LT. During this time,
+ * DPCD:600h must not be powered down.
+ */
+ link->sync_lt_in_progress = true;
+
+ /*Clear any existing preferred settings.*/
+ memset(&link->preferred_training_settings, 0,
+ sizeof(struct dc_link_training_overrides));
+ memset(&link->preferred_link_setting, 0,
+ sizeof(struct dc_link_settings));
+
+ return true;
+}
+
+enum link_training_result dc_link_dp_sync_lt_attempt(
+ struct dc_link *link,
+ struct dc_link_settings *link_settings,
+ struct dc_link_training_overrides *lt_overrides)
+{
+ struct link_training_settings lt_settings;
+ enum link_training_result lt_status = LINK_TRAINING_SUCCESS;
+ enum dp_panel_mode panel_mode = DP_PANEL_MODE_DEFAULT;
+ enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ bool fec_enable = false;
+#endif
+
+ initialize_training_settings(
+ link,
+ link_settings,
+ lt_overrides,
+ <_settings);
+
+ /* Setup MST Mode */
+ if (lt_overrides->mst_enable)
+ set_dp_mst_mode(link, *lt_overrides->mst_enable);
+
+ /* Disable link */
+ dp_disable_link_phy(link, link->connector_signal);
+
+ /* Enable link */
+ dp_cs_id = get_clock_source_id(link);
+ dp_enable_link_phy(link, link->connector_signal,
+ dp_cs_id, link_settings);
+
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ /* Set FEC enable */
+ fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
+ dp_set_fec_ready(link, fec_enable);
+#endif
+
+ if (lt_overrides->alternate_scrambler_reset) {
+ if (*lt_overrides->alternate_scrambler_reset)
+ panel_mode = DP_PANEL_MODE_EDP;
+ else
+ panel_mode = DP_PANEL_MODE_DEFAULT;
+ } else
+ panel_mode = dp_get_panel_mode(link);
+
+ dp_set_panel_mode(link, panel_mode);
+
+ /* Attempt to train with given link training settings */
+
+ /* Set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, <_settings);
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ lt_status = perform_clock_recovery_sequence(link, <_settings);
+ if (lt_status == LINK_TRAINING_SUCCESS) {
+ lt_status = perform_channel_equalization_sequence(link,
+ <_settings);
+ }
+
+ /* 3. Sync LT must skip TRAINING_PATTERN_SET:0 (video pattern)*/
+ /* 4. print status message*/
+ print_status_message(link, <_settings, lt_status);
+
+ return lt_status;
+}
+
+bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
+{
+ /* If input parameter is set, shut down phy.
+ * Still shouldn't turn off dp_receiver (DPCD:600h)
+ */
+ if (link_down == true) {
+ dp_disable_link_phy(link, link->connector_signal);
+#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
+ dp_set_fec_ready(link, false);
+#endif
+ }
+
+ link->sync_lt_in_progress = false;
+ return true;
+}
+
static struct dc_link_settings get_max_link_cap(struct dc_link *link)
{
/* Set Default link settings */
bool success;
bool skip_link_training;
bool skip_video_pattern;
- struct clock_source *dp_cs;
enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
enum link_training_result status;
union hpd_irq_data irq_data;
/* disable PHY done possible by BIOS, will be done by driver itself */
dp_disable_link_phy(link, link->connector_signal);
- dp_cs = link->dc->res_pool->dp_clock_source;
-
- if (dp_cs)
- dp_cs_id = dp_cs->id;
- else {
- /*
- * dp clock source is not initialized for some reason.
- * Should not happen, CLOCK_SOURCE_ID_EXTERNAL will be used
- */
- ASSERT(dp_cs);
- }
+ dp_cs_id = get_clock_source_id(link);
/* link training starts with the maximum common settings
* supported by both sink and ASIC.
union dpcd_rev rev;
union mstm_cap cap;
+ if (link->preferred_training_settings.mst_enable &&
+ *link->preferred_training_settings.mst_enable == false) {
+ return false;
+ }
+
rev.raw = 0;
cap.raw = 0;
core_link_write_dpcd(link, DP_MSTM_CTRL, &mstmCntl, 1);
}
+void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode)
+{
+ union dpcd_edp_config edp_config_set;
+ bool panel_mode_edp = false;
+
+ memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
+
+ if (panel_mode != DP_PANEL_MODE_DEFAULT) {
+
+ switch (panel_mode) {
+ case DP_PANEL_MODE_EDP:
+ case DP_PANEL_MODE_SPECIAL:
+ panel_mode_edp = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /*set edp panel mode in receiver*/
+ core_link_read_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ if (edp_config_set.bits.PANEL_MODE_EDP
+ != panel_mode_edp) {
+ enum ddc_result result = DDC_RESULT_UNKNOWN;
+
+ edp_config_set.bits.PANEL_MODE_EDP =
+ panel_mode_edp;
+ result = core_link_write_dpcd(
+ link,
+ DP_EDP_CONFIGURATION_SET,
+ &edp_config_set.raw,
+ sizeof(edp_config_set.raw));
+
+ ASSERT(result == DDC_RESULT_SUCESSFULL);
+ }
+ }
+ DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d "
+ "eDP panel mode enabled: %d \n",
+ link->link_index,
+ link->dpcd_caps.panel_mode_edp,
+ panel_mode_edp);
+}
+
+enum dp_panel_mode dp_get_panel_mode(struct dc_link *link)
+{
+ /* We need to explicitly check that connector
+ * is not DP. Some Travis_VGA get reported
+ * by video bios as DP.
+ */
+ if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
+
+ switch (link->dpcd_caps.branch_dev_id) {
+ case DP_BRANCH_DEVICE_ID_2:
+ if (strncmp(
+ link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_2,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ case DP_BRANCH_DEVICE_ID_3:
+ if (strncmp(link->dpcd_caps.branch_dev_name,
+ DP_VGA_LVDS_CONVERTER_ID_3,
+ sizeof(
+ link->dpcd_caps.
+ branch_dev_name)) == 0) {
+ return DP_PANEL_MODE_SPECIAL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (link->dpcd_caps.panel_mode_edp) {
+ return DP_PANEL_MODE_EDP;
+ }
+
+ return DP_PANEL_MODE_DEFAULT;
+}
+
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
void dp_set_fec_ready(struct dc_link *link, bool ready)
{