On Thu, Apr 06, 2017 at 12:15:25PM -0700, Rodrigo Vivi wrote: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > Add support for changing the cdclk frequency on CNL. Again, quite > similar to BXT, but there are some annoying differences which means > trying to share more code might not be feasible: > * PLL ratio now lives in the PLL enable register > * pcode came from SKL, not from BXT > > We support three cdclk frequencies: 168,336,528 Mhz. The first two > use the same PLL frequency, the last one uses a different one meaning > we once again may need to toggle the PLL off and on when changing > cdclk. > > v2: Rebased by Rodrigo on top of Ville's cdclk rework. > v3: Respect order of set_ bellow get_ (Ville) > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > Signed-off-by: Rodrigo Vivi <rodrigo.vivi@xxxxxxxxx> Reviewed-by: Imre Deak <imre.deak@xxxxxxxxx> > --- > drivers/gpu/drm/i915/intel_cdclk.c | 105 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 105 insertions(+) > > diff --git a/drivers/gpu/drm/i915/intel_cdclk.c b/drivers/gpu/drm/i915/intel_cdclk.c > index a4e2bd5..bee4394 100644 > --- a/drivers/gpu/drm/i915/intel_cdclk.c > +++ b/drivers/gpu/drm/i915/intel_cdclk.c > @@ -1450,6 +1450,111 @@ static void cnl_get_cdclk(struct drm_i915_private *dev_priv, > cdclk_state->cdclk = DIV_ROUND_CLOSEST(cdclk_state->vco, div); > } > > +static void cnl_cdclk_pll_disable(struct drm_i915_private *dev_priv) > +{ > + u32 val; > + > + val = I915_READ(BXT_DE_PLL_ENABLE); > + val &= ~BXT_DE_PLL_PLL_ENABLE; > + I915_WRITE(BXT_DE_PLL_ENABLE, val); > + > + /* Timeout 200us */ > + if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) == 0, 1)) > + DRM_ERROR("timout waiting for CDCLK PLL unlock\n"); > + > + dev_priv->cdclk.hw.vco = 0; > +} > + > +static void cnl_cdclk_pll_enable(struct drm_i915_private *dev_priv, int vco) > +{ > + int ratio = DIV_ROUND_CLOSEST(vco, dev_priv->cdclk.hw.ref); > + u32 val; > + > + val = CNL_CDCLK_PLL_RATIO(ratio); > + I915_WRITE(BXT_DE_PLL_ENABLE, val); > + > + val |= BXT_DE_PLL_PLL_ENABLE; > + I915_WRITE(BXT_DE_PLL_ENABLE, val); > + > + /* Timeout 200us */ > + if (wait_for((I915_READ(BXT_DE_PLL_ENABLE) & BXT_DE_PLL_LOCK) != 0, 1)) > + DRM_ERROR("timout waiting for CDCLK PLL lock\n"); > + > + dev_priv->cdclk.hw.vco = vco; > +} > + > +static void cnl_set_cdclk(struct drm_i915_private *dev_priv, > + const struct intel_cdclk_state *cdclk_state) > +{ > + int cdclk = cdclk_state->cdclk; > + int vco = cdclk_state->vco; > + u32 val, divider, pcu_ack; > + int ret; > + > + mutex_lock(&dev_priv->rps.hw_lock); > + ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL, > + SKL_CDCLK_PREPARE_FOR_CHANGE, > + SKL_CDCLK_READY_FOR_CHANGE, > + SKL_CDCLK_READY_FOR_CHANGE, 3); > + mutex_unlock(&dev_priv->rps.hw_lock); > + if (ret) { > + DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n", > + ret); > + return; > + } > + > + /* cdclk = vco / 2 / div{1,2} */ > + switch (DIV_ROUND_CLOSEST(vco, cdclk)) { > + case 4: > + divider = BXT_CDCLK_CD2X_DIV_SEL_2; > + break; > + case 2: > + divider = BXT_CDCLK_CD2X_DIV_SEL_1; > + break; > + default: > + WARN_ON(cdclk != dev_priv->cdclk.hw.ref); > + WARN_ON(vco != 0); > + > + divider = BXT_CDCLK_CD2X_DIV_SEL_1; > + break; > + } > + > + switch (cdclk) { > + case 528000: > + pcu_ack = 2; > + break; > + case 336000: > + pcu_ack = 1; > + break; > + case 168000: > + default: > + pcu_ack = 0; > + break; > + } > + > + if (dev_priv->cdclk.hw.vco != 0 && > + dev_priv->cdclk.hw.vco != vco) > + cnl_cdclk_pll_disable(dev_priv); > + > + if (dev_priv->cdclk.hw.vco != vco) > + cnl_cdclk_pll_enable(dev_priv, vco); > + > + val = divider | skl_cdclk_decimal(cdclk); > + /* > + * FIXME if only the cd2x divider needs changing, it could be done > + * without shutting off the pipe (if only one pipe is active). > + */ > + val |= BXT_CDCLK_CD2X_PIPE_NONE; > + I915_WRITE(CDCLK_CTL, val); > + > + /* inform PCU of the change */ > + mutex_lock(&dev_priv->rps.hw_lock); > + sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack); > + mutex_unlock(&dev_priv->rps.hw_lock); > + > + intel_update_cdclk(dev_priv); > +} > + > /** > * intel_cdclk_state_compare - Determine if two CDCLK states differ > * @a: first CDCLK state > -- > 1.9.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/intel-gfx _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx