[Intel-gfx] [PATCH 2/4] drm/i915: Read czclk from CCK on vlv/chv
Imre Deak
imre.deak at intel.com
Mon Sep 28 12:31:49 PDT 2015
On Thu, 2015-09-24 at 23:29 +0300, ville.syrjala at linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> 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ä <ville.syrjala at linux.intel.com>
Yep, much better to have a generic way to read out all the CCK clocks,
removes a lot of special casing. It's also true that these clocks can
change, though let's note that czclk is fixed. Looks ok to me:
Reviewed-by: Imre Deak <imre.deak at intel.com>
Below some nitpicks about naming.
> ---
> 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 2b5d587..77c9312 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 f22fb80..83218032 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 8567b46..d668897 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)
This wasn't added in this patch, but I would call it get_cck_ref or
similar. VCO is too generic and HPLL isn't accurate, since the 800MHz
clock is a bypass clock directly from iCLK.
> +{
> + 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)
I would have called it simply get_cck_clock for the above reason.
> +{
> + 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)
> {
> @@ -5749,20 +5796,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)
> {
> @@ -5983,7 +6016,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;
> @@ -6715,24 +6748,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)
> @@ -13323,8 +13340,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))
> @@ -14836,6 +14851,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 ab5ac5e..896a95c 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -5482,25 +5482,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;
> }
> @@ -7327,7 +7312,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)
> @@ -7338,7 +7323,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)
> @@ -7349,7 +7334,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)
> @@ -7360,7 +7345,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)
More information about the Intel-gfx
mailing list