1/*
2 * Copyright �� 2012 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Eugeni Dodonov <eugeni.dodonov@intel.com>
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <dev/drm2/drmP.h>
32#include <dev/drm2/drm.h>
33#include <dev/drm2/i915/i915_drm.h>
34#include <dev/drm2/i915/i915_drv.h>
35#include <dev/drm2/i915/intel_drv.h>
36
37/* HDMI/DVI modes ignore everything but the last 2 items. So we share
38 * them for both DP and FDI transports, allowing those ports to
39 * automatically adapt to HDMI connections as well
40 */
41static const u32 hsw_ddi_translations_dp[] = {
42	0x00FFFFFF, 0x0006000E,		/* DP parameters */
43	0x00D75FFF, 0x0005000A,
44	0x00C30FFF, 0x00040006,
45	0x80AAAFFF, 0x000B0000,
46	0x00FFFFFF, 0x0005000A,
47	0x00D75FFF, 0x000C0004,
48	0x80C30FFF, 0x000B0000,
49	0x00FFFFFF, 0x00040006,
50	0x80D75FFF, 0x000B0000,
51	0x00FFFFFF, 0x00040006		/* HDMI parameters */
52};
53
54static const u32 hsw_ddi_translations_fdi[] = {
55	0x00FFFFFF, 0x0007000E,		/* FDI parameters */
56	0x00D75FFF, 0x000F000A,
57	0x00C30FFF, 0x00060006,
58	0x00AAAFFF, 0x001E0000,
59	0x00FFFFFF, 0x000F000A,
60	0x00D75FFF, 0x00160004,
61	0x00C30FFF, 0x001E0000,
62	0x00FFFFFF, 0x00060006,
63	0x00D75FFF, 0x001E0000,
64	0x00FFFFFF, 0x00040006		/* HDMI parameters */
65};
66
67/* On Haswell, DDI port buffers must be programmed with correct values
68 * in advance. The buffer values are different for FDI and DP modes,
69 * but the HDMI/DVI fields are shared among those. So we program the DDI
70 * in either FDI or DP modes only, as HDMI connections will work with both
71 * of those
72 */
73static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode)
74{
75	struct drm_i915_private *dev_priv = dev->dev_private;
76	u32 reg;
77	int i;
78	const u32 *ddi_translations = ((use_fdi_mode) ?
79		hsw_ddi_translations_fdi :
80		hsw_ddi_translations_dp);
81
82	DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n",
83			port_name(port),
84			use_fdi_mode ? "FDI" : "DP");
85
86	if (use_fdi_mode && (port != PORT_E))
87		DRM_DEBUG_KMS("Programming port %c in FDI mode, this probably will not work.\n",
88		port_name(port));
89
90	for (i=0, reg=DDI_BUF_TRANS(port); i < DRM_ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
91		I915_WRITE(reg, ddi_translations[i]);
92		reg += 4;
93	}
94}
95
96/* Program DDI buffers translations for DP. By default, program ports A-D in DP
97 * mode and port E for FDI.
98 */
99void intel_prepare_ddi(struct drm_device *dev)
100{
101	int port;
102
103	if (IS_HASWELL(dev)) {
104		for (port = PORT_A; port < PORT_E; port++)
105			intel_prepare_ddi_buffers(dev, port, false);
106
107		/* DDI E is the suggested one to work in FDI mode, so program is as such by
108		 * default. It will have to be re-programmed in case a digital DP output
109		 * will be detected on it
110		 */
111		intel_prepare_ddi_buffers(dev, PORT_E, true);
112	}
113}
114
115static const long hsw_ddi_buf_ctl_values[] = {
116	DDI_BUF_EMP_400MV_0DB_HSW,
117	DDI_BUF_EMP_400MV_3_5DB_HSW,
118	DDI_BUF_EMP_400MV_6DB_HSW,
119	DDI_BUF_EMP_400MV_9_5DB_HSW,
120	DDI_BUF_EMP_600MV_0DB_HSW,
121	DDI_BUF_EMP_600MV_3_5DB_HSW,
122	DDI_BUF_EMP_600MV_6DB_HSW,
123	DDI_BUF_EMP_800MV_0DB_HSW,
124	DDI_BUF_EMP_800MV_3_5DB_HSW
125};
126
127
128/* Starting with Haswell, different DDI ports can work in FDI mode for
129 * connection to the PCH-located connectors. For this, it is necessary to train
130 * both the DDI port and PCH receiver for the desired DDI buffer settings.
131 *
132 * The recommended port to work in FDI mode is DDI E, which we use here. Also,
133 * please note that when FDI mode is active on DDI E, it shares 2 lines with
134 * DDI A (which is used for eDP)
135 */
136
137void hsw_fdi_link_train(struct drm_crtc *crtc)
138{
139	struct drm_device *dev = crtc->dev;
140	struct drm_i915_private *dev_priv = dev->dev_private;
141	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
142	int pipe = intel_crtc->pipe;
143	u32 reg, temp, i;
144
145	/* Configure CPU PLL, wait for warmup */
146	I915_WRITE(SPLL_CTL,
147			SPLL_PLL_ENABLE |
148			SPLL_PLL_FREQ_1350MHz |
149			SPLL_PLL_SCC);
150
151	/* Use SPLL to drive the output when in FDI mode */
152	I915_WRITE(PORT_CLK_SEL(PORT_E),
153			PORT_CLK_SEL_SPLL);
154	I915_WRITE(PIPE_CLK_SEL(pipe),
155			PIPE_CLK_SEL_PORT(PORT_E));
156
157	DELAY(20);
158
159	/* Start the training iterating through available voltages and emphasis */
160	for (i=0; i < DRM_ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
161		/* Configure DP_TP_CTL with auto-training */
162		I915_WRITE(DP_TP_CTL(PORT_E),
163					DP_TP_CTL_FDI_AUTOTRAIN |
164					DP_TP_CTL_ENHANCED_FRAME_ENABLE |
165					DP_TP_CTL_LINK_TRAIN_PAT1 |
166					DP_TP_CTL_ENABLE);
167
168		/* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
169		temp = I915_READ(DDI_BUF_CTL(PORT_E));
170		temp = (temp & ~DDI_BUF_EMP_MASK);
171		I915_WRITE(DDI_BUF_CTL(PORT_E),
172				temp |
173				DDI_BUF_CTL_ENABLE |
174				DDI_PORT_WIDTH_X2 |
175				hsw_ddi_buf_ctl_values[i]);
176
177		DELAY(600);
178
179		/* Enable CPU FDI Receiver with auto-training */
180		reg = FDI_RX_CTL(pipe);
181		I915_WRITE(reg,
182				I915_READ(reg) |
183					FDI_LINK_TRAIN_AUTO |
184					FDI_RX_ENABLE |
185					FDI_LINK_TRAIN_PATTERN_1_CPT |
186					FDI_RX_ENHANCE_FRAME_ENABLE |
187					FDI_PORT_WIDTH_2X_LPT |
188					FDI_RX_PLL_ENABLE);
189		POSTING_READ(reg);
190		DELAY(100);
191
192		temp = I915_READ(DP_TP_STATUS(PORT_E));
193		if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
194			DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
195
196			/* Enable normal pixel sending for FDI */
197			I915_WRITE(DP_TP_CTL(PORT_E),
198						DP_TP_CTL_FDI_AUTOTRAIN |
199						DP_TP_CTL_LINK_TRAIN_NORMAL |
200						DP_TP_CTL_ENHANCED_FRAME_ENABLE |
201						DP_TP_CTL_ENABLE);
202
203			/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */
204			temp = I915_READ(DDI_FUNC_CTL(pipe));
205			temp &= ~PIPE_DDI_PORT_MASK;
206			temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
207					PIPE_DDI_MODE_SELECT_FDI |
208					PIPE_DDI_FUNC_ENABLE |
209					PIPE_DDI_PORT_WIDTH_X2;
210			I915_WRITE(DDI_FUNC_CTL(pipe),
211					temp);
212			break;
213		} else {
214			DRM_ERROR("Error training BUF_CTL %d\n", i);
215
216			/* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
217			I915_WRITE(DP_TP_CTL(PORT_E),
218					I915_READ(DP_TP_CTL(PORT_E)) &
219						~DP_TP_CTL_ENABLE);
220			I915_WRITE(FDI_RX_CTL(pipe),
221					I915_READ(FDI_RX_CTL(pipe)) &
222						~FDI_RX_PLL_ENABLE);
223			continue;
224		}
225	}
226
227	DRM_DEBUG_KMS("FDI train done.\n");
228}
229
230/* For DDI connections, it is possible to support different outputs over the
231 * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by
232 * the time the output is detected what exactly is on the other end of it. This
233 * function aims at providing support for this detection and proper output
234 * configuration.
235 */
236void intel_ddi_init(struct drm_device *dev, enum port port)
237{
238	/* For now, we don't do any proper output detection and assume that we
239	 * handle HDMI only */
240
241	switch(port){
242	case PORT_A:
243		/* We don't handle eDP and DP yet */
244		DRM_DEBUG_DRIVER("Found digital output on DDI port A\n");
245		break;
246	/* Assume that the  ports B, C and D are working in HDMI mode for now */
247	case PORT_B:
248	case PORT_C:
249	case PORT_D:
250		intel_hdmi_init(dev, DDI_BUF_CTL(port));
251		break;
252	default:
253		DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n",
254				port);
255		break;
256	}
257}
258
259/* WRPLL clock dividers */
260struct wrpll_tmds_clock {
261	u32 clock;
262	u16 p;		/* Post divider */
263	u16 n2;		/* Feedback divider */
264	u16 r2;		/* Reference divider */
265};
266
267/* Table of matching values for WRPLL clocks programming for each frequency */
268static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
269	{19750,	38,	25,	18},
270	{20000,	48,	32,	18},
271	{21000,	36,	21,	15},
272	{21912,	42,	29,	17},
273	{22000,	36,	22,	15},
274	{23000,	36,	23,	15},
275	{23500,	40,	40,	23},
276	{23750,	26,	16,	14},
277	{23750,	26,	16,	14},
278	{24000,	36,	24,	15},
279	{25000,	36,	25,	15},
280	{25175,	26,	40,	33},
281	{25200,	30,	21,	15},
282	{26000,	36,	26,	15},
283	{27000,	30,	21,	14},
284	{27027,	18,	100,	111},
285	{27500,	30,	29,	19},
286	{28000,	34,	30,	17},
287	{28320,	26,	30,	22},
288	{28322,	32,	42,	25},
289	{28750,	24,	23,	18},
290	{29000,	30,	29,	18},
291	{29750,	32,	30,	17},
292	{30000,	30,	25,	15},
293	{30750,	30,	41,	24},
294	{31000,	30,	31,	18},
295	{31500,	30,	28,	16},
296	{32000,	30,	32,	18},
297	{32500,	28,	32,	19},
298	{33000,	24,	22,	15},
299	{34000,	28,	30,	17},
300	{35000,	26,	32,	19},
301	{35500,	24,	30,	19},
302	{36000,	26,	26,	15},
303	{36750,	26,	46,	26},
304	{37000,	24,	23,	14},
305	{37762,	22,	40,	26},
306	{37800,	20,	21,	15},
307	{38000,	24,	27,	16},
308	{38250,	24,	34,	20},
309	{39000,	24,	26,	15},
310	{40000,	24,	32,	18},
311	{40500,	20,	21,	14},
312	{40541,	22,	147,	89},
313	{40750,	18,	19,	14},
314	{41000,	16,	17,	14},
315	{41500,	22,	44,	26},
316	{41540,	22,	44,	26},
317	{42000,	18,	21,	15},
318	{42500,	22,	45,	26},
319	{43000,	20,	43,	27},
320	{43163,	20,	24,	15},
321	{44000,	18,	22,	15},
322	{44900,	20,	108,	65},
323	{45000,	20,	25,	15},
324	{45250,	20,	52,	31},
325	{46000,	18,	23,	15},
326	{46750,	20,	45,	26},
327	{47000,	20,	40,	23},
328	{48000,	18,	24,	15},
329	{49000,	18,	49,	30},
330	{49500,	16,	22,	15},
331	{50000,	18,	25,	15},
332	{50500,	18,	32,	19},
333	{51000,	18,	34,	20},
334	{52000,	18,	26,	15},
335	{52406,	14,	34,	25},
336	{53000,	16,	22,	14},
337	{54000,	16,	24,	15},
338	{54054,	16,	173,	108},
339	{54500,	14,	24,	17},
340	{55000,	12,	22,	18},
341	{56000,	14,	45,	31},
342	{56250,	16,	25,	15},
343	{56750,	14,	25,	17},
344	{57000,	16,	27,	16},
345	{58000,	16,	43,	25},
346	{58250,	16,	38,	22},
347	{58750,	16,	40,	23},
348	{59000,	14,	26,	17},
349	{59341,	14,	40,	26},
350	{59400,	16,	44,	25},
351	{60000,	16,	32,	18},
352	{60500,	12,	39,	29},
353	{61000,	14,	49,	31},
354	{62000,	14,	37,	23},
355	{62250,	14,	42,	26},
356	{63000,	12,	21,	15},
357	{63500,	14,	28,	17},
358	{64000,	12,	27,	19},
359	{65000,	14,	32,	19},
360	{65250,	12,	29,	20},
361	{65500,	12,	32,	22},
362	{66000,	12,	22,	15},
363	{66667,	14,	38,	22},
364	{66750,	10,	21,	17},
365	{67000,	14,	33,	19},
366	{67750,	14,	58,	33},
367	{68000,	14,	30,	17},
368	{68179,	14,	46,	26},
369	{68250,	14,	46,	26},
370	{69000,	12,	23,	15},
371	{70000,	12,	28,	18},
372	{71000,	12,	30,	19},
373	{72000,	12,	24,	15},
374	{73000,	10,	23,	17},
375	{74000,	12,	23,	14},
376	{74176,	8,	100,	91},
377	{74250,	10,	22,	16},
378	{74481,	12,	43,	26},
379	{74500,	10,	29,	21},
380	{75000,	12,	25,	15},
381	{75250,	10,	39,	28},
382	{76000,	12,	27,	16},
383	{77000,	12,	53,	31},
384	{78000,	12,	26,	15},
385	{78750,	12,	28,	16},
386	{79000,	10,	38,	26},
387	{79500,	10,	28,	19},
388	{80000,	12,	32,	18},
389	{81000,	10,	21,	14},
390	{81081,	6,	100,	111},
391	{81624,	8,	29,	24},
392	{82000,	8,	17,	14},
393	{83000,	10,	40,	26},
394	{83950,	10,	28,	18},
395	{84000,	10,	28,	18},
396	{84750,	6,	16,	17},
397	{85000,	6,	17,	18},
398	{85250,	10,	30,	19},
399	{85750,	10,	27,	17},
400	{86000,	10,	43,	27},
401	{87000,	10,	29,	18},
402	{88000,	10,	44,	27},
403	{88500,	10,	41,	25},
404	{89000,	10,	28,	17},
405	{89012,	6,	90,	91},
406	{89100,	10,	33,	20},
407	{90000,	10,	25,	15},
408	{91000,	10,	32,	19},
409	{92000,	10,	46,	27},
410	{93000,	10,	31,	18},
411	{94000,	10,	40,	23},
412	{94500,	10,	28,	16},
413	{95000,	10,	44,	25},
414	{95654,	10,	39,	22},
415	{95750,	10,	39,	22},
416	{96000,	10,	32,	18},
417	{97000,	8,	23,	16},
418	{97750,	8,	42,	29},
419	{98000,	8,	45,	31},
420	{99000,	8,	22,	15},
421	{99750,	8,	34,	23},
422	{100000,	6,	20,	18},
423	{100500,	6,	19,	17},
424	{101000,	6,	37,	33},
425	{101250,	8,	21,	14},
426	{102000,	6,	17,	15},
427	{102250,	6,	25,	22},
428	{103000,	8,	29,	19},
429	{104000,	8,	37,	24},
430	{105000,	8,	28,	18},
431	{106000,	8,	22,	14},
432	{107000,	8,	46,	29},
433	{107214,	8,	27,	17},
434	{108000,	8,	24,	15},
435	{108108,	8,	173,	108},
436	{109000,	6,	23,	19},
437	{109000,	6,	23,	19},
438	{110000,	6,	22,	18},
439	{110013,	6,	22,	18},
440	{110250,	8,	49,	30},
441	{110500,	8,	36,	22},
442	{111000,	8,	23,	14},
443	{111264,	8,	150,	91},
444	{111375,	8,	33,	20},
445	{112000,	8,	63,	38},
446	{112500,	8,	25,	15},
447	{113100,	8,	57,	34},
448	{113309,	8,	42,	25},
449	{114000,	8,	27,	16},
450	{115000,	6,	23,	18},
451	{116000,	8,	43,	25},
452	{117000,	8,	26,	15},
453	{117500,	8,	40,	23},
454	{118000,	6,	38,	29},
455	{119000,	8,	30,	17},
456	{119500,	8,	46,	26},
457	{119651,	8,	39,	22},
458	{120000,	8,	32,	18},
459	{121000,	6,	39,	29},
460	{121250,	6,	31,	23},
461	{121750,	6,	23,	17},
462	{122000,	6,	42,	31},
463	{122614,	6,	30,	22},
464	{123000,	6,	41,	30},
465	{123379,	6,	37,	27},
466	{124000,	6,	51,	37},
467	{125000,	6,	25,	18},
468	{125250,	4,	13,	14},
469	{125750,	4,	27,	29},
470	{126000,	6,	21,	15},
471	{127000,	6,	24,	17},
472	{127250,	6,	41,	29},
473	{128000,	6,	27,	19},
474	{129000,	6,	43,	30},
475	{129859,	4,	25,	26},
476	{130000,	6,	26,	18},
477	{130250,	6,	42,	29},
478	{131000,	6,	32,	22},
479	{131500,	6,	38,	26},
480	{131850,	6,	41,	28},
481	{132000,	6,	22,	15},
482	{132750,	6,	28,	19},
483	{133000,	6,	34,	23},
484	{133330,	6,	37,	25},
485	{134000,	6,	61,	41},
486	{135000,	6,	21,	14},
487	{135250,	6,	167,	111},
488	{136000,	6,	62,	41},
489	{137000,	6,	35,	23},
490	{138000,	6,	23,	15},
491	{138500,	6,	40,	26},
492	{138750,	6,	37,	24},
493	{139000,	6,	34,	22},
494	{139050,	6,	34,	22},
495	{139054,	6,	34,	22},
496	{140000,	6,	28,	18},
497	{141000,	6,	36,	23},
498	{141500,	6,	22,	14},
499	{142000,	6,	30,	19},
500	{143000,	6,	27,	17},
501	{143472,	4,	17,	16},
502	{144000,	6,	24,	15},
503	{145000,	6,	29,	18},
504	{146000,	6,	47,	29},
505	{146250,	6,	26,	16},
506	{147000,	6,	49,	30},
507	{147891,	6,	23,	14},
508	{148000,	6,	23,	14},
509	{148250,	6,	28,	17},
510	{148352,	4,	100,	91},
511	{148500,	6,	33,	20},
512	{149000,	6,	48,	29},
513	{150000,	6,	25,	15},
514	{151000,	4,	19,	17},
515	{152000,	6,	27,	16},
516	{152280,	6,	44,	26},
517	{153000,	6,	34,	20},
518	{154000,	6,	53,	31},
519	{155000,	6,	31,	18},
520	{155250,	6,	50,	29},
521	{155750,	6,	45,	26},
522	{156000,	6,	26,	15},
523	{157000,	6,	61,	35},
524	{157500,	6,	28,	16},
525	{158000,	6,	65,	37},
526	{158250,	6,	44,	25},
527	{159000,	6,	53,	30},
528	{159500,	6,	39,	22},
529	{160000,	6,	32,	18},
530	{161000,	4,	31,	26},
531	{162000,	4,	18,	15},
532	{162162,	4,	131,	109},
533	{162500,	4,	53,	44},
534	{163000,	4,	29,	24},
535	{164000,	4,	17,	14},
536	{165000,	4,	22,	18},
537	{166000,	4,	32,	26},
538	{167000,	4,	26,	21},
539	{168000,	4,	46,	37},
540	{169000,	4,	104,	83},
541	{169128,	4,	64,	51},
542	{169500,	4,	39,	31},
543	{170000,	4,	34,	27},
544	{171000,	4,	19,	15},
545	{172000,	4,	51,	40},
546	{172750,	4,	32,	25},
547	{172800,	4,	32,	25},
548	{173000,	4,	41,	32},
549	{174000,	4,	49,	38},
550	{174787,	4,	22,	17},
551	{175000,	4,	35,	27},
552	{176000,	4,	30,	23},
553	{177000,	4,	38,	29},
554	{178000,	4,	29,	22},
555	{178500,	4,	37,	28},
556	{179000,	4,	53,	40},
557	{179500,	4,	73,	55},
558	{180000,	4,	20,	15},
559	{181000,	4,	55,	41},
560	{182000,	4,	31,	23},
561	{183000,	4,	42,	31},
562	{184000,	4,	30,	22},
563	{184750,	4,	26,	19},
564	{185000,	4,	37,	27},
565	{186000,	4,	51,	37},
566	{187000,	4,	36,	26},
567	{188000,	4,	32,	23},
568	{189000,	4,	21,	15},
569	{190000,	4,	38,	27},
570	{190960,	4,	41,	29},
571	{191000,	4,	41,	29},
572	{192000,	4,	27,	19},
573	{192250,	4,	37,	26},
574	{193000,	4,	20,	14},
575	{193250,	4,	53,	37},
576	{194000,	4,	23,	16},
577	{194208,	4,	23,	16},
578	{195000,	4,	26,	18},
579	{196000,	4,	45,	31},
580	{197000,	4,	35,	24},
581	{197750,	4,	41,	28},
582	{198000,	4,	22,	15},
583	{198500,	4,	25,	17},
584	{199000,	4,	28,	19},
585	{200000,	4,	37,	25},
586	{201000,	4,	61,	41},
587	{202000,	4,	112,	75},
588	{202500,	4,	21,	14},
589	{203000,	4,	146,	97},
590	{204000,	4,	62,	41},
591	{204750,	4,	44,	29},
592	{205000,	4,	38,	25},
593	{206000,	4,	29,	19},
594	{207000,	4,	23,	15},
595	{207500,	4,	40,	26},
596	{208000,	4,	37,	24},
597	{208900,	4,	48,	31},
598	{209000,	4,	48,	31},
599	{209250,	4,	31,	20},
600	{210000,	4,	28,	18},
601	{211000,	4,	25,	16},
602	{212000,	4,	22,	14},
603	{213000,	4,	30,	19},
604	{213750,	4,	38,	24},
605	{214000,	4,	46,	29},
606	{214750,	4,	35,	22},
607	{215000,	4,	43,	27},
608	{216000,	4,	24,	15},
609	{217000,	4,	37,	23},
610	{218000,	4,	42,	26},
611	{218250,	4,	42,	26},
612	{218750,	4,	34,	21},
613	{219000,	4,	47,	29},
614	{219000,	4,	47,	29},
615	{220000,	4,	44,	27},
616	{220640,	4,	49,	30},
617	{220750,	4,	36,	22},
618	{221000,	4,	36,	22},
619	{222000,	4,	23,	14},
620	{222525,	4,	28,	17},
621	{222750,	4,	33,	20},
622	{227000,	4,	37,	22},
623	{230250,	4,	29,	17},
624	{233500,	4,	38,	22},
625	{235000,	4,	40,	23},
626	{238000,	4,	30,	17},
627	{241500,	2,	17,	19},
628	{245250,	2,	20,	22},
629	{247750,	2,	22,	24},
630	{253250,	2,	15,	16},
631	{256250,	2,	18,	19},
632	{262500,	2,	31,	32},
633	{267250,	2,	66,	67},
634	{268500,	2,	94,	95},
635	{270000,	2,	14,	14},
636	{272500,	2,	77,	76},
637	{273750,	2,	57,	56},
638	{280750,	2,	24,	23},
639	{281250,	2,	23,	22},
640	{286000,	2,	17,	16},
641	{291750,	2,	26,	24},
642	{296703,	2,	56,	51},
643	{297000,	2,	22,	20},
644	{298000,	2,	21,	19},
645};
646
647void intel_ddi_mode_set(struct drm_encoder *encoder,
648				struct drm_display_mode *mode,
649				struct drm_display_mode *adjusted_mode)
650{
651	struct drm_device *dev = encoder->dev;
652	struct drm_i915_private *dev_priv = dev->dev_private;
653	struct drm_crtc *crtc = encoder->crtc;
654	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
655	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
656	int port = intel_hdmi->ddi_port;
657	int pipe = intel_crtc->pipe;
658	int p, n2, r2, valid=0;
659	u32 temp, i;
660
661	/* On Haswell, we need to enable the clocks and prepare DDI function to
662	 * work in HDMI mode for this pipe.
663	 */
664	DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
665
666	for (i=0; i < DRM_ARRAY_SIZE(wrpll_tmds_clock_table); i++) {
667		if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) {
668			p = wrpll_tmds_clock_table[i].p;
669			n2 = wrpll_tmds_clock_table[i].n2;
670			r2 = wrpll_tmds_clock_table[i].r2;
671
672			DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n",
673					crtc->mode.clock,
674					p, n2, r2);
675
676			valid = 1;
677			break;
678		}
679	}
680
681	if (!valid) {
682		DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n",
683				crtc->mode.clock);
684		return;
685	}
686
687	/* Enable LCPLL if disabled */
688	temp = I915_READ(LCPLL_CTL);
689	if (temp & LCPLL_PLL_DISABLE)
690		I915_WRITE(LCPLL_CTL,
691				temp & ~LCPLL_PLL_DISABLE);
692
693	/* Configure WR PLL 1, program the correct divider values for
694	 * the desired frequency and wait for warmup */
695	I915_WRITE(WRPLL_CTL1,
696			WRPLL_PLL_ENABLE |
697			WRPLL_PLL_SELECT_LCPLL_2700 |
698			WRPLL_DIVIDER_REFERENCE(r2) |
699			WRPLL_DIVIDER_FEEDBACK(n2) |
700			WRPLL_DIVIDER_POST(p));
701
702	DELAY(20);
703
704	/* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use
705	 * this port for connection.
706	 */
707	I915_WRITE(PORT_CLK_SEL(port),
708			PORT_CLK_SEL_WRPLL1);
709	I915_WRITE(PIPE_CLK_SEL(pipe),
710			PIPE_CLK_SEL_PORT(port));
711
712	DELAY(20);
713
714	if (intel_hdmi->has_audio) {
715		/* Proper support for digital audio needs a new logic and a new set
716		 * of registers, so we leave it for future patch bombing.
717		 */
718		DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n",
719				 pipe_name(intel_crtc->pipe));
720	}
721
722	/* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
723	temp = I915_READ(DDI_FUNC_CTL(pipe));
724	temp &= ~PIPE_DDI_PORT_MASK;
725	temp &= ~PIPE_DDI_BPC_12;
726	temp |= PIPE_DDI_SELECT_PORT(port) |
727			PIPE_DDI_MODE_SELECT_HDMI |
728			((intel_crtc->bpp > 24) ?
729				PIPE_DDI_BPC_12 :
730				PIPE_DDI_BPC_8) |
731			PIPE_DDI_FUNC_ENABLE;
732
733	I915_WRITE(DDI_FUNC_CTL(pipe), temp);
734
735	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
736	intel_hdmi_set_spd_infoframe(encoder);
737}
738
739void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
740{
741	struct drm_device *dev = encoder->dev;
742	struct drm_i915_private *dev_priv = dev->dev_private;
743	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
744	int port = intel_hdmi->ddi_port;
745	u32 temp;
746
747	temp = I915_READ(DDI_BUF_CTL(port));
748
749	if (mode != DRM_MODE_DPMS_ON) {
750		temp &= ~DDI_BUF_CTL_ENABLE;
751	} else {
752		temp |= DDI_BUF_CTL_ENABLE;
753	}
754
755	/* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
756	 * and swing/emphasis values are ignored so nothing special needs
757	 * to be done besides enabling the port.
758	 */
759	I915_WRITE(DDI_BUF_CTL(port),
760			temp);
761}
762