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