From patchwork Tue Aug 28 22:06:36 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paulo Zanoni X-Patchwork-Id: 1382721 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 689263FDF5 for ; Tue, 28 Aug 2012 22:11:26 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 315A39EF8F for ; Tue, 28 Aug 2012 15:11:26 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mail-yx0-f177.google.com (mail-yx0-f177.google.com [209.85.213.177]) by gabe.freedesktop.org (Postfix) with ESMTP id 81EF59E9A3 for ; Tue, 28 Aug 2012 15:07:25 -0700 (PDT) Received: by mail-yx0-f177.google.com with SMTP id q9so1203648yen.36 for ; Tue, 28 Aug 2012 15:07:25 -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=U1aiGT4hErK0q8JA8H2tJegnSNMacNAun8R9MuRsWDI=; b=VzzcFTaw4nJX16d7XSrZcJtE5bd69S+LWZII0JJZN+Tlw8xqF2fr94kb537BZmUmco mgSruEaZL4f5u0hBQ0gmpoQhLe6XF85bB87n2poKR47bv4SmbRAg5ii80tWPiSynhgxF S1gsqOyspwwuzC5SRgbgrMqC9P0ePdLebxoyeI7KDAqMqXpFnEcM/G7f0w9np4NRN+1k cYhbOQOwwLZBJwX+xZlD5VXzN09qi4Yx3dVuJw1yBB/JCrasUPFyaaz3zTvhkgC+VFTY JgX/tIUsluGgsH0u5tWvx0ifLl2R1T6HYt8ANbNTWTcQjDSC23i9EW4TmCSaIcZZAM2P 8CAA== Received: by 10.236.200.132 with SMTP id z4mr15654997yhn.93.1346191645447; Tue, 28 Aug 2012 15:07:25 -0700 (PDT) Received: from vicky.domain.invalid (189.114.178.236.dynamic.adsl.gvt.net.br. [189.114.178.236]) by mx.google.com with ESMTPS id z3sm4434172anj.20.2012.08.28.15.07.23 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 28 Aug 2012 15:07:24 -0700 (PDT) From: Paulo Zanoni To: intel-gfx@lists.freedesktop.org Date: Tue, 28 Aug 2012 19:06:36 -0300 Message-Id: <1346191621-12996-6-git-send-email-przanoni@gmail.com> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1346191621-12996-1-git-send-email-przanoni@gmail.com> References: <1346191621-12996-1-git-send-email-przanoni@gmail.com> Cc: Paulo Zanoni Subject: [Intel-gfx] [RFC 05/30] drm/i915: implement intel_ddi_pll_mode_set 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 Previously we were setting the PLLs at encoder->mode_set. This was a problem because there's no way to fail and return error codes from encoder->mode_set. So now we follow the example of the previous gens and try to set the PLLs inside ironlake_crtc_mode_set, properly failing when we need to fail. In addition to moving the DDI PLL code from hsw_fdi_link_train and intel_ddi_mode_set to the new intel_ddi_pll_mode_set, we now try to use WR PLL 2 when it's available. Signed-off-by: Paulo Zanoni --- drivers/gpu/drm/i915/intel_ddi.c | 168 +++++++++++++++++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 4 + drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 128 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e3dac45..a29c1e7 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -136,15 +136,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp, i; - /* Configure CPU PLL, wait for warmup */ - I915_WRITE(SPLL_CTL, - SPLL_PLL_ENABLE | - SPLL_PLL_FREQ_1350MHz | - SPLL_PLL_SCC); - - /* Use SPLL to drive the output when in FDI mode */ - I915_WRITE(PORT_CLK_SEL(PORT_E), - PORT_CLK_SEL_SPLL); I915_WRITE(PIPE_CLK_SEL(pipe), PIPE_CLK_SEL_PORT(PORT_E)); @@ -645,6 +636,128 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { {298000, 2, 21, 19}, }; +bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *intel_encoder; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool is_hdmi = false, is_crt = false; + int port, i, to_use, num_encoders = 0; + bool wrpll_used[] = {false, false}; + bool spll_used = false; + uint32_t wrpll_reg[] = {WRPLL_CTL1, WRPLL_CTL2}; + uint32_t wrpll_sel[] = {PORT_CLK_SEL_WRPLL1, PORT_CLK_SEL_WRPLL2}; + uint32_t temp; + + for_each_encoder_on_crtc(dev, crtc, intel_encoder) { + struct intel_hdmi *intel_hdmi; + + switch (intel_encoder->type) { + case INTEL_OUTPUT_HDMI: + is_hdmi = true; + intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base); + port = intel_hdmi->ddi_port; + break; + case INTEL_OUTPUT_ANALOG: + is_crt = true; + port = PORT_E; + break; + default: + WARN(1, "Invalid encoder type %d on crtc for pipe %d\n", + intel_encoder->type, intel_crtc->pipe); + return false; + } + + num_encoders++; + } + + if (num_encoders != 1) { + WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders, + intel_crtc->pipe); + return false; + } + + for (i = PORT_A; i <= PORT_E; i++) { + if (i == port) + continue; + + switch (I915_READ(PORT_CLK_SEL(i))) { + case PORT_CLK_SEL_WRPLL1: + wrpll_used[0] = true; + break; + case PORT_CLK_SEL_WRPLL2: + wrpll_used[1] = true; + break; + case PORT_CLK_SEL_SPLL: + spll_used = true; + break; + } + } + + if (is_hdmi) { + int p, n2, r2; + + for (i = 0; i < ARRAY_SIZE(wrpll_reg); i++) + if (!wrpll_used[i]) + break; + if (i == ARRAY_SIZE(wrpll_reg)) { + DRM_ERROR("No WRPLL available\n"); + return false; + } + to_use = i; + + temp = I915_READ(wrpll_reg[to_use]); + if (temp & WRPLL_PLL_ENABLE) { + WARN(1, "WR PLL is enabled\n"); + temp &= ~WRPLL_PLL_ENABLE; + I915_WRITE(wrpll_reg[to_use], temp); + POSTING_READ(wrpll_reg[to_use]); + } + + for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) + if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock) + break; + if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) + i--; + + p = wrpll_tmds_clock_table[i].p; + n2 = wrpll_tmds_clock_table[i].n2; + r2 = wrpll_tmds_clock_table[i].r2; + + if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock) + DRM_INFO("WRPLL: using %dKHz settings on %dKHz mode\n", + wrpll_tmds_clock_table[i].clock, + crtc->mode.clock); + + DRM_DEBUG_KMS("WRPLL %d: %dKHz with p=%d, n2=%d r2=%d\n", + to_use +1, crtc->mode.clock, p, n2, r2); + + I915_WRITE(wrpll_reg[to_use], + WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | + WRPLL_DIVIDER_POST(p)); + + udelay(20); + + I915_WRITE(PORT_CLK_SEL(port), wrpll_sel[to_use]); + + } else if (is_crt) { + if (spll_used) { + DRM_ERROR("SPLL not available\n"); + return false; + } + + I915_WRITE(SPLL_CTL, SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SCC); + + I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_SPLL); + } + + return true; +} + void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -656,48 +769,13 @@ void intel_ddi_mode_set(struct drm_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); int port = intel_hdmi->ddi_port; int pipe = intel_crtc->pipe; - int p, n2, r2; - u32 temp, i; + u32 temp; /* On Haswell, we need to enable the clocks and prepare DDI function to * work in HDMI mode for this pipe. */ DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); - for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) - if (crtc->mode.clock <= wrpll_tmds_clock_table[i].clock) - break; - - if (i == ARRAY_SIZE(wrpll_tmds_clock_table)) - i--; - - p = wrpll_tmds_clock_table[i].p; - n2 = wrpll_tmds_clock_table[i].n2; - r2 = wrpll_tmds_clock_table[i].r2; - - if (wrpll_tmds_clock_table[i].clock != crtc->mode.clock) - DRM_INFO("WR PLL: using settings for %dKHz on %dKHz mode\n", - wrpll_tmds_clock_table[i].clock, crtc->mode.clock); - - DRM_DEBUG_KMS("WR PLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", - crtc->mode.clock, p, n2, r2); - - /* Configure WR PLL 1, program the correct divider values for - * the desired frequency and wait for warmup */ - I915_WRITE(WRPLL_CTL1, - WRPLL_PLL_ENABLE | - WRPLL_PLL_SELECT_LCPLL_2700 | - WRPLL_DIVIDER_REFERENCE(r2) | - WRPLL_DIVIDER_FEEDBACK(n2) | - WRPLL_DIVIDER_POST(p)); - - udelay(20); - - /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use - * this port for connection. - */ - I915_WRITE(PORT_CLK_SEL(port), - PORT_CLK_SEL_WRPLL1); I915_WRITE(PIPE_CLK_SEL(pipe), PIPE_CLK_SEL_PORT(port)); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 33eebcb..cd506bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4627,6 +4627,10 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, num_connectors++; } + if (IS_HASWELL(dev)) + if (!intel_ddi_pll_mode_set(crtc)) + return -EINVAL; + refclk = ironlake_get_refclk(crtc); /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b99af38..aa62439 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -522,6 +522,7 @@ extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); extern void ironlake_teardown_rc6(struct drm_device *dev); extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); +extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); extern void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode);