From patchwork Wed Apr 15 13:07:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mika Kahola X-Patchwork-Id: 6220651 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A2956BF4A7 for ; Wed, 15 Apr 2015 13:09:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5C0D320270 for ; Wed, 15 Apr 2015 13:09:37 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id D777E202E5 for ; Wed, 15 Apr 2015 13:09:35 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5EC9D6E84E; Wed, 15 Apr 2015 06:09:35 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTP id E4CAA6E85A for ; Wed, 15 Apr 2015 06:09:31 -0700 (PDT) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 15 Apr 2015 06:08:11 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,582,1422950400"; d="scan'208";a="714047353" Received: from sorvi.fi.intel.com ([10.237.72.165]) by orsmga002.jf.intel.com with ESMTP; 15 Apr 2015 06:08:09 -0700 From: Mika Kahola To: intel-gfx@lists.freedesktop.org Date: Wed, 15 Apr 2015 16:07:20 +0300 Message-Id: <1429103244-3515-11-git-send-email-mika.kahola@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1429103244-3515-1-git-send-email-mika.kahola@intel.com> References: <1429103244-3515-1-git-send-email-mika.kahola@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH 10/14] drm/i915: HSW cdclk support 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: , 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 Implement support for changing the cdclk frequency during runtime on HSW. VLV/CHV already have support for this, so we can follow their example for the most part. Only the actual hardware programming differs, the rest is pretty much the same. The pipe pixel rate stuff is handled a bit differently for now due to the difference in pch vs. gmch pfit handling. Eventually we should unify that part to eliminate what is essentially duplicated code. v2: Grab rps.hw_lock around sandybridge_pcode_write() v3: Rebase due to power well vs. .global_resources() reordering Signed-off-by: Ville Syrjälä v3: Rebased to the latest Signed-off-by: Mika Kahola --- drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_display.c | 140 ++++++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d4cf3bc..74ff995 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6410,6 +6410,7 @@ enum skl_disp_power_wells { #define GEN6_PCODE_WRITE_D_COMP 0x11 #define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17 #define DISPLAY_IPS_CONTROL 0x19 #define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A #define GEN6_PCODE_DATA 0x138128 @@ -6859,10 +6860,12 @@ enum skl_disp_power_wells { #define LCPLL_PLL_LOCK (1<<30) #define LCPLL_CLK_FREQ_MASK (3<<26) #define LCPLL_CLK_FREQ_450 (0<<26) +#define LCPLL_CLK_FREQ_ALT_HSW (1<<26) /* 337.5 (ULX) or 540 */ #define LCPLL_CLK_FREQ_54O_BDW (1<<26) #define LCPLL_CLK_FREQ_337_5_BDW (2<<26) #define LCPLL_CLK_FREQ_675_BDW (3<<26) #define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_ROOT_CD_CLOCK_DISABLE (1<<24) #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) #define LCPLL_POWER_DOWN_ALLOW (1<<22) #define LCPLL_CD_SOURCE_FCLK (1<<21) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fa7baf2..35489cd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5214,7 +5214,16 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_VALLEYVIEW(dev)) { + if (IS_HASWELL(dev)) { + if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + dev_priv->max_cdclk_freq = 450000; + else if (IS_HSW_ULX(dev)) + dev_priv->max_cdclk_freq = 337500; + else if (IS_HSW_ULT(dev)) + dev_priv->max_cdclk_freq = 450000; + else + dev_priv->max_cdclk_freq = 540000; + } else if (IS_VALLEYVIEW(dev)) { dev_priv->max_cdclk_freq = 400000; } else { /* otherwise assume cdclk is fixed */ @@ -9065,6 +9074,125 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) intel_prepare_ddi(dev); } +/* compute the max rate for new configuration */ +static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *crtc; + int max_pixel_rate = 0; + + for_each_intel_crtc(dev, crtc) { + if (crtc->new_enabled) + max_pixel_rate = max((int)max_pixel_rate, + (int)ilk_pipe_pixel_rate(crtc->config)); + } + + return max_pixel_rate; +} + +static int haswell_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixel_rate) +{ + int cdclk; + + /* + * FIXME should also account for plane ratio + * once 64bpp pixel formats are supported. + */ + if (max_pixel_rate > 450000) + cdclk = 540000; + else if (max_pixel_rate > 337500 || !IS_HSW_ULX(dev_priv)) + cdclk = 450000; + else + cdclk = 337500; + + /* + * FIXME move the cdclk caclulation to + * compute_config() so we can fail gracegully. + */ + if (cdclk > dev_priv->max_cdclk_freq) { + DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n", + cdclk, dev_priv->max_cdclk_freq); + cdclk = dev_priv->max_cdclk_freq; + } + + return cdclk; +} + +static void haswell_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val; + + if (WARN((I915_READ(LCPLL_CTL) & + (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK | + LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE | + LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW | + LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK, + "trying to change cdclk frequency with cdclk not enabled\n")) + return; + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CLK_FREQ_MASK; + + switch (cdclk) { + case 450000: + val |= LCPLL_CLK_FREQ_450; + break; + case 337500: + case 540000: + val |= LCPLL_CLK_FREQ_ALT_HSW; + break; + default: + WARN(1, "invalid cdclk frequency\n"); + return; + } + + I915_WRITE(LCPLL_CTL, val); + + if (IS_HSW_ULX(dev)) { + mutex_lock(&dev_priv->rps.hw_lock); + sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, + cdclk == 337500); + mutex_unlock(&dev_priv->rps.hw_lock); + } + + intel_update_cdclk(dev); + + WARN(cdclk != dev_priv->cdclk_freq, + "cdclk requested %d kHz but got %d kHz\n", + cdclk, dev_priv->cdclk_freq); +} + +static void haswell_modeset_global_pipes(struct drm_atomic_state *state, + unsigned *prepare_pipes) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc; + int max_pixel_rate = ilk_max_pixel_rate(dev_priv); + + if (haswell_calc_cdclk(dev_priv, max_pixel_rate) == dev_priv->cdclk_freq) + return; + + /* disable/enable all currently active pipes while we change cdclk */ + for_each_intel_crtc(dev, crtc) + if (crtc->base.enabled) + *prepare_pipes |= 1 << crtc->pipe; +} + +static void haswell_modeset_global_resources(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixel_rate = ilk_max_pixel_rate(dev_priv); + int req_cdclk = haswell_calc_cdclk(dev_priv, max_pixel_rate); + + if (req_cdclk != dev_priv->cdclk_freq) { + haswell_set_cdclk(dev, req_cdclk); + } +} + static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -12221,8 +12349,11 @@ static int __intel_set_mode(struct drm_crtc *crtc, * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev)) { - ret = valleyview_modeset_global_pipes(state, &prepare_pipes); + if (IS_VALLEYVIEW(dev) || IS_HASWELL(dev)) { + if (IS_VALLEYVIEW(dev)) + valleyview_modeset_global_pipes(state, &prepare_pipes); + else + haswell_modeset_global_pipes(state, &prepare_pipes); if (ret) goto done; @@ -14256,6 +14387,9 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; + if (IS_HASWELL(dev)) + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources;