Message ID | 1409830075-11139-64-git-send-email-damien.lespiau@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
2014-09-04 8:27 GMT-03:00 Damien Lespiau <damien.lespiau@intel.com>: > From: Satheeshakrishna M <satheeshakrishna.m@intel.com> > > On skylake, DPLL 1, 2 and 3 can be used for DP and HDMI. The shared dpll > framework allows us to share those DPLLs among DDIs when possible. > > The most tricky part is to provide a DPLL state that can be easily > compared. DPLL_CRTL1 is shared by all the DPLLs, 6 bits each. The > per-dpll crtl1 field of the hw state is then normalized to be the same > value if 2 DPLLs do indeed have identical values for those 6 bits. > > v2: Port the code to the shared DPLL infrastructure (Damien) > > XXX: This patch would benefit from a bunchf of macros for handling ctrl1 > to encapsulate the masking and shifting (Daniel) Are you planning to do the XXX above before merging? The only suspect thing is that the spec doesn't mention if/when/how-much we need to sleep after enabling the clocks... I hope this won't be a problem later :) Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> > > Signed-off-by: Satheeshakrishna M <satheeshakrishna.m@intel.com> (v1) > Signed-off-by: Damien Lespiau <damien.lespiau@intel.com> > --- > drivers/gpu/drm/i915/i915_drv.h | 11 ++++ > drivers/gpu/drm/i915/intel_ddi.c | 126 ++++++++++++++++++++++++++++++++++++++- > 2 files changed, 136 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 65e5ffb..a6e14db 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -225,6 +225,17 @@ struct intel_dpll_hw_state { > > /* hsw, bdw */ > uint32_t wrpll; > + > + /* skl */ > + /* > + * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in > + * lower part of crtl1 and they get shifted into position when writing > + * the register. This allows us to easily compare the state to share > + * the DPLL. > + */ > + uint32_t ctrl1; > + /* HDMI only, 0 when used for DP */ > + uint32_t cfgcr1, cfgcr2; > }; > > struct intel_shared_dpll { > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > index b5cfb07..53ac23d 100644 > --- a/drivers/gpu/drm/i915/intel_ddi.c > +++ b/drivers/gpu/drm/i915/intel_ddi.c > @@ -1522,12 +1522,136 @@ static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) > } > } > > +static const char * const skl_ddi_pll_names[] = { > + "DPLL 1", > + "DPLL 2", > + "DPLL 3", > +}; > + > +struct skl_dpll_regs { > + u32 ctl, cfgcr1, cfgcr2; > +}; > + > +/* this array is indexed by the *shared* pll id */ > +static const struct skl_dpll_regs skl_dpll_regs[3] = { > + { > + /* DPLL 1 */ > + .ctl = LCPLL2_CTL, > + .cfgcr1 = DPLL1_CFGCR1, > + .cfgcr2 = DPLL1_CFGCR2, > + }, > + { > + /* DPLL 2 */ > + .ctl = WRPLL_CTL1, > + .cfgcr1 = DPLL2_CFGCR1, > + .cfgcr2 = DPLL2_CFGCR2, > + }, > + { > + /* DPLL 3 */ > + .ctl = WRPLL_CTL2, > + .cfgcr1 = DPLL3_CFGCR1, > + .cfgcr2 = DPLL3_CFGCR2, > + }, > +}; > + > +static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, > + struct intel_shared_dpll *pll) > +{ > + uint32_t val; > + unsigned int dpll; > + const struct skl_dpll_regs *regs = skl_dpll_regs; > + > + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ > + dpll = pll->id + 1; > + > + val = I915_READ(DPLL_CTRL1); > + > + val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | > + DPLL_CRTL1_LINK_RATE_MASK(dpll)); > + val |= pll->hw_state.ctrl1 << (dpll * 6); > + > + I915_WRITE(DPLL_CTRL1, val); > + POSTING_READ(DPLL_CTRL1); > + > + I915_WRITE(regs[pll->id].cfgcr1, pll->hw_state.cfgcr1); > + I915_WRITE(regs[pll->id].cfgcr2, pll->hw_state.cfgcr2); > + POSTING_READ(regs[pll->id].cfgcr1); > + POSTING_READ(regs[pll->id].cfgcr2); > + > + /* the enable bit is always bit 31 */ > + I915_WRITE(regs[pll->id].ctl, > + I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE); > + > + if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5)) > + DRM_ERROR("DPLL %d not locked\n", dpll); > +} > + > +static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, > + struct intel_shared_dpll *pll) > +{ > + const struct skl_dpll_regs *regs = skl_dpll_regs; > + > + /* the enable bit is always bit 31 */ > + I915_WRITE(regs[pll->id].ctl, > + I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE); > + POSTING_READ(regs[pll->id].ctl); > +} > + > +static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, > + struct intel_shared_dpll *pll, > + struct intel_dpll_hw_state *hw_state) > +{ > + uint32_t val; > + unsigned int dpll; > + const struct skl_dpll_regs *regs = skl_dpll_regs; > + > + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS)) > + return false; > + > + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ > + dpll = pll->id + 1; > + > + val = I915_READ(regs[pll->id].ctl); > + if (!(val & LCPLL_PLL_ENABLE)) > + return false; > + > + val = I915_READ(DPLL_CTRL1); > + hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f; > + > + /* avoid reading back stale values if HDMI mode is not enabled */ > + if (val & DPLL_CTRL1_HDMI_MODE(dpll)) { > + hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1); > + hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); > + } > + > + return true; > +} > + > +static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) > +{ > + int i; > + > + dev_priv->num_shared_dpll = 3; > + > + for (i = 0; i < dev_priv->num_shared_dpll; i++) { > + dev_priv->shared_dplls[i].id = i; > + dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i]; > + dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable; > + dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable; > + dev_priv->shared_dplls[i].get_hw_state = > + skl_ddi_pll_get_hw_state; > + } > +} > + > void intel_ddi_pll_init(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > uint32_t val = I915_READ(LCPLL_CTL); > > - hsw_shared_dplls_init(dev_priv); > + if (IS_SKYLAKE(dev)) > + skl_shared_dplls_init(dev_priv); > + else > + hsw_shared_dplls_init(dev_priv); > > DRM_DEBUG_KMS("CDCLK running at %dKHz\n", > intel_ddi_get_cdclk_freq(dev_priv)); > -- > 1.8.3.1 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
On 9/23/2014 7:58 PM, Paulo Zanoni wrote: > 2014-09-04 8:27 GMT-03:00 Damien Lespiau<damien.lespiau@intel.com>: >> From: Satheeshakrishna M<satheeshakrishna.m@intel.com> >> >> On skylake, DPLL 1, 2 and 3 can be used for DP and HDMI. The shared dpll >> framework allows us to share those DPLLs among DDIs when possible. >> >> The most tricky part is to provide a DPLL state that can be easily >> compared. DPLL_CRTL1 is shared by all the DPLLs, 6 bits each. The >> per-dpll crtl1 field of the hw state is then normalized to be the same >> value if 2 DPLLs do indeed have identical values for those 6 bits. >> >> v2: Port the code to the shared DPLL infrastructure (Damien) >> >> XXX: This patch would benefit from a bunchf of macros for handling ctrl1 >> to encapsulate the masking and shifting (Daniel) > Are you planning to do the XXX above before merging? > > The only suspect thing is that the spec doesn't mention > if/when/how-much we need to sleep after enabling the clocks... I hope > this won't be a problem later :) We added a very conservative number, so shouldn't be a problem. > Reviewed-by: Paulo Zanoni<paulo.r.zanoni@intel.com> > >> Signed-off-by: Satheeshakrishna M<satheeshakrishna.m@intel.com> (v1) >> Signed-off-by: Damien Lespiau<damien.lespiau@intel.com> >> --- >> drivers/gpu/drm/i915/i915_drv.h | 11 ++++ >> drivers/gpu/drm/i915/intel_ddi.c | 126 ++++++++++++++++++++++++++++++++++++++- >> 2 files changed, 136 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h >> index 65e5ffb..a6e14db 100644 >> --- a/drivers/gpu/drm/i915/i915_drv.h >> +++ b/drivers/gpu/drm/i915/i915_drv.h >> @@ -225,6 +225,17 @@ struct intel_dpll_hw_state { >> >> /* hsw, bdw */ >> uint32_t wrpll; >> + >> + /* skl */ >> + /* >> + * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in >> + * lower part of crtl1 and they get shifted into position when writing >> + * the register. This allows us to easily compare the state to share >> + * the DPLL. >> + */ >> + uint32_t ctrl1; >> + /* HDMI only, 0 when used for DP */ >> + uint32_t cfgcr1, cfgcr2; >> }; >> >> struct intel_shared_dpll { >> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c >> index b5cfb07..53ac23d 100644 >> --- a/drivers/gpu/drm/i915/intel_ddi.c >> +++ b/drivers/gpu/drm/i915/intel_ddi.c >> @@ -1522,12 +1522,136 @@ static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) >> } >> } >> >> +static const char * const skl_ddi_pll_names[] = { >> + "DPLL 1", >> + "DPLL 2", >> + "DPLL 3", >> +}; >> + >> +struct skl_dpll_regs { >> + u32 ctl, cfgcr1, cfgcr2; >> +}; >> + >> +/* this array is indexed by the *shared* pll id */ >> +static const struct skl_dpll_regs skl_dpll_regs[3] = { >> + { >> + /* DPLL 1 */ >> + .ctl = LCPLL2_CTL, >> + .cfgcr1 = DPLL1_CFGCR1, >> + .cfgcr2 = DPLL1_CFGCR2, >> + }, >> + { >> + /* DPLL 2 */ >> + .ctl = WRPLL_CTL1, >> + .cfgcr1 = DPLL2_CFGCR1, >> + .cfgcr2 = DPLL2_CFGCR2, >> + }, >> + { >> + /* DPLL 3 */ >> + .ctl = WRPLL_CTL2, >> + .cfgcr1 = DPLL3_CFGCR1, >> + .cfgcr2 = DPLL3_CFGCR2, >> + }, >> +}; >> + >> +static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, >> + struct intel_shared_dpll *pll) >> +{ >> + uint32_t val; >> + unsigned int dpll; >> + const struct skl_dpll_regs *regs = skl_dpll_regs; >> + >> + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ >> + dpll = pll->id + 1; >> + >> + val = I915_READ(DPLL_CTRL1); >> + >> + val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | >> + DPLL_CRTL1_LINK_RATE_MASK(dpll)); >> + val |= pll->hw_state.ctrl1 << (dpll * 6); >> + >> + I915_WRITE(DPLL_CTRL1, val); >> + POSTING_READ(DPLL_CTRL1); >> + >> + I915_WRITE(regs[pll->id].cfgcr1, pll->hw_state.cfgcr1); >> + I915_WRITE(regs[pll->id].cfgcr2, pll->hw_state.cfgcr2); >> + POSTING_READ(regs[pll->id].cfgcr1); >> + POSTING_READ(regs[pll->id].cfgcr2); >> + >> + /* the enable bit is always bit 31 */ >> + I915_WRITE(regs[pll->id].ctl, >> + I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE); >> + >> + if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5)) >> + DRM_ERROR("DPLL %d not locked\n", dpll); >> +} >> + >> +static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, >> + struct intel_shared_dpll *pll) >> +{ >> + const struct skl_dpll_regs *regs = skl_dpll_regs; >> + >> + /* the enable bit is always bit 31 */ >> + I915_WRITE(regs[pll->id].ctl, >> + I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE); >> + POSTING_READ(regs[pll->id].ctl); >> +} >> + >> +static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, >> + struct intel_shared_dpll *pll, >> + struct intel_dpll_hw_state *hw_state) >> +{ >> + uint32_t val; >> + unsigned int dpll; >> + const struct skl_dpll_regs *regs = skl_dpll_regs; >> + >> + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS)) >> + return false; >> + >> + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ >> + dpll = pll->id + 1; >> + >> + val = I915_READ(regs[pll->id].ctl); >> + if (!(val & LCPLL_PLL_ENABLE)) >> + return false; >> + >> + val = I915_READ(DPLL_CTRL1); >> + hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f; >> + >> + /* avoid reading back stale values if HDMI mode is not enabled */ >> + if (val & DPLL_CTRL1_HDMI_MODE(dpll)) { >> + hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1); >> + hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); >> + } >> + >> + return true; >> +} >> + >> +static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) >> +{ >> + int i; >> + >> + dev_priv->num_shared_dpll = 3; >> + >> + for (i = 0; i < dev_priv->num_shared_dpll; i++) { >> + dev_priv->shared_dplls[i].id = i; >> + dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i]; >> + dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable; >> + dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable; >> + dev_priv->shared_dplls[i].get_hw_state = >> + skl_ddi_pll_get_hw_state; >> + } >> +} >> + >> void intel_ddi_pll_init(struct drm_device *dev) >> { >> struct drm_i915_private *dev_priv = dev->dev_private; >> uint32_t val = I915_READ(LCPLL_CTL); >> >> - hsw_shared_dplls_init(dev_priv); >> + if (IS_SKYLAKE(dev)) >> + skl_shared_dplls_init(dev_priv); >> + else >> + hsw_shared_dplls_init(dev_priv); >> >> DRM_DEBUG_KMS("CDCLK running at %dKHz\n", >> intel_ddi_get_cdclk_freq(dev_priv)); >> -- >> 1.8.3.1 >> >> _______________________________________________ >> Intel-gfx mailing list >> Intel-gfx@lists.freedesktop.org >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx >
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 65e5ffb..a6e14db 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -225,6 +225,17 @@ struct intel_dpll_hw_state { /* hsw, bdw */ uint32_t wrpll; + + /* skl */ + /* + * DPLL_CTRL1 has 6 bits for each each this DPLL. We store those in + * lower part of crtl1 and they get shifted into position when writing + * the register. This allows us to easily compare the state to share + * the DPLL. + */ + uint32_t ctrl1; + /* HDMI only, 0 when used for DP */ + uint32_t cfgcr1, cfgcr2; }; struct intel_shared_dpll { diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b5cfb07..53ac23d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1522,12 +1522,136 @@ static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv) } } +static const char * const skl_ddi_pll_names[] = { + "DPLL 1", + "DPLL 2", + "DPLL 3", +}; + +struct skl_dpll_regs { + u32 ctl, cfgcr1, cfgcr2; +}; + +/* this array is indexed by the *shared* pll id */ +static const struct skl_dpll_regs skl_dpll_regs[3] = { + { + /* DPLL 1 */ + .ctl = LCPLL2_CTL, + .cfgcr1 = DPLL1_CFGCR1, + .cfgcr2 = DPLL1_CFGCR2, + }, + { + /* DPLL 2 */ + .ctl = WRPLL_CTL1, + .cfgcr1 = DPLL2_CFGCR1, + .cfgcr2 = DPLL2_CFGCR2, + }, + { + /* DPLL 3 */ + .ctl = WRPLL_CTL2, + .cfgcr1 = DPLL3_CFGCR1, + .cfgcr2 = DPLL3_CFGCR2, + }, +}; + +static void skl_ddi_pll_enable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + uint32_t val; + unsigned int dpll; + const struct skl_dpll_regs *regs = skl_dpll_regs; + + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ + dpll = pll->id + 1; + + val = I915_READ(DPLL_CTRL1); + + val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | + DPLL_CRTL1_LINK_RATE_MASK(dpll)); + val |= pll->hw_state.ctrl1 << (dpll * 6); + + I915_WRITE(DPLL_CTRL1, val); + POSTING_READ(DPLL_CTRL1); + + I915_WRITE(regs[pll->id].cfgcr1, pll->hw_state.cfgcr1); + I915_WRITE(regs[pll->id].cfgcr2, pll->hw_state.cfgcr2); + POSTING_READ(regs[pll->id].cfgcr1); + POSTING_READ(regs[pll->id].cfgcr2); + + /* the enable bit is always bit 31 */ + I915_WRITE(regs[pll->id].ctl, + I915_READ(regs[pll->id].ctl) | LCPLL_PLL_ENABLE); + + if (wait_for(I915_READ(DPLL_STATUS) & DPLL_LOCK(dpll), 5)) + DRM_ERROR("DPLL %d not locked\n", dpll); +} + +static void skl_ddi_pll_disable(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll) +{ + const struct skl_dpll_regs *regs = skl_dpll_regs; + + /* the enable bit is always bit 31 */ + I915_WRITE(regs[pll->id].ctl, + I915_READ(regs[pll->id].ctl) & ~LCPLL_PLL_ENABLE); + POSTING_READ(regs[pll->id].ctl); +} + +static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll *pll, + struct intel_dpll_hw_state *hw_state) +{ + uint32_t val; + unsigned int dpll; + const struct skl_dpll_regs *regs = skl_dpll_regs; + + if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_PLLS)) + return false; + + /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ + dpll = pll->id + 1; + + val = I915_READ(regs[pll->id].ctl); + if (!(val & LCPLL_PLL_ENABLE)) + return false; + + val = I915_READ(DPLL_CTRL1); + hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f; + + /* avoid reading back stale values if HDMI mode is not enabled */ + if (val & DPLL_CTRL1_HDMI_MODE(dpll)) { + hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1); + hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); + } + + return true; +} + +static void skl_shared_dplls_init(struct drm_i915_private *dev_priv) +{ + int i; + + dev_priv->num_shared_dpll = 3; + + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + dev_priv->shared_dplls[i].id = i; + dev_priv->shared_dplls[i].name = skl_ddi_pll_names[i]; + dev_priv->shared_dplls[i].disable = skl_ddi_pll_disable; + dev_priv->shared_dplls[i].enable = skl_ddi_pll_enable; + dev_priv->shared_dplls[i].get_hw_state = + skl_ddi_pll_get_hw_state; + } +} + void intel_ddi_pll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t val = I915_READ(LCPLL_CTL); - hsw_shared_dplls_init(dev_priv); + if (IS_SKYLAKE(dev)) + skl_shared_dplls_init(dev_priv); + else + hsw_shared_dplls_init(dev_priv); DRM_DEBUG_KMS("CDCLK running at %dKHz\n", intel_ddi_get_cdclk_freq(dev_priv));