From patchwork Fri Nov 1 18:02:25 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jesse Barnes X-Patchwork-Id: 3126921 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id AD5C0BEEB2 for ; Fri, 1 Nov 2013 18:02:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 64CC8204C9 for ; Fri, 1 Nov 2013 18:02:41 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 5F0E4204B0 for ; Fri, 1 Nov 2013 18:02:40 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 3DE14F074F; Fri, 1 Nov 2013 11:02:39 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from outbound-ss-2175.bluehost.com (outbound-ss-2175.bluehost.com [74.220.218.8]) by gabe.freedesktop.org (Postfix) with SMTP id C6EEEF0751 for ; Fri, 1 Nov 2013 11:02:33 -0700 (PDT) Received: (qmail 16909 invoked by uid 0); 1 Nov 2013 18:02:30 -0000 Received: from unknown (HELO box514.bluehost.com) (74.220.219.114) by oproxy16-pub.mail.unifiedlayer.com with SMTP; 1 Nov 2013 18:02:30 -0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuousgeek.org; s=default; h=References:In-Reply-To:Message-Id:Date:Subject:To:From; bh=K0arBM7vs/oOpaaITOpBshQCYq6BqB5dxBgBO8RKDnE=; b=TmJyJlY5TvIhZOu0xa/ns5gQcEV7dKDB+WRK65uC9z1eE5hS6oXrNyZLkzlT83ZK5yEK4AzeWlRmBSIEaTMSGsWu/82tJqhBz7YGGovIlaRJDudVS4hKnBjFInLIPJou; Received: from [67.161.37.189] (port=45085 helo=localhost.localdomain) by box514.bluehost.com with esmtpsa (TLSv1:CAMELLIA256-SHA:256) (Exim 4.80) (envelope-from ) id 1VcJ3F-00039v-Vo for intel-gfx@lists.freedesktop.org; Fri, 01 Nov 2013 12:02:30 -0600 From: Jesse Barnes To: intel-gfx@lists.freedesktop.org Date: Fri, 1 Nov 2013 11:02:25 -0700 Message-Id: <1383328945-1286-1-git-send-email-jbarnes@virtuousgeek.org> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1383320487-790-4-git-send-email-jbarnes@virtuousgeek.org> References: <1383320487-790-4-git-send-email-jbarnes@virtuousgeek.org> X-Identified-User: {10642:box514.bluehost.com:virtuous:virtuousgeek.org} {sentby:smtp auth 67.161.37.189 authed with jbarnes@virtuousgeek.org} Subject: [Intel-gfx] [PATCH] drm/i915/vlv: modeset_global_* for VLV v2 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@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-3.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_BL_SPAMCOP_NET, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham 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 On VLV/BYT, we can adjust the CDclk frequency up or down based on the max pixel clock we need to drive. Lowering it can save power, while raising it is necessary to support high resolution. Add proper modeset_global_pipes and modeset_global_resources support to perform this adjustment as necessary. v2: use punit interface for 320 and 266 MHz CDclk adjustments (Ville) Signed-off-by: Jesse Barnes --- drivers/gpu/drm/i915/i915_reg.h | 7 ++ drivers/gpu/drm/i915/intel_display.c | 175 +++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 737d8a3..8a34dcc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -363,6 +363,11 @@ #define PUNIT_OPCODE_REG_READ 6 #define PUNIT_OPCODE_REG_WRITE 7 +#define PUNIT_REG_DSPFREQ 0x36 +#define DSPFREQSTAT_SHIFT 30 +#define DSPFREQSTAT_MASK (0x3 << DSPFREQSTAT_SHIFT) +#define DSPFREQGUAR_SHIFT 14 +#define DSPFREQGUAR_MASK (0x3 << DSPFREQGUAR_SHIFT) #define PUNIT_REG_PWRGT_CTRL 0x60 #define PUNIT_REG_PWRGT_STATUS 0x61 #define PUNIT_CLK_GATE 1 @@ -1453,6 +1458,8 @@ #define CZCLK_FREQ_MASK 0xf #define GMBUSFREQ_VLV (VLV_DISPLAY_BASE + 0x6510) +#define CZCLK_CDCLK_FREQ_RATIO (VLV_DISPLAY_BASE + 0x6508) + /* * Palette regs */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index faa7548..85b1dbf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3894,6 +3894,176 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc) I915_WRITE(BCLRPAT(crtc->pipe), 0); } +static int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int vco; + + switch (dev_priv->mem_freq) { + default: + case 800: + vco = 800; + break; + case 1066: + vco = 1600; + break; + case 1333: + vco = 2000; + break; + } + + return vco; +} + +/* Adjust CDclk dividers to allow high res or save power if possible */ +static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + if (cdclk == 400) { + u32 divider, vco; + + vco = valleyview_get_vco(dev_priv); + divider = (vco * 10) / cdclk; + divider = ((divider * 2) / 10) - 1; + + mutex_lock(&dev_priv->dpio_lock); + /* adjust cdclk divider */ + val = vlv_cck_read(dev_priv, 0x6b); + val &= ~0xf; + val |= divider; + vlv_cck_write(dev_priv, 0x6b, val); + mutex_unlock(&dev_priv->dpio_lock); + } else { + u32 cmd; + + if (cdclk == 320) + cmd = 2; + else if (cdclk == 266) + cmd = 1; + else + cmd = 0; + + mutex_lock(&dev_priv->rps.hw_lock); + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + val &= ~DSPFREQGUAR_MASK; + val |= (cmd << DSPFREQGUAR_SHIFT); + vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val); + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) & + DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT), + 50)) { + DRM_ERROR("timed out waiting for CDclk change\n"); + } + mutex_unlock(&dev_priv->rps.hw_lock); + } + + mutex_lock(&dev_priv->dpio_lock); + /* adjust self-refresh exit latency value */ + val = vlv_bunit_read(dev_priv, 0x11); + val &= ~0x7f; + + /* + * For high bandwidth configs, we set a higher latency in the bunit + * so that the core display fetch happens in time to avoid underruns. + */ + if (cdclk == 400) + val |= 0x12; + else + val |= 0xc; + vlv_bunit_write(dev_priv, 0x11, val); + mutex_unlock(&dev_priv->dpio_lock); +} + +static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv) +{ + int cur_cdclk, vco; + int divider; + + vco = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->dpio_lock); + divider = vlv_cck_read(dev_priv, 0x6b); + mutex_unlock(&dev_priv->dpio_lock); + + divider &= 0xf; + divider = ((divider + 1) * 10) / 2; + + cur_cdclk = (vco * 10) / divider; + + return cur_cdclk; +} + +static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixclk) +{ + int cur_cdclk; + + cur_cdclk = valleyview_cur_cdclk(dev_priv); + + /* + * Really only a few cases to deal with, as only 4 CDclks are supported: + * 200MHz + * 267MHz + * 320MHz + * 400MHz + * So we check to see whether we're above 90% of the lower bin and + * adjust if needed. + */ + if (max_pixclk > 288000) { + return 400; + } else if (max_pixclk <= 288000 && max_pixclk > 240300) { + return 320; + } else + return 266; + /* Looks like the 200MHz CDclk freq doesn't work on some configs */ +} + +static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + int max_pixclk = 0; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) { + if (!intel_crtc->base.enabled) + continue; + + if (max_pixclk < intel_crtc->config.adjusted_mode.clock) + max_pixclk = intel_crtc->config.adjusted_mode.clock; + } + + return max_pixclk; +} + +static void valleyview_modeset_global_pipes(struct drm_device *dev, + unsigned *prepare_pipes) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc; + int max_pixclk = intel_mode_max_pixclk(dev_priv); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + + if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk) + return; + + list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, + base.head) + if (intel_crtc->base.enabled) + *prepare_pipes |= (1 << intel_crtc->pipe); +} + +static void valleyview_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev_priv); + int cur_cdclk = valleyview_cur_cdclk(dev_priv); + int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); + + if (req_cdclk != cur_cdclk) + valleyview_set_cdclk(dev, req_cdclk); +} + static void valleyview_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -10336,6 +10506,11 @@ static void intel_init_display(struct drm_device *dev) } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.modeset_global_resources = + valleyview_modeset_global_resources; + dev_priv->display.modeset_global_pipes = + valleyview_modeset_global_pipes; } /* Default just returns -ENODEV to indicate unsupported */