From patchwork Tue Oct 2 20:51:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Zanoni X-Patchwork-Id: 1538931 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 5C1A63FDAE for ; Tue, 2 Oct 2012 21:04:38 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6932E9EFC5 for ; Tue, 2 Oct 2012 14:04:38 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-gh0-f177.google.com (mail-gh0-f177.google.com [209.85.160.177]) by gabe.freedesktop.org (Postfix) with ESMTP id DFDBA9E74C for ; Tue, 2 Oct 2012 13:53:35 -0700 (PDT) Received: by mail-gh0-f177.google.com with SMTP id f20so1791743ghb.36 for ; Tue, 02 Oct 2012 13:53:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=do5HF2/na1JzGukWHcaDsbrzOnkQdeqsI7D7fSk42oc=; b=OerieQYzx18Dc8hfXQmIwZfUpQkBaZe8rlWoRQFh198OoTa3HCHbVvI/eDmi2zUXCx wa0ajV9p5tzHgLUxh1TDy/sXyI6JKSzOka754lZgCsxDgousjXwEMhWKW0Sz+OVNIHsM OTJp95iWn8Zd972WZ/19SPGfeiXBLwh8FgeXx4zC9lrHJswpePadLZ1LoRIEGI9nDTGp PsczA1hzor1vVWE3bWiNpBXv8qdb016UQqar5jpz3twtRRYqMgVLBb9YSYE1AiGjwbiD L1GnBei3an8+XpCsKRoeAlE2zOFV4vSl5w2w3eLcudu1hMXqaOVJizAXbUsd4qarFdiH Byfg== Received: by 10.101.67.13 with SMTP id u13mr5102249ank.66.1349211215540; Tue, 02 Oct 2012 13:53:35 -0700 (PDT) Received: from vicky.domain.invalid ([187.59.149.118]) by mx.google.com with ESMTPS id f1sm2117168ank.12.2012.10.02.13.53.33 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 02 Oct 2012 13:53:35 -0700 (PDT) From: Paulo Zanoni To: intel-gfx@lists.freedesktop.org Date: Tue, 2 Oct 2012 17:51:58 -0300 Message-Id: <1349211142-4802-24-git-send-email-przanoni@gmail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1349211142-4802-1-git-send-email-przanoni@gmail.com> References: <1349211142-4802-1-git-send-email-przanoni@gmail.com> Cc: Paulo Zanoni Subject: [Intel-gfx] [PATCH 23/47] drm/i915: implement Haswell DP link train sequence 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 From: Paulo Zanoni Previous patch "drm/i915: add basic Haswell DP link train bits" implemented the basic structure to set the voltage levels and training patterns. This patch adds the higher-level bits that are part of the mode set sequence and hot plug. Signed-off-by: Paulo Zanoni --- drivers/gpu/drm/i915/intel_ddi.c | 53 ++++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dp.c | 32 ++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 4 +++ 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 154fec7..c014652 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1106,14 +1106,23 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) { - struct drm_crtc *crtc = intel_encoder->base.crtc; - struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum port port = intel_ddi_get_encoder_port(intel_encoder); WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); I915_WRITE(PORT_CLK_SEL(port), intel_crtc->ddi_pll_sel); + + if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_start_link_train(intel_dp); + intel_dp_complete_link_train(intel_dp); + } } static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, @@ -1217,3 +1226,43 @@ void intel_ddi_pll_init(struct drm_device *dev) if (lcpll_needs_change) I915_WRITE(LCPLL_CTL, lcpll_val); } + +void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + enum port port = intel_dp->port; + bool wait; + uint32_t val; + + if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { + val = I915_READ(DDI_BUF_CTL(port)); + if (val & DDI_BUF_CTL_ENABLE) { + val &= ~DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), val); + wait = true; + } + + val = I915_READ(DP_TP_CTL(port)); + val &= ~(DP_TP_CTL_ENABLE | DP_TP_CTL_LINK_TRAIN_MASK); + val |= DP_TP_CTL_LINK_TRAIN_PAT1; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + if (wait) + intel_wait_ddi_buf_idle(dev_priv, port); + } + + val = DP_TP_CTL_ENABLE | DP_TP_CTL_MODE_SST | + DP_TP_CTL_LINK_TRAIN_PAT1 | DP_TP_CTL_SCRAMBLE_DISABLE; + if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) + val |= DP_TP_CTL_ENHANCED_FRAME_ENABLE; + I915_WRITE(DP_TP_CTL(port), val); + POSTING_READ(DP_TP_CTL(port)); + + intel_dp->DP |= DDI_BUF_CTL_ENABLE; + I915_WRITE(DDI_BUF_CTL(port), intel_dp->DP); + POSTING_READ(DDI_BUF_CTL(port)); + + udelay(600); +} diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a40df1e..72fc184 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -102,8 +102,6 @@ bool intel_encoder_is_pch_edp(struct drm_encoder *encoder) return is_pch_edp(intel_dp); } -static void intel_dp_start_link_train(struct intel_dp *intel_dp); -static void intel_dp_complete_link_train(struct intel_dp *intel_dp); static void intel_dp_link_down(struct intel_dp *intel_dp); void @@ -1267,7 +1265,7 @@ static void ironlake_edp_pll_off(struct intel_dp *intel_dp) } /* If the sink supports it, try to set the power state appropriately */ -static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) +void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) { int ret, i; @@ -1855,16 +1853,20 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, } /* Enable corresponding port and start training pattern 1 */ -static void +void intel_dp_start_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp->base.base.dev; + struct drm_encoder *encoder = &intel_dp->base.base; + struct drm_device *dev = encoder->dev; int i; uint8_t voltage; bool clock_recovery = false; int voltage_tries, loop_tries; uint32_t DP = intel_dp->DP; + if (IS_HASWELL(dev)) + intel_ddi_prepare_link_retrain(encoder); + /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, intel_dp->link_configuration, @@ -1950,7 +1952,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) intel_dp->DP = DP; } -static void +void intel_dp_complete_link_train(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; @@ -2036,6 +2038,24 @@ intel_dp_link_down(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t DP = intel_dp->DP; + /* + * DDI code has a strict mode set sequence and we should try to respect + * it, otherwise we might hang the machine in many different ways. So we + * really should be disabling the port only on a complete crtc_disable + * sequence. This function is just called under two conditions on DDI + * code: + * - Link train failed while doing crtc_enable, and on this case we + * really should respect the mode set sequence and wait for a + * crtc_disable. + * - Someone turned the monitor off and intel_dp_check_link_status + * called us. We don't need to disable the whole port on this case, so + * when someone turns the monitor on again, + * intel_ddi_prepare_link_retrain will take care of redoing the link + * train. + */ + if (IS_HASWELL(dev)) + return; + if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) return; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d89d428..95cbd67 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -423,6 +423,9 @@ void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); extern void intel_dp_init_link_config(struct intel_dp *intel_dp); +extern void intel_dp_start_link_train(struct intel_dp *intel_dp); +extern void intel_dp_complete_link_train(struct intel_dp *intel_dp); +extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config(struct intel_encoder *, int *, int *); extern int intel_edp_target_clock(struct intel_encoder *, @@ -599,5 +602,6 @@ extern void intel_ddi_pre_enable(struct intel_encoder *intel_encoder); extern void intel_ddi_post_disable(struct intel_encoder *intel_encoder); extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); +extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); #endif /* __INTEL_DRV_H__ */