File Index
Files and directories
Sign in
FILE

intel_pch_refclk.c

File preview with syntax highlighting.

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