From bfa7df01a092e92ae764d39fee07fc3f486ed6a9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 24 Sep 2015 23:29:18 +0300 Subject: [PATCH] drm/i915: Read czclk from CCK on vlv/chv MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit As with the cdclk, read out czclk from CCK as well. This gives us the real current value and avoids having to decode fuses and whatnot. Also store it in kHz under dev_priv like we do for cdlck since it's not just an rps related clock, and having it in kHz is more standard/convenient for some things. Imre also pointed out that we currently fail to read czclk on VLV, which means the PFI credit programming isn't working as expected. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 88 ++++++++++++++++++++++-------------- drivers/gpu/drm/i915/intel_pm.c | 25 ++-------- 4 files changed, 60 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ad37b25..4711a79 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1146,7 +1146,6 @@ struct intel_gen6_power_mgmt { u8 efficient_freq; /* AKA RPe. Pre-determined balanced frequency */ u8 rp1_freq; /* "less than" RP0 power/freqency */ u8 rp0_freq; /* Non-overclocked max frequency. */ - u32 cz_freq; u8 up_threshold; /* Current %busy required to uplock */ u8 down_threshold; /* Current %busy required to downclock */ @@ -1810,6 +1809,7 @@ struct drm_i915_private { unsigned int cdclk_freq, max_cdclk_freq; unsigned int max_dotclk_freq; unsigned int hpll_freq; + unsigned int czclk_freq; /** * wq - Driver workqueue for GEM. diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index aca25bf..3709d6b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -728,6 +728,7 @@ enum skl_disp_power_wells { #define DSI_PLL_N1_DIV_MASK (3 << 16) #define DSI_PLL_M1_DIV_SHIFT 0 #define DSI_PLL_M1_DIV_MASK (0x1ff << 0) +#define CCK_CZ_CLOCK_CONTROL 0x62 #define CCK_DISPLAY_CLOCK_CONTROL 0x6b #define CCK_TRUNK_FORCE_ON (1 << 17) #define CCK_TRUNK_FORCE_OFF (1 << 16) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36591e3..797b882 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -132,6 +132,42 @@ struct intel_limit { intel_p2_t p2; }; +/* returns HPLL frequency in kHz */ +static int valleyview_get_vco(struct drm_i915_private *dev_priv) +{ + int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; + + /* Obtain SKU information */ + mutex_lock(&dev_priv->sb_lock); + hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & + CCK_FUSE_HPLL_FREQ_MASK; + mutex_unlock(&dev_priv->sb_lock); + + return vco_freq[hpll_freq] * 1000; +} + +static int vlv_get_cck_clock_hpll(struct drm_i915_private *dev_priv, + const char *name, u32 reg) +{ + u32 val; + int divider; + + if (dev_priv->hpll_freq == 0) + dev_priv->hpll_freq = valleyview_get_vco(dev_priv); + + mutex_lock(&dev_priv->sb_lock); + val = vlv_cck_read(dev_priv, reg); + mutex_unlock(&dev_priv->sb_lock); + + divider = val & CCK_FREQUENCY_VALUES; + + WARN((val & CCK_FREQUENCY_STATUS) != + (divider << CCK_FREQUENCY_STATUS_SHIFT), + "%s change in progress\n", name); + + return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); +} + int intel_pch_rawclk(struct drm_device *dev) { @@ -175,6 +211,17 @@ int intel_hrawclk(struct drm_device *dev) } } +static void intel_update_czclk(struct drm_i915_private *dev_priv) +{ + if (!IS_VALLEYVIEW(dev_priv)) + return; + + dev_priv->czclk_freq = vlv_get_cck_clock_hpll(dev_priv, "czclk", + CCK_CZ_CLOCK_CONTROL); + + DRM_DEBUG_DRIVER("CZ clock rate: %d kHz\n", dev_priv->czclk_freq); +} + static inline u32 /* units of 100MHz */ intel_fdi_link_freq(struct drm_device *dev) { @@ -5756,20 +5803,6 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) DRM_ERROR("DBuf power enable timeout\n"); } -/* returns HPLL frequency in kHz */ -static int valleyview_get_vco(struct drm_i915_private *dev_priv) -{ - int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 }; - - /* Obtain SKU information */ - mutex_lock(&dev_priv->sb_lock); - hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) & - CCK_FUSE_HPLL_FREQ_MASK; - mutex_unlock(&dev_priv->sb_lock); - - return vco_freq[hpll_freq] * 1000; -} - /* Adjust CDclk dividers to allow high res or save power if possible */ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) { @@ -5990,7 +6023,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) else default_credits = PFI_CREDIT(8); - if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) { + if (dev_priv->cdclk_freq >= dev_priv->czclk_freq) { /* CHV suggested value is 31 or 63 */ if (IS_CHERRYVIEW(dev_priv)) credits = PFI_CREDIT_63; @@ -6722,24 +6755,8 @@ static int haswell_get_display_clock_speed(struct drm_device *dev) static int valleyview_get_display_clock_speed(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - int divider; - - if (dev_priv->hpll_freq == 0) - dev_priv->hpll_freq = valleyview_get_vco(dev_priv); - - mutex_lock(&dev_priv->sb_lock); - val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL); - mutex_unlock(&dev_priv->sb_lock); - - divider = val & CCK_FREQUENCY_VALUES; - - WARN((val & CCK_FREQUENCY_STATUS) != - (divider << CCK_FREQUENCY_STATUS_SHIFT), - "cdclk change in progress\n"); - - return DIV_ROUND_CLOSEST(dev_priv->hpll_freq << 1, divider + 1); + return vlv_get_cck_clock_hpll(to_i915(dev), "cdclk", + CCK_DISPLAY_CLOCK_CONTROL); } static int ilk_get_display_clock_speed(struct drm_device *dev) @@ -13329,8 +13346,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - intel_update_cdclk(dev); - if (HAS_DDI(dev)) intel_ddi_pll_init(dev); else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) @@ -14839,6 +14854,9 @@ void intel_modeset_init(struct drm_device *dev) } } + intel_update_czclk(dev_priv); + intel_update_cdclk(dev); + intel_shared_dpll_init(dev); /* Just disable it once at startup */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 780b1e0..9643a7c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5460,25 +5460,10 @@ static void cherryview_init_gt_powersave(struct drm_device *dev) mutex_unlock(&dev_priv->sb_lock); switch ((val >> 2) & 0x7) { - case 0: - case 1: - dev_priv->rps.cz_freq = 200; - dev_priv->mem_freq = 1600; - break; - case 2: - dev_priv->rps.cz_freq = 267; - dev_priv->mem_freq = 1600; - break; case 3: - dev_priv->rps.cz_freq = 333; dev_priv->mem_freq = 2000; break; - case 4: - dev_priv->rps.cz_freq = 320; - dev_priv->mem_freq = 1600; - break; - case 5: - dev_priv->rps.cz_freq = 400; + default: dev_priv->mem_freq = 1600; break; } @@ -7305,7 +7290,7 @@ static int vlv_gpu_freq_div(unsigned int czclk_freq) static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) { - int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4); + int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); div = vlv_gpu_freq_div(czclk_freq); if (div < 0) @@ -7316,7 +7301,7 @@ static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val) { - int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->mem_freq, 4); + int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); mul = vlv_gpu_freq_div(czclk_freq); if (mul < 0) @@ -7327,7 +7312,7 @@ static int byt_freq_opcode(struct drm_i915_private *dev_priv, int val) static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val) { - int div, czclk_freq = dev_priv->rps.cz_freq; + int div, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); div = vlv_gpu_freq_div(czclk_freq) / 2; if (div < 0) @@ -7338,7 +7323,7 @@ static int chv_gpu_freq(struct drm_i915_private *dev_priv, int val) static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val) { - int mul, czclk_freq = dev_priv->rps.cz_freq; + int mul, czclk_freq = DIV_ROUND_CLOSEST(dev_priv->czclk_freq, 1000); mul = vlv_gpu_freq_div(czclk_freq) / 2; if (mul < 0) -- 2.7.4