brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · 713cfba Raw
678 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2021 Intel Corporation4 */5 6#include "i915_reg.h"7#include "intel_de.h"8#include "intel_display_types.h"9#include "intel_panel.h"10#include "intel_pch_refclk.h"11#include "intel_sbi.h"12 13static void lpt_fdi_reset_mphy(struct drm_i915_private *dev_priv)14{15	intel_de_rmw(dev_priv, SOUTH_CHICKEN2, 0, FDI_MPHY_IOSFSB_RESET_CTL);16 17	if (wait_for_us(intel_de_read(dev_priv, SOUTH_CHICKEN2) &18			FDI_MPHY_IOSFSB_RESET_STATUS, 100))19		drm_err(&dev_priv->drm, "FDI mPHY reset assert timeout\n");20 21	intel_de_rmw(dev_priv, SOUTH_CHICKEN2, FDI_MPHY_IOSFSB_RESET_CTL, 0);22 23	if (wait_for_us((intel_de_read(dev_priv, SOUTH_CHICKEN2) &24			 FDI_MPHY_IOSFSB_RESET_STATUS) == 0, 100))25		drm_err(&dev_priv->drm, "FDI mPHY reset de-assert timeout\n");26}27 28/* WaMPhyProgramming:hsw */29static void lpt_fdi_program_mphy(struct drm_i915_private *dev_priv)30{31	u32 tmp;32 33	lpt_fdi_reset_mphy(dev_priv);34 35	tmp = intel_sbi_read(dev_priv, 0x8008, SBI_MPHY);36	tmp &= ~(0xFF << 24);37	tmp |= (0x12 << 24);38	intel_sbi_write(dev_priv, 0x8008, tmp, SBI_MPHY);39 40	tmp = intel_sbi_read(dev_priv, 0x2008, SBI_MPHY);41	tmp |= (1 << 11);42	intel_sbi_write(dev_priv, 0x2008, tmp, SBI_MPHY);43 44	tmp = intel_sbi_read(dev_priv, 0x2108, SBI_MPHY);45	tmp |= (1 << 11);46	intel_sbi_write(dev_priv, 0x2108, tmp, SBI_MPHY);47 48	tmp = intel_sbi_read(dev_priv, 0x206C, SBI_MPHY);49	tmp |= (1 << 24) | (1 << 21) | (1 << 18);50	intel_sbi_write(dev_priv, 0x206C, tmp, SBI_MPHY);51 52	tmp = intel_sbi_read(dev_priv, 0x216C, SBI_MPHY);53	tmp |= (1 << 24) | (1 << 21) | (1 << 18);54	intel_sbi_write(dev_priv, 0x216C, tmp, SBI_MPHY);55 56	tmp = intel_sbi_read(dev_priv, 0x2080, SBI_MPHY);57	tmp &= ~(7 << 13);58	tmp |= (5 << 13);59	intel_sbi_write(dev_priv, 0x2080, tmp, SBI_MPHY);60 61	tmp = intel_sbi_read(dev_priv, 0x2180, SBI_MPHY);62	tmp &= ~(7 << 13);63	tmp |= (5 << 13);64	intel_sbi_write(dev_priv, 0x2180, tmp, SBI_MPHY);65 66	tmp = intel_sbi_read(dev_priv, 0x208C, SBI_MPHY);67	tmp &= ~0xFF;68	tmp |= 0x1C;69	intel_sbi_write(dev_priv, 0x208C, tmp, SBI_MPHY);70 71	tmp = intel_sbi_read(dev_priv, 0x218C, SBI_MPHY);72	tmp &= ~0xFF;73	tmp |= 0x1C;74	intel_sbi_write(dev_priv, 0x218C, tmp, SBI_MPHY);75 76	tmp = intel_sbi_read(dev_priv, 0x2098, SBI_MPHY);77	tmp &= ~(0xFF << 16);78	tmp |= (0x1C << 16);79	intel_sbi_write(dev_priv, 0x2098, tmp, SBI_MPHY);80 81	tmp = intel_sbi_read(dev_priv, 0x2198, SBI_MPHY);82	tmp &= ~(0xFF << 16);83	tmp |= (0x1C << 16);84	intel_sbi_write(dev_priv, 0x2198, tmp, SBI_MPHY);85 86	tmp = intel_sbi_read(dev_priv, 0x20C4, SBI_MPHY);87	tmp |= (1 << 27);88	intel_sbi_write(dev_priv, 0x20C4, tmp, SBI_MPHY);89 90	tmp = intel_sbi_read(dev_priv, 0x21C4, SBI_MPHY);91	tmp |= (1 << 27);92	intel_sbi_write(dev_priv, 0x21C4, tmp, SBI_MPHY);93 94	tmp = intel_sbi_read(dev_priv, 0x20EC, SBI_MPHY);95	tmp &= ~(0xF << 28);96	tmp |= (4 << 28);97	intel_sbi_write(dev_priv, 0x20EC, tmp, SBI_MPHY);98 99	tmp = intel_sbi_read(dev_priv, 0x21EC, SBI_MPHY);100	tmp &= ~(0xF << 28);101	tmp |= (4 << 28);102	intel_sbi_write(dev_priv, 0x21EC, tmp, SBI_MPHY);103}104 105void lpt_disable_iclkip(struct drm_i915_private *dev_priv)106{107	u32 temp;108 109	intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_GATE);110 111	mutex_lock(&dev_priv->sb_lock);112 113	temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);114	temp |= SBI_SSCCTL_DISABLE;115	intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);116 117	mutex_unlock(&dev_priv->sb_lock);118}119 120struct iclkip_params {121	u32 iclk_virtual_root_freq;122	u32 iclk_pi_range;123	u32 divsel, phaseinc, auxdiv, phasedir, desired_divisor;124};125 126static void iclkip_params_init(struct iclkip_params *p)127{128	memset(p, 0, sizeof(*p));129 130	p->iclk_virtual_root_freq = 172800 * 1000;131	p->iclk_pi_range = 64;132}133 134static int lpt_iclkip_freq(struct iclkip_params *p)135{136	return DIV_ROUND_CLOSEST(p->iclk_virtual_root_freq,137				 p->desired_divisor << p->auxdiv);138}139 140static void lpt_compute_iclkip(struct iclkip_params *p, int clock)141{142	iclkip_params_init(p);143 144	/* The iCLK virtual clock root frequency is in MHz,145	 * but the adjusted_mode->crtc_clock in KHz. To get the146	 * divisors, it is necessary to divide one by another, so we147	 * convert the virtual clock precision to KHz here for higher148	 * precision.149	 */150	for (p->auxdiv = 0; p->auxdiv < 2; p->auxdiv++) {151		p->desired_divisor = DIV_ROUND_CLOSEST(p->iclk_virtual_root_freq,152						       clock << p->auxdiv);153		p->divsel = (p->desired_divisor / p->iclk_pi_range) - 2;154		p->phaseinc = p->desired_divisor % p->iclk_pi_range;155 156		/*157		 * Near 20MHz is a corner case which is158		 * out of range for the 7-bit divisor159		 */160		if (p->divsel <= 0x7f)161			break;162	}163}164 165int lpt_iclkip(const struct intel_crtc_state *crtc_state)166{167	struct iclkip_params p;168 169	lpt_compute_iclkip(&p, crtc_state->hw.adjusted_mode.crtc_clock);170 171	return lpt_iclkip_freq(&p);172}173 174/* Program iCLKIP clock to the desired frequency */175void lpt_program_iclkip(const struct intel_crtc_state *crtc_state)176{177	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);178	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);179	int clock = crtc_state->hw.adjusted_mode.crtc_clock;180	struct iclkip_params p;181	u32 temp;182 183	lpt_disable_iclkip(dev_priv);184 185	lpt_compute_iclkip(&p, clock);186	drm_WARN_ON(&dev_priv->drm, lpt_iclkip_freq(&p) != clock);187 188	/* This should not happen with any sane values */189	drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIVSEL(p.divsel) &190		    ~SBI_SSCDIVINTPHASE_DIVSEL_MASK);191	drm_WARN_ON(&dev_priv->drm, SBI_SSCDIVINTPHASE_DIR(p.phasedir) &192		    ~SBI_SSCDIVINTPHASE_INCVAL_MASK);193 194	drm_dbg_kms(&dev_priv->drm,195		    "iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",196		    clock, p.auxdiv, p.divsel, p.phasedir, p.phaseinc);197 198	mutex_lock(&dev_priv->sb_lock);199 200	/* Program SSCDIVINTPHASE6 */201	temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);202	temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;203	temp |= SBI_SSCDIVINTPHASE_DIVSEL(p.divsel);204	temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;205	temp |= SBI_SSCDIVINTPHASE_INCVAL(p.phaseinc);206	temp |= SBI_SSCDIVINTPHASE_DIR(p.phasedir);207	temp |= SBI_SSCDIVINTPHASE_PROPAGATE;208	intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE6, temp, SBI_ICLK);209 210	/* Program SSCAUXDIV */211	temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);212	temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);213	temp |= SBI_SSCAUXDIV_FINALDIV2SEL(p.auxdiv);214	intel_sbi_write(dev_priv, SBI_SSCAUXDIV6, temp, SBI_ICLK);215 216	/* Enable modulator and associated divider */217	temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);218	temp &= ~SBI_SSCCTL_DISABLE;219	intel_sbi_write(dev_priv, SBI_SSCCTL6, temp, SBI_ICLK);220 221	mutex_unlock(&dev_priv->sb_lock);222 223	/* Wait for initialization time */224	udelay(24);225 226	intel_de_write(dev_priv, PIXCLK_GATE, PIXCLK_GATE_UNGATE);227}228 229int lpt_get_iclkip(struct drm_i915_private *dev_priv)230{231	struct iclkip_params p;232	u32 temp;233 234	if ((intel_de_read(dev_priv, PIXCLK_GATE) & PIXCLK_GATE_UNGATE) == 0)235		return 0;236 237	iclkip_params_init(&p);238 239	mutex_lock(&dev_priv->sb_lock);240 241	temp = intel_sbi_read(dev_priv, SBI_SSCCTL6, SBI_ICLK);242	if (temp & SBI_SSCCTL_DISABLE) {243		mutex_unlock(&dev_priv->sb_lock);244		return 0;245	}246 247	temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6, SBI_ICLK);248	p.divsel = (temp & SBI_SSCDIVINTPHASE_DIVSEL_MASK) >>249		SBI_SSCDIVINTPHASE_DIVSEL_SHIFT;250	p.phaseinc = (temp & SBI_SSCDIVINTPHASE_INCVAL_MASK) >>251		SBI_SSCDIVINTPHASE_INCVAL_SHIFT;252 253	temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6, SBI_ICLK);254	p.auxdiv = (temp & SBI_SSCAUXDIV_FINALDIV2SEL_MASK) >>255		SBI_SSCAUXDIV_FINALDIV2SEL_SHIFT;256 257	mutex_unlock(&dev_priv->sb_lock);258 259	p.desired_divisor = (p.divsel + 2) * p.iclk_pi_range + p.phaseinc;260 261	return lpt_iclkip_freq(&p);262}263 264/* Implements 3 different sequences from BSpec chapter "Display iCLK265 * Programming" based on the parameters passed:266 * - Sequence to enable CLKOUT_DP267 * - Sequence to enable CLKOUT_DP without spread268 * - Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O269 */270static void lpt_enable_clkout_dp(struct drm_i915_private *dev_priv,271				 bool with_spread, bool with_fdi)272{273	u32 reg, tmp;274 275	if (drm_WARN(&dev_priv->drm, with_fdi && !with_spread,276		     "FDI requires downspread\n"))277		with_spread = true;278	if (drm_WARN(&dev_priv->drm, HAS_PCH_LPT_LP(dev_priv) &&279		     with_fdi, "LP PCH doesn't have FDI\n"))280		with_fdi = false;281 282	mutex_lock(&dev_priv->sb_lock);283 284	tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);285	tmp &= ~SBI_SSCCTL_DISABLE;286	tmp |= SBI_SSCCTL_PATHALT;287	intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);288 289	udelay(24);290 291	if (with_spread) {292		tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);293		tmp &= ~SBI_SSCCTL_PATHALT;294		intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);295 296		if (with_fdi)297			lpt_fdi_program_mphy(dev_priv);298	}299 300	reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;301	tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);302	tmp |= SBI_GEN0_CFG_BUFFENABLE_DISABLE;303	intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);304 305	mutex_unlock(&dev_priv->sb_lock);306}307 308/* Sequence to disable CLKOUT_DP */309void lpt_disable_clkout_dp(struct drm_i915_private *dev_priv)310{311	u32 reg, tmp;312 313	mutex_lock(&dev_priv->sb_lock);314 315	reg = HAS_PCH_LPT_LP(dev_priv) ? SBI_GEN0 : SBI_DBUFF0;316	tmp = intel_sbi_read(dev_priv, reg, SBI_ICLK);317	tmp &= ~SBI_GEN0_CFG_BUFFENABLE_DISABLE;318	intel_sbi_write(dev_priv, reg, tmp, SBI_ICLK);319 320	tmp = intel_sbi_read(dev_priv, SBI_SSCCTL, SBI_ICLK);321	if (!(tmp & SBI_SSCCTL_DISABLE)) {322		if (!(tmp & SBI_SSCCTL_PATHALT)) {323			tmp |= SBI_SSCCTL_PATHALT;324			intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);325			udelay(32);326		}327		tmp |= SBI_SSCCTL_DISABLE;328		intel_sbi_write(dev_priv, SBI_SSCCTL, tmp, SBI_ICLK);329	}330 331	mutex_unlock(&dev_priv->sb_lock);332}333 334#define BEND_IDX(steps) ((50 + (steps)) / 5)335 336static const u16 sscdivintphase[] = {337	[BEND_IDX( 50)] = 0x3B23,338	[BEND_IDX( 45)] = 0x3B23,339	[BEND_IDX( 40)] = 0x3C23,340	[BEND_IDX( 35)] = 0x3C23,341	[BEND_IDX( 30)] = 0x3D23,342	[BEND_IDX( 25)] = 0x3D23,343	[BEND_IDX( 20)] = 0x3E23,344	[BEND_IDX( 15)] = 0x3E23,345	[BEND_IDX( 10)] = 0x3F23,346	[BEND_IDX(  5)] = 0x3F23,347	[BEND_IDX(  0)] = 0x0025,348	[BEND_IDX( -5)] = 0x0025,349	[BEND_IDX(-10)] = 0x0125,350	[BEND_IDX(-15)] = 0x0125,351	[BEND_IDX(-20)] = 0x0225,352	[BEND_IDX(-25)] = 0x0225,353	[BEND_IDX(-30)] = 0x0325,354	[BEND_IDX(-35)] = 0x0325,355	[BEND_IDX(-40)] = 0x0425,356	[BEND_IDX(-45)] = 0x0425,357	[BEND_IDX(-50)] = 0x0525,358};359 360/*361 * Bend CLKOUT_DP362 * steps -50 to 50 inclusive, in steps of 5363 * < 0 slow down the clock, > 0 speed up the clock, 0 == no bend (135MHz)364 * change in clock period = -(steps / 10) * 5.787 ps365 */366static void lpt_bend_clkout_dp(struct drm_i915_private *dev_priv, int steps)367{368	u32 tmp;369	int idx = BEND_IDX(steps);370 371	if (drm_WARN_ON(&dev_priv->drm, steps % 5 != 0))372		return;373 374	if (drm_WARN_ON(&dev_priv->drm, idx >= ARRAY_SIZE(sscdivintphase)))375		return;376 377	mutex_lock(&dev_priv->sb_lock);378 379	if (steps % 10 != 0)380		tmp = 0xAAAAAAAB;381	else382		tmp = 0x00000000;383	intel_sbi_write(dev_priv, SBI_SSCDITHPHASE, tmp, SBI_ICLK);384 385	tmp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE, SBI_ICLK);386	tmp &= 0xffff0000;387	tmp |= sscdivintphase[idx];388	intel_sbi_write(dev_priv, SBI_SSCDIVINTPHASE, tmp, SBI_ICLK);389 390	mutex_unlock(&dev_priv->sb_lock);391}392 393#undef BEND_IDX394 395static bool spll_uses_pch_ssc(struct drm_i915_private *dev_priv)396{397	u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);398	u32 ctl = intel_de_read(dev_priv, SPLL_CTL);399 400	if ((ctl & SPLL_PLL_ENABLE) == 0)401		return false;402 403	if ((ctl & SPLL_REF_MASK) == SPLL_REF_MUXED_SSC &&404	    (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)405		return true;406 407	if (IS_BROADWELL(dev_priv) &&408	    (ctl & SPLL_REF_MASK) == SPLL_REF_PCH_SSC_BDW)409		return true;410 411	return false;412}413 414static bool wrpll_uses_pch_ssc(struct drm_i915_private *dev_priv,415			       enum intel_dpll_id id)416{417	u32 fuse_strap = intel_de_read(dev_priv, FUSE_STRAP);418	u32 ctl = intel_de_read(dev_priv, WRPLL_CTL(id));419 420	if ((ctl & WRPLL_PLL_ENABLE) == 0)421		return false;422 423	if ((ctl & WRPLL_REF_MASK) == WRPLL_REF_PCH_SSC)424		return true;425 426	if ((IS_BROADWELL(dev_priv) || IS_HASWELL_ULT(dev_priv)) &&427	    (ctl & WRPLL_REF_MASK) == WRPLL_REF_MUXED_SSC_BDW &&428	    (fuse_strap & HSW_CPU_SSC_ENABLE) == 0)429		return true;430 431	return false;432}433 434static void lpt_init_pch_refclk(struct drm_i915_private *dev_priv)435{436	struct intel_encoder *encoder;437	bool has_fdi = false;438 439	for_each_intel_encoder(&dev_priv->drm, encoder) {440		switch (encoder->type) {441		case INTEL_OUTPUT_ANALOG:442			has_fdi = true;443			break;444		default:445			break;446		}447	}448 449	/*450	 * The BIOS may have decided to use the PCH SSC451	 * reference so we must not disable it until the452	 * relevant PLLs have stopped relying on it. We'll453	 * just leave the PCH SSC reference enabled in case454	 * any active PLL is using it. It will get disabled455	 * after runtime suspend if we don't have FDI.456	 *457	 * TODO: Move the whole reference clock handling458	 * to the modeset sequence proper so that we can459	 * actually enable/disable/reconfigure these things460	 * safely. To do that we need to introduce a real461	 * clock hierarchy. That would also allow us to do462	 * clock bending finally.463	 */464	dev_priv->display.dpll.pch_ssc_use = 0;465 466	if (spll_uses_pch_ssc(dev_priv)) {467		drm_dbg_kms(&dev_priv->drm, "SPLL using PCH SSC\n");468		dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_SPLL);469	}470 471	if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL1)) {472		drm_dbg_kms(&dev_priv->drm, "WRPLL1 using PCH SSC\n");473		dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL1);474	}475 476	if (wrpll_uses_pch_ssc(dev_priv, DPLL_ID_WRPLL2)) {477		drm_dbg_kms(&dev_priv->drm, "WRPLL2 using PCH SSC\n");478		dev_priv->display.dpll.pch_ssc_use |= BIT(DPLL_ID_WRPLL2);479	}480 481	if (dev_priv->display.dpll.pch_ssc_use)482		return;483 484	if (has_fdi) {485		lpt_bend_clkout_dp(dev_priv, 0);486		lpt_enable_clkout_dp(dev_priv, true, true);487	} else {488		lpt_disable_clkout_dp(dev_priv);489	}490}491 492static void ilk_init_pch_refclk(struct drm_i915_private *dev_priv)493{494	struct intel_encoder *encoder;495	struct intel_shared_dpll *pll;496	int i;497	u32 val, final;498	bool has_lvds = false;499	bool has_cpu_edp = false;500	bool has_panel = false;501	bool has_ck505 = false;502	bool can_ssc = false;503	bool using_ssc_source = false;504 505	/* We need to take the global config into account */506	for_each_intel_encoder(&dev_priv->drm, encoder) {507		switch (encoder->type) {508		case INTEL_OUTPUT_LVDS:509			has_panel = true;510			has_lvds = true;511			break;512		case INTEL_OUTPUT_EDP:513			has_panel = true;514			if (encoder->port == PORT_A)515				has_cpu_edp = true;516			break;517		default:518			break;519		}520	}521 522	if (HAS_PCH_IBX(dev_priv)) {523		has_ck505 = dev_priv->display.vbt.display_clock_mode;524		can_ssc = has_ck505;525	} else {526		has_ck505 = false;527		can_ssc = true;528	}529 530	/* Check if any DPLLs are using the SSC source */531	for_each_shared_dpll(dev_priv, pll, i) {532		u32 temp;533 534		temp = intel_de_read(dev_priv, PCH_DPLL(pll->info->id));535 536		if (!(temp & DPLL_VCO_ENABLE))537			continue;538 539		if ((temp & PLL_REF_INPUT_MASK) ==540		    PLLB_REF_INPUT_SPREADSPECTRUMIN) {541			using_ssc_source = true;542			break;543		}544	}545 546	drm_dbg_kms(&dev_priv->drm,547		    "has_panel %d has_lvds %d has_ck505 %d using_ssc_source %d\n",548		    has_panel, has_lvds, has_ck505, using_ssc_source);549 550	/* Ironlake: try to setup display ref clock before DPLL551	 * enabling. This is only under driver's control after552	 * PCH B stepping, previous chipset stepping should be553	 * ignoring this setting.554	 */555	val = intel_de_read(dev_priv, PCH_DREF_CONTROL);556 557	/* As we must carefully and slowly disable/enable each source in turn,558	 * compute the final state we want first and check if we need to559	 * make any changes at all.560	 */561	final = val;562	final &= ~DREF_NONSPREAD_SOURCE_MASK;563	if (has_ck505)564		final |= DREF_NONSPREAD_CK505_ENABLE;565	else566		final |= DREF_NONSPREAD_SOURCE_ENABLE;567 568	final &= ~DREF_SSC_SOURCE_MASK;569	final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;570	final &= ~DREF_SSC1_ENABLE;571 572	if (has_panel) {573		final |= DREF_SSC_SOURCE_ENABLE;574 575		if (intel_panel_use_ssc(dev_priv) && can_ssc)576			final |= DREF_SSC1_ENABLE;577 578		if (has_cpu_edp) {579			if (intel_panel_use_ssc(dev_priv) && can_ssc)580				final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;581			else582				final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;583		} else {584			final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;585		}586	} else if (using_ssc_source) {587		final |= DREF_SSC_SOURCE_ENABLE;588		final |= DREF_SSC1_ENABLE;589	}590 591	if (final == val)592		return;593 594	/* Always enable nonspread source */595	val &= ~DREF_NONSPREAD_SOURCE_MASK;596 597	if (has_ck505)598		val |= DREF_NONSPREAD_CK505_ENABLE;599	else600		val |= DREF_NONSPREAD_SOURCE_ENABLE;601 602	if (has_panel) {603		val &= ~DREF_SSC_SOURCE_MASK;604		val |= DREF_SSC_SOURCE_ENABLE;605 606		/* SSC must be turned on before enabling the CPU output  */607		if (intel_panel_use_ssc(dev_priv) && can_ssc) {608			drm_dbg_kms(&dev_priv->drm, "Using SSC on panel\n");609			val |= DREF_SSC1_ENABLE;610		} else {611			val &= ~DREF_SSC1_ENABLE;612		}613 614		/* Get SSC going before enabling the outputs */615		intel_de_write(dev_priv, PCH_DREF_CONTROL, val);616		intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);617		udelay(200);618 619		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;620 621		/* Enable CPU source on CPU attached eDP */622		if (has_cpu_edp) {623			if (intel_panel_use_ssc(dev_priv) && can_ssc) {624				drm_dbg_kms(&dev_priv->drm,625					    "Using SSC on eDP\n");626				val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;627			} else {628				val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;629			}630		} else {631			val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;632		}633 634		intel_de_write(dev_priv, PCH_DREF_CONTROL, val);635		intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);636		udelay(200);637	} else {638		drm_dbg_kms(&dev_priv->drm, "Disabling CPU source output\n");639 640		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;641 642		/* Turn off CPU output */643		val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;644 645		intel_de_write(dev_priv, PCH_DREF_CONTROL, val);646		intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);647		udelay(200);648 649		if (!using_ssc_source) {650			drm_dbg_kms(&dev_priv->drm, "Disabling SSC source\n");651 652			/* Turn off the SSC source */653			val &= ~DREF_SSC_SOURCE_MASK;654			val |= DREF_SSC_SOURCE_DISABLE;655 656			/* Turn off SSC1 */657			val &= ~DREF_SSC1_ENABLE;658 659			intel_de_write(dev_priv, PCH_DREF_CONTROL, val);660			intel_de_posting_read(dev_priv, PCH_DREF_CONTROL);661			udelay(200);662		}663	}664 665	drm_WARN_ON(&dev_priv->drm, val != final);666}667 668/*669 * Initialize reference clocks when the driver loads670 */671void intel_init_pch_refclk(struct drm_i915_private *dev_priv)672{673	if (HAS_PCH_IBX(dev_priv) || HAS_PCH_CPT(dev_priv))674		ilk_init_pch_refclk(dev_priv);675	else if (HAS_PCH_LPT(dev_priv))676		lpt_init_pch_refclk(dev_priv);677}678