Re: [PATCH 63/89] drm/i915/skl: Define shared DPLLs for Skylake

M, Satheeshakrishna
2014-10-01T10:52:09Z

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
>