[Intel-gfx] [PATCH 07/13] drm/i915/cnl: DVFS for PLL enabling

Ville Syrjälä ville.syrjala at linux.intel.com
Tue Oct 17 20:36:14 UTC 2017


On Tue, Oct 17, 2017 at 09:02:05PM +0300, Ville Syrjälä wrote:
> On Tue, Oct 17, 2017 at 10:45:22AM -0700, Rodrigo Vivi wrote:
> > On Tue, Oct 17, 2017 at 05:23:20PM +0000, Ville Syrjälä wrote:
> > > On Tue, Oct 17, 2017 at 09:47:05AM -0700, Rodrigo Vivi wrote:
> > > > On Tue, Oct 17, 2017 at 03:44:21PM +0000, Ville Syrjälä wrote:
> > > > > On Tue, Oct 03, 2017 at 12:06:08AM -0700, Rodrigo Vivi wrote:
> > > > > > From: "Kahola, Mika" <mika.kahola at intel.com>
> > > > > > 
> > > > > > Display Voltage and Frequency Switching (DVFS) is used to adjust the
> > > > > > display voltage to match the display clock frequencies. If voltage is
> > > > > > set too low, it will break functionality. If voltage is set too high,
> > > > > > it will waste power. Voltage level is selected based on CD clock and
> > > > > > DDI clock.
> > > > > > 
> > > > > > The sequence before frequency change is the following and it requests
> > > > > > the power controller to raise voltage to maximum
> > > > > > 
> > > > > > - Ensure any previous GT Driver Mailbox transaction is complete.
> > > > > > - Write GT Driver Mailbox Data Low = 0x3.
> > > > > > - Write GT Driver Mailbox Data High = 0x0.
> > > > > > - Write GT Driver Mailbox Interface = 0x80000007.
> > > > > > - Poll GT Driver Mailbox Interface for Run/Busy indication cleared (bit 31 = 0).
> > > > > > - Read GT Driver Mailbox Data Low, if bit 0 is 0x1, continue, else restart the sequence.
> > > > > >   Timeout after 3ms
> > > > > > 
> > > > > > The sequence after frequency change is the following and it requests
> > > > > > the port controller to raise voltage to the requested level.
> > > > > > 
> > > > > > - Write GT Driver Mailbox Data Low
> > > > > >  * For level 0, write 0x0
> > > > > >  * For level 1, write 0x1
> > > > > >  * For level 2, write 0x2
> > > > > >  * For level 3, write 0x3
> > > > > >    - Write GT Driver Mailbox Data High = 0x0.
> > > > > >    - Write GT Driver Mailbox Interface = 0x80000007.
> > > > > > 
> > > > > > For Cannonlake, the level 3 is not used and it aliases to level 2.
> > > > > > 
> > > > > > v2: reuse Paulo's work on cdclk. This patch depends on Paulo's patch
> > > > > >     [PATCH 02/12] drm/i915/cnl: extract cnl_dvfs_{pre,post}_change
> > > > > > v3: (By Rodrigo): Remove duplicated commend and fix typo on Paulo's name.
> > > > > > v4: (By Rodrigo): Rebase on top "Unify and export gen9+ port_clock calculation"
> > > > > >     The port clock calculation here was only addressing DP, so let's reuse
> > > > > >     the current port calculation that is already in place without any duplication.
> > > > > >     Alos fix portclk <= 594000 instead of portclk < 594000.
> > > > > > 
> > > > > > Cc: Paulo Zanoni <paulo.r.zanoni at intel.com>
> > > > > > Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
> > > > > > Signed-off-by: Kahola, Mika <mika.kahola at intel.com>
> > > > > > Signed-off-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 30 ++++++++++++++++++++++--------
> > > > > >  1 file changed, 22 insertions(+), 8 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > > > > > index a2a3d93d67bd..6030fbafa580 100644
> > > > > > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > > > > > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > > > > > @@ -1966,10 +1966,23 @@ static const struct intel_dpll_mgr bxt_pll_mgr = {
> > > > > >  	.dump_hw_state = bxt_dump_hw_state,
> > > > > >  };
> > > > > >  
> > > > > > +static int cnl_get_dvfs_level(int cdclk, int portclk)
> > > > > > +{
> > > > > > +	if (cdclk == 168000 && portclk <= 594000)
> > > > > > +		return 0;
> > > > > > +	else if (cdclk == 336000 && portclk <= 594000)
> > > > > > +		return 1;
> > > > > > +	else
> > > > > > +		return 2;
> > > > > > +}
> > > > > > +
> > > > > >  static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv,
> > > > > >  			       struct intel_shared_dpll *pll)
> > > > > >  {
> > > > > >  	uint32_t val;
> > > > > > +	int ret;
> > > > > > +	int level;
> > > > > > +	int cdclk, portclk;
> > > > > >  
> > > > > >  	/* 1. Enable DPLL power in DPLL_ENABLE. */
> > > > > >  	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
> > > > > > @@ -2006,11 +2019,9 @@ static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv,
> > > > > >  	/*
> > > > > >  	 * 5. If the frequency will result in a change to the voltage
> > > > > >  	 * requirement, follow the Display Voltage Frequency Switching
> > > > > > -	 * Sequence Before Frequency Change
> > > > > > -	 *
> > > > > > -	 * FIXME: (DVFS) is used to adjust the display voltage to match the
> > > > > > -	 * display clock frequencies
> > > > > > +	 * (DVFS) Sequence Before Frequency Change
> > > > > >  	 */
> > > > > > +	ret = cnl_dvfs_pre_change(dev_priv);
> > > > > >  
> > > > > >  	/* 6. Enable DPLL in DPLL_ENABLE. */
> > > > > >  	val = I915_READ(CNL_DPLL_ENABLE(pll->id));
> > > > > > @@ -2028,11 +2039,14 @@ static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv,
> > > > > >  	/*
> > > > > >  	 * 8. If the frequency will result in a change to the voltage
> > > > > >  	 * requirement, follow the Display Voltage Frequency Switching
> > > > > > -	 * Sequence After Frequency Change
> > > > > > -	 *
> > > > > > -	 * FIXME: (DVFS) is used to adjust the display voltage to match the
> > > > > > -	 * display clock frequencies
> > > > > > +	 * (DVFS) Sequence After Frequency Change
> > > > > >  	 */
> > > > > > +	if (ret == 0) {
> > > > > > +		cdclk = dev_priv->cdclk.hw.cdclk;
> > > > > > +		portclk = intel_ddi_port_clock(dev_priv, pll->id);
> > > > > > +		level = cnl_get_dvfs_level(cdclk, portclk);
> > > > > > +		cnl_dvfs_post_change(dev_priv, level);
> > > > > 
> > > > > This isn't how I imagined we'd handle this. What I was after is
> > > > > pre-computing the correct "dfvfs level" (or what I'd probably just call
> > > > > "voltage" or something like that), and then we'd just let the normal
> > > > > cdclk programming sequence do its thing.
> > > > > 
> > > > > Is it even safe to do this with other pipes/ports enabled? I would
> > > > > have assumed no, but maybe I'm mistaken?
> > > > 
> > > > Well, this is how the spec is written. So I assume it is safe to change
> > > > that at that point.
> > > > 
> > > > Also we enable CDCLK during boot while we have no way to compute the
> > > > link rate. So I don't see a better way of hadling that.
> > > 
> > > We do a full state readout, which should tell us what voltage we need.
> > > And if the cdclk isn't even enabled, then obviously we can't have any
> > > pipes running either, so we can safely enable it with any frequency
> > > even before the full state readout.
> > > 
> > > > So, Art is it ok in the way that I'm proposing here:
> > > > 
> > > > on core display init:
> > > > 
> > > > - dvfs-pre;
> > > > - enable cdclk;
> > > > - dvfs-post considering cdclk only and link rate 0; 
> > > > 
> > > > on pll init:
> > > > 
> > > > - consider cdclk and link rate and if desired level is different from what is currently set: dvfs-pre
> > > > - enable pll
> > > > - consider cdclk and link rate and if desired level is different from what is currently set: dvfs-post with new level.
> > > > 
> > > > This is how I read the spec, but please let me know what I'm missing.
> > > 
> > > Hmm. OK, so maybe we can change the voltage while things are up and
> > > running.
> > > 
> > > That said, the voltage level is a global thing, so whenever we change it
> > > we must consider the state of all ports, and the cdclk. This looks like
> > > it only considers the current port. Thus if we first enable a port that
> > > needs high voltage, and later a port that can make due with a lower
> > > voltage we'll end up with something not working.
> > 
> > ouch! this is true! So, what link rate should we consider on that dvfs spec?
> > so, always the highest avaiblable at that time?
> 
> Yes.
> 
> > 
> > So we cache somewhere the highest on atomic check? and then during
> > these dvfs sequences we just check for the highest?
> 
> IIRC I pastebinned a sketch for this at some point. Hmm. Found it, and
> pushed it here:
> git://github.com/vsyrjala/linux.git dvfs_voltage_2
> 
> I tried to also pimp it a little bit to not force a modeset on all
> pipes if just the voltage changes.
> 
> I *think* this should work, after someone fills out the code for
> DDI .compute_config() and .get_config(). But totally untested of course
> so YMMV.

Except I forgot about the lack of a pcode command to read out the current
voltage setting :( So I had to add some extra kludges to the state readout 
on top. Branch updated.

-- 
Ville Syrjälä
Intel OTC


More information about the Intel-gfx mailing list