From patchwork Mon Oct 15 18:51:41 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Zanoni X-Patchwork-Id: 1595201 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id 11EB5DFB34 for ; Mon, 15 Oct 2012 18:58:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F27849EFCD for ; Mon, 15 Oct 2012 11:58:45 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-yh0-f49.google.com (mail-yh0-f49.google.com [209.85.213.49]) by gabe.freedesktop.org (Postfix) with ESMTP id 3D7789F6FC for ; Mon, 15 Oct 2012 11:52:31 -0700 (PDT) Received: by mail-yh0-f49.google.com with SMTP id j52so1335408yhj.36 for ; Mon, 15 Oct 2012 11:52:31 -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=5RDKTIg/T3V49ZUVKyckwfaI9h9RsmfQKBhDgZGuY+g=; b=C/nbqfPvFczot7aK1ddQKejFjGXPOo2TQJJhOa+3Ivf+e+676SbVXEdyxKrqVb2Ox1 zhxXoUIGpuOmVFNAJeymTu6n3GHBo7hC+4UWe2l7Av/RO6nwX+iXEddI+QUHH65hPSXQ ktoIrXNA1A3ZCZ0ZVpHiWzWCwYKKh07CxKfMMW4ih8TuizAba4U4t8lJnYb54ZG133WB J7XBvzcTWRzd9tIkGuw05GILTmjmBeHBRkUnr+/Wti9bV25ImcgENfBJnDdifg466ir2 utbDoNMhT5QxZ8gUlIJ/WDLFV/pfY39cvPiSOgAjazQNxenMDGNSUDboZt2MYpHWWmBu TlnA== Received: by 10.236.190.35 with SMTP id d23mr11283295yhn.104.1350327151038; Mon, 15 Oct 2012 11:52:31 -0700 (PDT) Received: from vicky.domain.invalid ([177.16.37.219]) by mx.google.com with ESMTPS id u67sm15879079yhb.8.2012.10.15.11.52.29 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 15 Oct 2012 11:52:30 -0700 (PDT) From: Paulo Zanoni To: intel-gfx@lists.freedesktop.org Date: Mon, 15 Oct 2012 15:51:41 -0300 Message-Id: <1350327102-4463-14-git-send-email-przanoni@gmail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1350327102-4463-1-git-send-email-przanoni@gmail.com> References: <1350327102-4463-1-git-send-email-przanoni@gmail.com> Cc: Paulo Zanoni Subject: [Intel-gfx] [PATCH 13/14] 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 Reviewed-by: Damien Lespiau --- 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 601ffc2..81cca48 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1108,14 +1108,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, @@ -1210,3 +1219,43 @@ void intel_ddi_pll_init(struct drm_device *dev) if (val & LCPLL_PLL_DISABLE) DRM_ERROR("LCPLL is disabled\n"); } + +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 3a5fe2f..36687d9 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 @@ -1266,7 +1264,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; @@ -1854,16 +1852,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, @@ -1949,7 +1951,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; @@ -2035,6 +2037,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__ */