Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2021 Intel Corporation
0004  */
0005 
0006 #include "intel_de.h"
0007 #include "intel_display_types.h"
0008 #include "intel_panel.h"
0009 #include "intel_pch_refclk.h"
0010 #include "intel_sbi.h"
0011 
0012 static void lpt_fdi_reset_mphy(struct drm_i915_private *dev_priv)
0013 {
0014     u32 tmp;
0015 
0016     tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
0017     tmp |= FDI_MPHY_IOSFSB_RESET_CTL;
0018     intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
0019 
0020     if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &
0021             FDI_MPHY_IOSFSB_RESET_STATUS, 100))
0022         drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");
0023 
0024     tmp = intel_de_read(dev_priv, SOUTH_CHICKEN2);
0025     tmp &= ~FDI_MPHY_IOSFSB_RESET_CTL;
0026     intel_de_write(dev_priv, SOUTH_CHICKEN2, tmp);
0027 
0028     if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &
0029              FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))
0030         drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");
0031 }
0032 
0033 /* WaMPhyProgramming:hsw */
0034 static void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv)
0035 {
0036     u32 tmp;
0037 
0038     lpt_fdi_reset_mphy(dev_priv);
0039 
0040     tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);
0041     tmp &= ~(0xFF << 24);
0042     tmp |= (0x12 << 24);
0043     intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);
0044 
0045     tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);
0046     tmp |= (1 << 11);
0047     intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);
0048 
0049     tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);
0050     tmp |= (1 << 11);
0051     intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);
0052 
0053     tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);
0054     tmp |= (1 << 24) | (1 << 21) | (1 << 18);
0055     intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);
0056 
0057     tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);
0058     tmp |= (1 << 24) | (1 << 21) | (1 << 18);
0059     intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);
0060 
0061     tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);
0062     tmp &= ~(7 << 13);
0063     tmp |= (5 << 13);
0064     intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);
0065 
0066     tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);
0067     tmp &= ~(7 << 13);
0068     tmp |= (5 << 13);
0069     intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);
0070 
0071     tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);
0072     tmp &= ~0xFF;
0073     tmp |= 0x1C;
0074     intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);
0075 
0076     tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);
0077     tmp &= ~0xFF;
0078     tmp |= 0x1C;
0079     intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);
0080 
0081     tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);
0082     tmp &= ~(0xFF << 16);
0083     tmp |= (0x1C << 16);
0084     intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);
0085 
0086     tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);
0087     tmp &= ~(0xFF << 16);
0088     tmp |= (0x1C << 16);
0089     intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);
0090 
0091     tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);
0092     tmp |= (1 << 27);
0093     intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);
0094 
0095     tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);
0096     tmp |= (1 << 27);
0097     intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);
0098 
0099     tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);
0100     tmp &= ~(0xF << 28);
0101     tmp |= (4 << 28);
0102     intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);
0103 
0104     tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);
0105     tmp &= ~(0xF << 28);
0106     tmp |= (4 << 28);
0107     intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);
0108 }
0109 
0110 void lpt_disable_iclkip(struct drm_i915_private *dev_priv)
0111 {
0112     u32 temp;
0113 
0114     intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_GATE);
0115 
0116     mutex_lock(&dev_priv->sb_lock);
0117 
0118     temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
0119     temp |= SBI_SSCCTL_DISABLE;
0120     intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
0121 
0122     mutex_unlock(&dev_priv->sb_lock);
0123 }
0124 
0125 struct iclkip_params {
0126     u32 iclk_virtual_root_freq;
0127     u32 iclk_pi_range;
0128     u32 divsel, phaseinc, auxdiv, phasedir, desired_divisor;
0129 };
0130 
0131 static void iclkip_params_init(struct iclkip_params *p)
0132 {
0133     memset(p, 0, sizeof(*p));
0134 
0135     p->iclk_virtual_root_freq = 172800 * 1000;
0136     p->iclk_pi_range = 64;
0137 }
0138 
0139 static int lpt_iclkip_freq(struct iclkip_params *p)
0140 {
0141     return DIV_ROUND_CLOSEST(p->iclk_virtual_root_freq,
0142                  p->desired_divisor << p->auxdiv);
0143 }
0144 
0145 static void lpt_compute_iclkip(struct iclkip_params *p, int clock)
0146 {
0147     iclkip_params_init(p);
0148 
0149     /* The iCLK virtual clock root frequency is in MHz,
0150      * but the adjusted_mode->crtc_clock in KHz. To get the
0151      * divisors, it is necessary to divide one by another, so we
0152      * convert the virtual clock precision to KHz here for higher
0153      * precision.
0154      */
0155     for (p->auxdiv = 0; p->auxdiv < 2; p->auxdiv++) {
0156         p->desired_divisor = DIV_ROUND_CLOSEST(p->iclk_virtual_root_freq,
0157                                clock << p->auxdiv);
0158         p->divsel = (p->desired_divisor / p->iclk_pi_range) - 2;
0159         p->phaseinc = p->desired_divisor % p->iclk_pi_range;
0160 
0161         /*
0162          * Near 20MHz is a corner case which is
0163          * out of range for the 7-bit divisor
0164          */
0165         if (p->divsel <= 0x7f)
0166             break;
0167     }
0168 }
0169 
0170 /* Program iCLKIP clock to the desired frequency */
0171 void lpt_program_iclkip(const struct intel_crtc_state *crtc_state)
0172 {
0173     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0174     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0175     int clock = crtc_state->hw.adjusted_mode.crtc_clock;
0176     struct iclkip_params p;
0177     u32 temp;
0178 
0179     lpt_disable_iclkip(dev_priv);
0180 
0181     lpt_compute_iclkip(&p, clock);
0182 
0183     /* This should not happen with any sane values */
0184     drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIVSEL(p.divsel) &
0185             ~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
0186     drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIR(p.phasedir) &
0187             ~SBI_SSCDIVINTPHASE_INCVAL_MASK);
0188 
0189     drm_dbg_kms(&dev_priv->drm,
0190             "iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
0191             clock, p.auxdiv, p.divsel, p.phasedir, p.phaseinc);
0192 
0193     mutex_lock(&dev_priv->sb_lock);
0194 
0195     /* Program SSCDIVINTPHASE6 */
0196     temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
0197     temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
0198     temp |= SBI_SSCDIVINTPHASE_DIVSEL(p.divsel);
0199     temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
0200     temp |= SBI_SSCDIVINTPHASE_INCVAL(p.phaseinc);
0201     temp |= SBI_SSCDIVINTPHASE_DIR(p.phasedir);
0202     temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
0203     intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK);
0204 
0205     /* Program SSCAUXDIV */
0206     temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
0207     temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
0208     temp |= SBI_SSCAUXDIV_FINALDIV2SEL(p.auxdiv);
0209     intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK);
0210 
0211     /* Enable modulator and associated divider */
0212     temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
0213     temp &= ~SBI_SSCCTL_DISABLE;
0214     intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);
0215 
0216     mutex_unlock(&dev_priv->sb_lock);
0217 
0218     /* Wait for initialization time */
0219     udelay(24);
0220 
0221     intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_UNGATE);
0222 }
0223 
0224 int lpt_get_iclkip(struct drm_i915_private *dev_priv)
0225 {
0226     struct iclkip_params p;
0227     u32 temp;
0228 
0229     if ((intel_de_read(dev_priv, PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)
0230         return 0;
0231 
0232     iclkip_params_init(&p);
0233 
0234     mutex_lock(&dev_priv->sb_lock);
0235 
0236     temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);
0237     if (temp & SBI_SSCCTL_DISABLE) {
0238         mutex_unlock(&dev_priv->sb_lock);
0239         return 0;
0240     }
0241 
0242     temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);
0243     p.divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>
0244         SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;
0245     p.phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>
0246         SBI_SSCDIVINTPHASE_INCVAL_SHIFT;
0247 
0248     temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);
0249     p.auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>
0250         SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;
0251 
0252     mutex_unlock(&dev_priv->sb_lock);
0253 
0254     p.desired_divisor = (p.divsel + 2) * p.iclk_pi_range + p.phaseinc;
0255 
0256     return lpt_iclkip_freq(&p);
0257 }
0258 
0259 /* Implements 3 different sequences from BSpec chapter "Display iCLK
0260  * Programming" based on the parameters passed:
0261  * - Sequence to enable CLKOUT_DP
0262  * - Sequence to enable CLKOUT_DP without spread
0263  * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O
0264  */
0265 static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,
0266                  bool with_spread, bool with_fdi)
0267 {
0268     u32 reg, tmp;
0269 
0270     if (drm_WARN(&dev_priv->drm, with_fdi && !with_spread,
0271              "FDI requires downspread\n"))
0272         with_spread = true;
0273     if (drm_WARN(&dev_priv->drm, HAS_PCH_LPT_LP(dev_priv) &&
0274              with_fdi, "LP PCH doesn't have FDI\n"))
0275         with_fdi = false;
0276 
0277     mutex_lock(&dev_priv->sb_lock);
0278 
0279     tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
0280     tmp &= ~SBI_SSCCTL_DISABLE;
0281     tmp |= SBI_SSCCTL_PATHALT;
0282     intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
0283 
0284     udelay(24);
0285 
0286     if (with_spread) {
0287         tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
0288         tmp &= ~SBI_SSCCTL_PATHALT;
0289         intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
0290 
0291         if (with_fdi)
0292             lpt_fdi_program_mphy(dev_priv);
0293     }
0294 
0295     reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
0296     tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
0297     tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;
0298     intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
0299 
0300     mutex_unlock(&dev_priv->sb_lock);
0301 }
0302 
0303 /* Sequence to disable CLKOUT_DP */
0304 void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)
0305 {
0306     u32 reg, tmp;
0307 
0308     mutex_lock(&dev_priv->sb_lock);
0309 
0310     reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;
0311     tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);
0312     tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;
0313     intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);
0314 
0315     tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);
0316     if (!(tmp & SBI_SSCCTL_DISABLE)) {
0317         if (!(tmp & SBI_SSCCTL_PATHALT)) {
0318             tmp |= SBI_SSCCTL_PATHALT;
0319             intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
0320             udelay(32);
0321         }
0322         tmp |= SBI_SSCCTL_DISABLE;
0323         intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);
0324     }
0325 
0326     mutex_unlock(&dev_priv->sb_lock);
0327 }
0328 
0329 #define BEND_IDX(steps) ((50 + (steps)) / 5)
0330 
0331 static const u16 sscdivintphase[] = {
0332     [BEND_IDX( 50)] = 0x3B23,
0333     [BEND_IDX( 45)] = 0x3B23,
0334     [BEND_IDX( 40)] = 0x3C23,
0335     [BEND_IDX( 35)] = 0x3C23,
0336     [BEND_IDX( 30)] = 0x3D23,
0337     [BEND_IDX( 25)] = 0x3D23,
0338     [BEND_IDX( 20)] = 0x3E23,
0339     [BEND_IDX( 15)] = 0x3E23,
0340     [BEND_IDX( 10)] = 0x3F23,
0341     [BEND_IDX(  5)] = 0x3F23,
0342     [BEND_IDX(  0)] = 0x0025,
0343     [BEND_IDX( -5)] = 0x0025,
0344     [BEND_IDX(-10)] = 0x0125,
0345     [BEND_IDX(-15)] = 0x0125,
0346     [BEND_IDX(-20)] = 0x0225,
0347     [BEND_IDX(-25)] = 0x0225,
0348     [BEND_IDX(-30)] = 0x0325,
0349     [BEND_IDX(-35)] = 0x0325,
0350     [BEND_IDX(-40)] = 0x0425,
0351     [BEND_IDX(-45)] = 0x0425,
0352     [BEND_IDX(-50)] = 0x0525,
0353 };
0354 
0355 /*
0356  * Bend CLKOUT_DP
0357  * steps -50 to 50 inclusive, in steps of 5
0358  * < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)
0359  * change in clock period = -(steps / 10) * 5.787 ps
0360  */
0361 static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)
0362 {
0363     u32 tmp;
0364     int idx = BEND_IDX(steps);
0365 
0366     if (drm_WARN_ON(&dev_priv->drm, steps % 5 != 0))
0367         return;
0368 
0369     if (drm_WARN_ON(&dev_priv->drm, idx >= ARRAY_SIZE(sscdivintphase)))
0370         return;
0371 
0372     mutex_lock(&dev_priv->sb_lock);
0373 
0374     if (steps % 10 != 0)
0375         tmp = 0xAAAAAAAB;
0376     else
0377         tmp = 0x00000000;
0378     intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);
0379 
0380     tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);
0381     tmp &= 0xffff0000;
0382     tmp |= sscdivintphase[idx];
0383     intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);
0384 
0385     mutex_unlock(&dev_priv->sb_lock);
0386 }
0387 
0388 #undef BEND_IDX
0389 
0390 static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)
0391 {
0392     u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
0393     u32 ctl = intel_de_read(dev_priv, SPLL_CTL);
0394 
0395     if ((ctl & SPLL_PLL_ENABLE) == 0)
0396         return false;
0397 
0398     if ((ctl & SPLL_REF_MASK) == SPLL_REF_MUXED_SSC &&
0399         (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
0400         return true;
0401 
0402     if (IS_BROADWELL(dev_priv) &&
0403         (ctl & SPLL_REF_MASK) == SPLL_REF_PCH_SSC_BDW)
0404         return true;
0405 
0406     return false;
0407 }
0408 
0409 static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,
0410                    enum intel_dpll_id id)
0411 {
0412     u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);
0413     u32 ctl = intel_de_read(dev_priv, WRPLL_CTL(id));
0414 
0415     if ((ctl & WRPLL_PLL_ENABLE) == 0)
0416         return false;
0417 
0418     if ((ctl & WRPLL_REF_MASK) == WRPLL_REF_PCH_SSC)
0419         return true;
0420 
0421     if ((IS_BROADWELL(dev_priv) || IS_HSW_ULT(dev_priv)) &&
0422         (ctl & WRPLL_REF_MASK) == WRPLL_REF_MUXED_SSC_BDW &&
0423         (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)
0424         return true;
0425 
0426     return false;
0427 }
0428 
0429 static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)
0430 {
0431     struct intel_encoder *encoder;
0432     bool has_fdi = false;
0433 
0434     for_each_intel_encoder(&dev_priv->drm, encoder) {
0435         switch (encoder->type) {
0436         case INTEL_OUTPUT_ANALOG:
0437             has_fdi = true;
0438             break;
0439         default:
0440             break;
0441         }
0442     }
0443 
0444     /*
0445      * The BIOS may have decided to use the PCH SSC
0446      * reference so we must not disable it until the
0447      * relevant PLLs have stopped relying on it. We'll
0448      * just leave the PCH SSC reference enabled in case
0449      * any active PLL is using it. It will get disabled
0450      * after runtime suspend if we don't have FDI.
0451      *
0452      * TODO: Move the whole reference clock handling
0453      * to the modeset sequence proper so that we can
0454      * actually enable/disable/reconfigure these things
0455      * safely. To do that we need to introduce a real
0456      * clock hierarchy. That would also allow us to do
0457      * clock bending finally.
0458      */
0459     dev_priv->pch_ssc_use = 0;
0460 
0461     if (spll_uses_pch_ssc(dev_priv)) {
0462         drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");
0463         dev_priv->pch_ssc_use |= BIT(DPLL_ID_SPLL);
0464     }
0465 
0466     if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {
0467         drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");
0468         dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL1);
0469     }
0470 
0471     if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {
0472         drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");
0473         dev_priv->pch_ssc_use |= BIT(DPLL_ID_WRPLL2);
0474     }
0475 
0476     if (dev_priv->pch_ssc_use)
0477         return;
0478 
0479     if (has_fdi) {
0480         lpt_bend_clkout_dp(dev_priv, 0);
0481         lpt_enable_clkout_dp(dev_priv, true, true);
0482     } else {
0483         lpt_disable_clkout_dp(dev_priv);
0484     }
0485 }
0486 
0487 static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv)
0488 {
0489     struct intel_encoder *encoder;
0490     int i;
0491     u32 val, final;
0492     bool has_lvds = false;
0493     bool has_cpu_edp = false;
0494     bool has_panel = false;
0495     bool has_ck505 = false;
0496     bool can_ssc = false;
0497     bool using_ssc_source = false;
0498 
0499     /* We need to take the global config into account */
0500     for_each_intel_encoder(&dev_priv->drm, encoder) {
0501         switch (encoder->type) {
0502         case INTEL_OUTPUT_LVDS:
0503             has_panel = true;
0504             has_lvds = true;
0505             break;
0506         case INTEL_OUTPUT_EDP:
0507             has_panel = true;
0508             if (encoder->port == PORT_A)
0509                 has_cpu_edp = true;
0510             break;
0511         default:
0512             break;
0513         }
0514     }
0515 
0516     if (HAS_PCH_IBX(dev_priv)) {
0517         has_ck505 = dev_priv->vbt.display_clock_mode;
0518         can_ssc = has_ck505;
0519     } else {
0520         has_ck505 = false;
0521         can_ssc = true;
0522     }
0523 
0524     /* Check if any DPLLs are using the SSC source */
0525     for (i = 0; i < dev_priv->dpll.num_shared_dpll; i++) {
0526         u32 temp = intel_de_read(dev_priv, PCH_DPLL(i));
0527 
0528         if (!(temp & DPLL_VCO_ENABLE))
0529             continue;
0530 
0531         if ((temp & PLL_REF_INPUT_MASK) ==
0532             PLLB_REF_INPUT_SPREADSPECTRUMIN) {
0533             using_ssc_source = true;
0534             break;
0535         }
0536     }
0537 
0538     drm_dbg_kms(&dev_priv->drm,
0539             "has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",
0540             has_panel, has_lvds, has_ck505, using_ssc_source);
0541 
0542     /* Ironlake: try to setup display ref clock before DPLL
0543      * enabling. This is only under driver's control after
0544      * PCH B stepping, previous chipset stepping should be
0545      * ignoring this setting.
0546      */
0547     val = intel_de_read(dev_priv, PCH_DREF_CONTROL);
0548 
0549     /* As we must carefully and slowly disable/enable each source in turn,
0550      * compute the final state we want first and check if we need to
0551      * make any changes at all.
0552      */
0553     final = val;
0554     final &= ~DREF_NONSPREAD_SOURCE_MASK;
0555     if (has_ck505)
0556         final |= DREF_NONSPREAD_CK505_ENABLE;
0557     else
0558         final |= DREF_NONSPREAD_SOURCE_ENABLE;
0559 
0560     final &= ~DREF_SSC_SOURCE_MASK;
0561     final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
0562     final &= ~DREF_SSC1_ENABLE;
0563 
0564     if (has_panel) {
0565         final |= DREF_SSC_SOURCE_ENABLE;
0566 
0567         if (intel_panel_use_ssc(dev_priv) && can_ssc)
0568             final |= DREF_SSC1_ENABLE;
0569 
0570         if (has_cpu_edp) {
0571             if (intel_panel_use_ssc(dev_priv) && can_ssc)
0572                 final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
0573             else
0574                 final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
0575         } else {
0576             final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
0577         }
0578     } else if (using_ssc_source) {
0579         final |= DREF_SSC_SOURCE_ENABLE;
0580         final |= DREF_SSC1_ENABLE;
0581     }
0582 
0583     if (final == val)
0584         return;
0585 
0586     /* Always enable nonspread source */
0587     val &= ~DREF_NONSPREAD_SOURCE_MASK;
0588 
0589     if (has_ck505)
0590         val |= DREF_NONSPREAD_CK505_ENABLE;
0591     else
0592         val |= DREF_NONSPREAD_SOURCE_ENABLE;
0593 
0594     if (has_panel) {
0595         val &= ~DREF_SSC_SOURCE_MASK;
0596         val |= DREF_SSC_SOURCE_ENABLE;
0597 
0598         /* SSC must be turned on before enabling the CPU output  */
0599         if (intel_panel_use_ssc(dev_priv) && can_ssc) {
0600             drm_dbg_kms(&dev_priv->drm, "Using SSC on panel\n");
0601             val |= DREF_SSC1_ENABLE;
0602         } else {
0603             val &= ~DREF_SSC1_ENABLE;
0604         }
0605 
0606         /* Get SSC going before enabling the outputs */
0607         intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
0608         intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
0609         udelay(200);
0610 
0611         val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
0612 
0613         /* Enable CPU source on CPU attached eDP */
0614         if (has_cpu_edp) {
0615             if (intel_panel_use_ssc(dev_priv) && can_ssc) {
0616                 drm_dbg_kms(&dev_priv->drm,
0617                         "Using SSC on eDP\n");
0618                 val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
0619             } else {
0620                 val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
0621             }
0622         } else {
0623             val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
0624         }
0625 
0626         intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
0627         intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
0628         udelay(200);
0629     } else {
0630         drm_dbg_kms(&dev_priv->drm, "Disabling CPU source output\n");
0631 
0632         val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
0633 
0634         /* Turn off CPU output */
0635         val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
0636 
0637         intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
0638         intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
0639         udelay(200);
0640 
0641         if (!using_ssc_source) {
0642             drm_dbg_kms(&dev_priv->drm, "Disabling SSC source\n");
0643 
0644             /* Turn off the SSC source */
0645             val &= ~DREF_SSC_SOURCE_MASK;
0646             val |= DREF_SSC_SOURCE_DISABLE;
0647 
0648             /* Turn off SSC1 */
0649             val &= ~DREF_SSC1_ENABLE;
0650 
0651             intel_de_write(dev_priv, PCH_DREF_CONTROL, val);
0652             intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);
0653             udelay(200);
0654         }
0655     }
0656 
0657     BUG_ON(val != final);
0658 }
0659 
0660 /*
0661  * Initialize reference clocks when the driver loads
0662  */
0663 void intel_init_pch_refclk(struct drm_i915_private *dev_priv)
0664 {
0665     if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))
0666         ilk_init_pch_refclk(dev_priv);
0667     else if (HAS_PCH_LPT(dev_priv))
0668         lpt_init_pch_refclk(dev_priv);
0669 }