Linux Audio

Check our new training course

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