From patchwork Fri Sep 27 12:10:44 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jani Nikula X-Patchwork-Id: 2954361 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E7DA69F244 for ; Fri, 27 Sep 2013 12:12:14 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9641C202AB for ; Fri, 27 Sep 2013 12:12:13 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 446DE20278 for ; Fri, 27 Sep 2013 12:12:12 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 43CAFE6657 for ; Fri, 27 Sep 2013 05:12:12 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTP id 04ABDE633C for ; Fri, 27 Sep 2013 05:08:19 -0700 (PDT) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 27 Sep 2013 05:08:18 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.90,992,1371106800"; d="scan'208";a="410372080" Received: from jnikula-mobl1.fi.intel.com (HELO localhost) ([10.237.72.185]) by orsmga002.jf.intel.com with ESMTP; 27 Sep 2013 05:08:17 -0700 From: Jani Nikula To: intel-gfx@lists.freedesktop.org Date: Fri, 27 Sep 2013 15:10:44 +0300 Message-Id: <1380283844-30766-1-git-send-email-jani.nikula@intel.com> X-Mailer: git-send-email 1.7.9.5 Organization: Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo Subject: [Intel-gfx] [PATCH] drm/i915/dp: do not write DP_TRAINING_PATTERN_SET all the time X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org X-Spam-Status: No, score=-6.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Neither the DP spec nor the compliance test spec state or imply that we should write the DP_TRAINING_PATTERN_SET at every voltage swing and pre-emphasis change. Indeed we probably shouldn't. So don't. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=49402 Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä --- I haven't tested this much, but it fixes the Zotac DP -> dual-hdmi dongle for me. --- drivers/gpu/drm/i915/intel_dp.c | 129 ++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 95a3159..ab805d3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2313,7 +2313,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) static bool intel_dp_set_link_train(struct intel_dp *intel_dp, - uint32_t dp_reg_value, + uint32_t *DP, uint8_t dp_train_pat) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -2349,50 +2349,51 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, I915_WRITE(DP_TP_CTL(port), temp); } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) { - dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT; + *DP &= ~DP_LINK_TRAIN_MASK_CPT; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: - dp_reg_value |= DP_LINK_TRAIN_OFF_CPT; + *DP |= DP_LINK_TRAIN_OFF_CPT; break; case DP_TRAINING_PATTERN_1: - dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT; + *DP |= DP_LINK_TRAIN_PAT_1_CPT; break; case DP_TRAINING_PATTERN_2: - dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; + *DP |= DP_LINK_TRAIN_PAT_2_CPT; break; case DP_TRAINING_PATTERN_3: DRM_ERROR("DP training pattern 3 not supported\n"); - dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; + *DP |= DP_LINK_TRAIN_PAT_2_CPT; break; } } else { - dp_reg_value &= ~DP_LINK_TRAIN_MASK; + *DP &= ~DP_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: - dp_reg_value |= DP_LINK_TRAIN_OFF; + *DP |= DP_LINK_TRAIN_OFF; break; case DP_TRAINING_PATTERN_1: - dp_reg_value |= DP_LINK_TRAIN_PAT_1; + *DP |= DP_LINK_TRAIN_PAT_1; break; case DP_TRAINING_PATTERN_2: - dp_reg_value |= DP_LINK_TRAIN_PAT_2; + *DP |= DP_LINK_TRAIN_PAT_2; break; case DP_TRAINING_PATTERN_3: DRM_ERROR("DP training pattern 3 not supported\n"); - dp_reg_value |= DP_LINK_TRAIN_PAT_2; + *DP |= DP_LINK_TRAIN_PAT_2; break; } } - I915_WRITE(intel_dp->output_reg, dp_reg_value); + I915_WRITE(intel_dp->output_reg, *DP); POSTING_READ(intel_dp->output_reg); - intel_dp_aux_native_write_1(intel_dp, - DP_TRAINING_PATTERN_SET, - dp_train_pat); + ret = intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET, + dp_train_pat); + if (ret != 1) + return false; if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) != DP_TRAINING_PATTERN_DISABLE) { @@ -2407,6 +2408,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, return true; } +static bool +intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP, + uint8_t dp_train_pat) +{ + memset(intel_dp->train_set, 0, 4); + intel_dp_set_signal_levels(intel_dp, DP); + return intel_dp_set_link_train(intel_dp, DP, dp_train_pat); +} + +static bool +intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP, + uint8_t link_status[DP_LINK_STATUS_SIZE]) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + intel_get_adjust_train(intel_dp, link_status); + intel_dp_set_signal_levels(intel_dp, DP); + + I915_WRITE(intel_dp->output_reg, *DP); + POSTING_READ(intel_dp->output_reg); + + ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET, + intel_dp->train_set, + intel_dp->lane_count); + + return ret == intel_dp->lane_count; +} + static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); @@ -2459,21 +2491,19 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP |= DP_PORT_EN; - memset(intel_dp->train_set, 0, 4); + /* clock recovery */ + if (!intel_dp_reset_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to enable link training\n"); + return; + } + voltage = 0xff; voltage_tries = 0; loop_tries = 0; for (;;) { - /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ - uint8_t link_status[DP_LINK_STATUS_SIZE]; - - intel_dp_set_signal_levels(intel_dp, &DP); - - /* Set training pattern 1 */ - if (!intel_dp_set_link_train(intel_dp, DP, - DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE)) - break; + uint8_t link_status[DP_LINK_STATUS_SIZE]; drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); if (!intel_dp_get_link_status(intel_dp, link_status)) { @@ -2496,7 +2526,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DRM_DEBUG_KMS("too many full retries, give up\n"); break; } - memset(intel_dp->train_set, 0, 4); + intel_dp_reset_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE); voltage_tries = 0; continue; } @@ -2512,8 +2544,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) voltage_tries = 0; voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp, link_status); + /* Update training set as requested by target */ + if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) { + DRM_ERROR("failed to update link training\n"); + break; + } } intel_dp->DP = DP; @@ -2527,11 +2562,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) uint32_t DP = intel_dp->DP; /* channel equalization */ + if (!intel_dp_set_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_2 | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to start channel equalization\n"); + return; + } + tries = 0; cr_tries = 0; channel_eq = false; for (;;) { - uint8_t link_status[DP_LINK_STATUS_SIZE]; + uint8_t link_status[DP_LINK_STATUS_SIZE]; if (cr_tries > 5) { DRM_ERROR("failed to train DP, aborting\n"); @@ -2539,21 +2581,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - intel_dp_set_signal_levels(intel_dp, &DP); - - /* channel eq pattern */ - if (!intel_dp_set_link_train(intel_dp, DP, - DP_TRAINING_PATTERN_2 | - DP_LINK_SCRAMBLING_DISABLE)) - break; - drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); - if (!intel_dp_get_link_status(intel_dp, link_status)) + if (!intel_dp_get_link_status(intel_dp, link_status)) { + DRM_ERROR("failed to get link status\n"); break; + } /* Make sure clock is still ok */ if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { intel_dp_start_link_train(intel_dp); + intel_dp_set_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_2 | + DP_LINK_SCRAMBLING_DISABLE); cr_tries++; continue; } @@ -2567,13 +2606,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) if (tries > 5) { intel_dp_link_down(intel_dp); intel_dp_start_link_train(intel_dp); + intel_dp_set_link_train(intel_dp, &DP, + DP_TRAINING_PATTERN_2 | + DP_LINK_SCRAMBLING_DISABLE); tries = 0; cr_tries++; continue; } - /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp, link_status); + /* Update training set as requested by target */ + if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) { + DRM_ERROR("failed to update link training\n"); + break; + } ++tries; } @@ -2588,7 +2633,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) void intel_dp_stop_link_train(struct intel_dp *intel_dp) { - intel_dp_set_link_train(intel_dp, intel_dp->DP, + intel_dp_set_link_train(intel_dp, &intel_dp->DP, DP_TRAINING_PATTERN_DISABLE); }