From patchwork Wed Oct 14 12:00:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: durgadoss.r@intel.com X-Patchwork-Id: 7392331 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.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 57C5F9F1B9 for ; Wed, 14 Oct 2015 11:31:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 49BC320632 for ; Wed, 14 Oct 2015 11:31:57 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 3E9212065A for ; Wed, 14 Oct 2015 11:31:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A55476EC2D; Wed, 14 Oct 2015 04:31:55 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by gabe.freedesktop.org (Postfix) with ESMTP id 361E872183 for ; Wed, 14 Oct 2015 04:31:52 -0700 (PDT) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga103.fm.intel.com with ESMTP; 14 Oct 2015 04:31:51 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,681,1437462000"; d="scan'208";a="664106021" Received: from dr3-desktop.iind.intel.com ([10.223.26.125]) by orsmga003.jf.intel.com with ESMTP; 14 Oct 2015 04:31:50 -0700 From: Durgadoss R To: intel-gfx@lists.freedesktop.org Date: Wed, 14 Oct 2015 17:30:13 +0530 Message-Id: <1444824013-23147-7-git-send-email-durgadoss.r@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1444824013-23147-1-git-send-email-durgadoss.r@intel.com> References: <1444824013-23147-1-git-send-email-durgadoss.r@intel.com> Subject: [Intel-gfx] [RFCv2 DP-typeC 6/6] drm/i915/dp: Enable Upfront link training for typeC DP support on CHV X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 To support USB type C alternate DP mode, the display driver needs to know the number of lanes required by DP panel as well as number of lanes that can be supported by the type-C cable. Sometimes, the type-C cable may limit the bandwidth even if Panel can support more lanes. To address these scenarios, the display driver will start link training with max lanes, and if the link training fails, the driver then falls back to x2 lanes. * Since link training is done before modeset, planes are not enabled. Only encoder and the its associated PLLs are enabled. * Once link training is done, the encoder and its PLLs are disabled; so that the subsequent modeset is not aware of these changes. * As of now, this is tested only on CHV. Signed-off-by: Durgadoss R --- drivers/gpu/drm/i915/intel_display.c | 135 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_dp.c | 2 + drivers/gpu/drm/i915/intel_drv.h | 2 + 3 files changed, 139 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a2ec8cb..17b3c7a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15751,3 +15751,138 @@ void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file) spin_unlock_irq(&dev->event_lock); } } + +bool chv_upfront_link_train(struct drm_device *dev, + struct intel_dp *intel_dp, struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_connector *connector = intel_dp->attached_connector; + struct intel_encoder *tmp_encoder, *encoder = connector->encoder; + struct intel_crtc *tmp_crtc; + struct drm_crtc *tmp_drm_crtc; + bool found = false, valid_crtc = false; + uint8_t tmp_lane_count, tmp_link_bw; + + if (!connector || !encoder) { + DRM_DEBUG_KMS("dp connector/encoder is NULL\n"); + return false; + } + + /* If we already have a crtc, start link training directly */ + if (crtc) { + valid_crtc = true; + goto start_link_train; + } + + /* Find an unused crtc and use it for link training */ + for_each_intel_crtc(dev, crtc) { + if (intel_crtc_active(&crtc->base)) + continue; + + /* Make sure the new crtc will work with the encoder */ + if (drm_encoder_crtc_ok(&encoder->base, &crtc->base)) { + /* Save the existing values */ + tmp_encoder = connector->new_encoder; + tmp_crtc = encoder->new_crtc; + tmp_drm_crtc = encoder->base.crtc; + + connector->new_encoder = encoder; + encoder->new_crtc = crtc; + encoder->base.crtc = &crtc->base; + + found = true; + break; + } + } + + if (!found) { + DRM_ERROR("Could not find crtc for upfront link training\n"); + return false; + } + +start_link_train: + + DRM_DEBUG_KMS("upfront link training on pipe:%c\n", + pipe_name(crtc->pipe)); + found = false; + + /* Save the existing lane_count and link_bw values */ + tmp_lane_count = intel_dp->lane_count; + tmp_link_bw = intel_dp->link_bw; + + /* Initialize with Max Link rate & lane count supported by panel */ + intel_dp->link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE]; + intel_dp->lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & + DP_MAX_LANE_COUNT_MASK; + + /* CHV does not support HBR2 */ + if (intel_dp->link_bw == DP_LINK_BW_5_4) + intel_dp->link_bw = DP_LINK_BW_2_7; + + do { + /* Find port clock from link_bw */ + crtc->config.port_clock = + drm_dp_bw_code_to_link_rate(intel_dp->link_bw); + + /* Enable PLL followed by port */ + intel_dp_set_clock(encoder, &crtc->config, intel_dp->link_bw); + chv_update_pll(crtc); + encoder->pre_pll_enable(encoder); + chv_enable_pll(crtc); + encoder->pre_enable(encoder); + + /* Check if link training passed; if so update lane count */ + /* TODO: Newer code has this variable as 'train_set_valid */ + if (intel_dp->has_fast_link_train) { + intel_dp->dpcd[DP_MAX_LANE_COUNT] &= + ~DP_MAX_LANE_COUNT_MASK; + intel_dp->dpcd[DP_MAX_LANE_COUNT] |= + intel_dp->lane_count & DP_MAX_LANE_COUNT_MASK; + + found = true; + } + + /* Reset encoder for next retry or for clean up */ + encoder->disable(encoder); + encoder->post_disable(encoder); + chv_disable_pll(dev_priv, crtc->pipe); + + if (found) + goto exit; + + DRM_DEBUG_KMS("upfront link training failed. lanes:%d bw:%d\n", + intel_dp->lane_count, intel_dp->link_bw); + + /* Go down to the next level and retry link training */ + if (intel_dp->lane_count == 4) { + intel_dp->lane_count = 2; + } else if (intel_dp->lane_count == 2) { + intel_dp->lane_count = 1; + } else if (intel_dp->link_bw == DP_LINK_BW_2_7) { + intel_dp->link_bw = DP_LINK_BW_1_62; + intel_dp->lane_count = 4; + } else { + /* Tried all combinations, so exit */ + break; + } + + } while (1); + +exit: + /* Clear local associations made */ + if (!valid_crtc) { + connector->new_encoder = tmp_encoder; + encoder->new_crtc = tmp_crtc; + encoder->base.crtc = tmp_drm_crtc; + } + + if (found) + DRM_DEBUG_KMS("upfront link training passed. lanes:%d bw:%d\n", + intel_dp->lane_count, intel_dp->link_bw); + + /* Restore lane_count and link_bw values */ + intel_dp->lane_count = tmp_lane_count; + intel_dp->link_bw = tmp_link_bw; + + return found; +} diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 8376b47..0254395 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4808,6 +4808,8 @@ static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp) if (HAS_DDI(dev)) return intel_ddi_upfront_link_train(dev, intel_dp, intel_crtc); + else if (IS_CHERRYVIEW(dev)) + return intel_chv_upfront_link_train(dev, intel_dp, intel_crtc); /* Not a supported platform. Assume we don't need upfront_train */ return true; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 82af4e6..c214797 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1166,6 +1166,8 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv); void intel_dp_get_m_n(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n); +bool intel_chv_upfront_link_train(struct drm_device *dev, + struct intel_dp *intel_dp, struct intel_crtc *crtc); int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); void ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,