intel_tv.c revision d5627663f2088fa4be447fdcfd52bcb233448d85
1/*
2 * Copyright © 2006-2008 Intel Corporation
3 *   Jesse Barnes <jesse.barnes@intel.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Eric Anholt <eric@anholt.net>
26 *
27 */
28
29/** @file
30 * Integrated TV-out support for the 915GM and 945GM.
31 */
32
33#include "drmP.h"
34#include "drm.h"
35#include "drm_crtc.h"
36#include "drm_edid.h"
37#include "intel_drv.h"
38#include "i915_drm.h"
39#include "i915_drv.h"
40
41enum tv_margin {
42	TV_MARGIN_LEFT, TV_MARGIN_TOP,
43	TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
44};
45
46/** Private structure for the integrated TV support */
47struct intel_tv {
48	struct intel_encoder base;
49
50	int type;
51	const char *tv_format;
52	int margin[4];
53	u32 save_TV_H_CTL_1;
54	u32 save_TV_H_CTL_2;
55	u32 save_TV_H_CTL_3;
56	u32 save_TV_V_CTL_1;
57	u32 save_TV_V_CTL_2;
58	u32 save_TV_V_CTL_3;
59	u32 save_TV_V_CTL_4;
60	u32 save_TV_V_CTL_5;
61	u32 save_TV_V_CTL_6;
62	u32 save_TV_V_CTL_7;
63	u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
64
65	u32 save_TV_CSC_Y;
66	u32 save_TV_CSC_Y2;
67	u32 save_TV_CSC_U;
68	u32 save_TV_CSC_U2;
69	u32 save_TV_CSC_V;
70	u32 save_TV_CSC_V2;
71	u32 save_TV_CLR_KNOBS;
72	u32 save_TV_CLR_LEVEL;
73	u32 save_TV_WIN_POS;
74	u32 save_TV_WIN_SIZE;
75	u32 save_TV_FILTER_CTL_1;
76	u32 save_TV_FILTER_CTL_2;
77	u32 save_TV_FILTER_CTL_3;
78
79	u32 save_TV_H_LUMA[60];
80	u32 save_TV_H_CHROMA[60];
81	u32 save_TV_V_LUMA[43];
82	u32 save_TV_V_CHROMA[43];
83
84	u32 save_TV_DAC;
85	u32 save_TV_CTL;
86};
87
88struct video_levels {
89	int blank, black, burst;
90};
91
92struct color_conversion {
93	u16 ry, gy, by, ay;
94	u16 ru, gu, bu, au;
95	u16 rv, gv, bv, av;
96};
97
98static const u32 filter_table[] = {
99	0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
100	0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
101	0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
102	0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
103	0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
104	0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
105	0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
106	0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
107	0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
108	0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
109	0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
110	0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
111	0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
112	0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
113	0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
114	0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
115	0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
116	0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
117	0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
118	0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
119	0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
120	0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
121	0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
122	0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
123	0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
124	0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
125	0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
126	0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
127	0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
128	0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
129	0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
130	0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
131	0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
132	0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
133	0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
134	0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
135	0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
136	0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
137	0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
138	0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
139	0x28003100, 0x28002F00, 0x00003100, 0x36403000,
140	0x2D002CC0, 0x30003640, 0x2D0036C0,
141	0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
142	0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
143	0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
144	0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
145	0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
146	0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
147	0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
148	0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
149	0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
150	0x28003100, 0x28002F00, 0x00003100,
151};
152
153/*
154 * Color conversion values have 3 separate fixed point formats:
155 *
156 * 10 bit fields (ay, au)
157 *   1.9 fixed point (b.bbbbbbbbb)
158 * 11 bit fields (ry, by, ru, gu, gv)
159 *   exp.mantissa (ee.mmmmmmmmm)
160 *   ee = 00 = 10^-1 (0.mmmmmmmmm)
161 *   ee = 01 = 10^-2 (0.0mmmmmmmmm)
162 *   ee = 10 = 10^-3 (0.00mmmmmmmmm)
163 *   ee = 11 = 10^-4 (0.000mmmmmmmmm)
164 * 12 bit fields (gy, rv, bu)
165 *   exp.mantissa (eee.mmmmmmmmm)
166 *   eee = 000 = 10^-1 (0.mmmmmmmmm)
167 *   eee = 001 = 10^-2 (0.0mmmmmmmmm)
168 *   eee = 010 = 10^-3 (0.00mmmmmmmmm)
169 *   eee = 011 = 10^-4 (0.000mmmmmmmmm)
170 *   eee = 100 = reserved
171 *   eee = 101 = reserved
172 *   eee = 110 = reserved
173 *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
174 *
175 * Saturation and contrast are 8 bits, with their own representation:
176 * 8 bit field (saturation, contrast)
177 *   exp.mantissa (ee.mmmmmm)
178 *   ee = 00 = 10^-1 (0.mmmmmm)
179 *   ee = 01 = 10^0 (m.mmmmm)
180 *   ee = 10 = 10^1 (mm.mmmm)
181 *   ee = 11 = 10^2 (mmm.mmm)
182 *
183 * Simple conversion function:
184 *
185 * static u32
186 * float_to_csc_11(float f)
187 * {
188 *     u32 exp;
189 *     u32 mant;
190 *     u32 ret;
191 *
192 *     if (f < 0)
193 *         f = -f;
194 *
195 *     if (f >= 1) {
196 *         exp = 0x7;
197 * 	   mant = 1 << 8;
198 *     } else {
199 *         for (exp = 0; exp < 3 && f < 0.5; exp++)
200 * 	       f *= 2.0;
201 *         mant = (f * (1 << 9) + 0.5);
202 *         if (mant >= (1 << 9))
203 *             mant = (1 << 9) - 1;
204 *     }
205 *     ret = (exp << 9) | mant;
206 *     return ret;
207 * }
208 */
209
210/*
211 * Behold, magic numbers!  If we plant them they might grow a big
212 * s-video cable to the sky... or something.
213 *
214 * Pre-converted to appropriate hex value.
215 */
216
217/*
218 * PAL & NTSC values for composite & s-video connections
219 */
220static const struct color_conversion ntsc_m_csc_composite = {
221	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
222	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
223	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
224};
225
226static const struct video_levels ntsc_m_levels_composite = {
227	.blank = 225, .black = 267, .burst = 113,
228};
229
230static const struct color_conversion ntsc_m_csc_svideo = {
231	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
232	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
233	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
234};
235
236static const struct video_levels ntsc_m_levels_svideo = {
237	.blank = 266, .black = 316, .burst = 133,
238};
239
240static const struct color_conversion ntsc_j_csc_composite = {
241	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
242	.ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
243	.rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
244};
245
246static const struct video_levels ntsc_j_levels_composite = {
247	.blank = 225, .black = 225, .burst = 113,
248};
249
250static const struct color_conversion ntsc_j_csc_svideo = {
251	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
252	.ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
253	.rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
254};
255
256static const struct video_levels ntsc_j_levels_svideo = {
257	.blank = 266, .black = 266, .burst = 133,
258};
259
260static const struct color_conversion pal_csc_composite = {
261	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
262	.ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
263	.rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
264};
265
266static const struct video_levels pal_levels_composite = {
267	.blank = 237, .black = 237, .burst = 118,
268};
269
270static const struct color_conversion pal_csc_svideo = {
271	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
272	.ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
273	.rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
274};
275
276static const struct video_levels pal_levels_svideo = {
277	.blank = 280, .black = 280, .burst = 139,
278};
279
280static const struct color_conversion pal_m_csc_composite = {
281	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
282	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
283	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
284};
285
286static const struct video_levels pal_m_levels_composite = {
287	.blank = 225, .black = 267, .burst = 113,
288};
289
290static const struct color_conversion pal_m_csc_svideo = {
291	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
292	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
293	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
294};
295
296static const struct video_levels pal_m_levels_svideo = {
297	.blank = 266, .black = 316, .burst = 133,
298};
299
300static const struct color_conversion pal_n_csc_composite = {
301	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
302	.ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
303	.rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
304};
305
306static const struct video_levels pal_n_levels_composite = {
307	.blank = 225, .black = 267, .burst = 118,
308};
309
310static const struct color_conversion pal_n_csc_svideo = {
311	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
312	.ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
313	.rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
314};
315
316static const struct video_levels pal_n_levels_svideo = {
317	.blank = 266, .black = 316, .burst = 139,
318};
319
320/*
321 * Component connections
322 */
323static const struct color_conversion sdtv_csc_yprpb = {
324	.ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
325	.ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
326	.rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
327};
328
329static const struct color_conversion sdtv_csc_rgb = {
330	.ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
331	.ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
332	.rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
333};
334
335static const struct color_conversion hdtv_csc_yprpb = {
336	.ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
337	.ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
338	.rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
339};
340
341static const struct color_conversion hdtv_csc_rgb = {
342	.ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
343	.ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
344	.rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
345};
346
347static const struct video_levels component_levels = {
348	.blank = 279, .black = 279, .burst = 0,
349};
350
351
352struct tv_mode {
353	const char *name;
354	int clock;
355	int refresh; /* in millihertz (for precision) */
356	u32 oversample;
357	int hsync_end, hblank_start, hblank_end, htotal;
358	bool progressive, trilevel_sync, component_only;
359	int vsync_start_f1, vsync_start_f2, vsync_len;
360	bool veq_ena;
361	int veq_start_f1, veq_start_f2, veq_len;
362	int vi_end_f1, vi_end_f2, nbr_end;
363	bool burst_ena;
364	int hburst_start, hburst_len;
365	int vburst_start_f1, vburst_end_f1;
366	int vburst_start_f2, vburst_end_f2;
367	int vburst_start_f3, vburst_end_f3;
368	int vburst_start_f4, vburst_end_f4;
369	/*
370	 * subcarrier programming
371	 */
372	int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
373	u32 sc_reset;
374	bool pal_burst;
375	/*
376	 * blank/black levels
377	 */
378	const struct video_levels *composite_levels, *svideo_levels;
379	const struct color_conversion *composite_color, *svideo_color;
380	const u32 *filter_table;
381	int max_srcw;
382};
383
384
385/*
386 * Sub carrier DDA
387 *
388 *  I think this works as follows:
389 *
390 *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
391 *
392 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
393 *
394 * So,
395 *  dda1_ideal = subcarrier/pixel * 4096
396 *  dda1_inc = floor (dda1_ideal)
397 *  dda2 = dda1_ideal - dda1_inc
398 *
399 *  then pick a ratio for dda2 that gives the closest approximation. If
400 *  you can't get close enough, you can play with dda3 as well. This
401 *  seems likely to happen when dda2 is small as the jumps would be larger
402 *
403 * To invert this,
404 *
405 *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
406 *
407 * The constants below were all computed using a 107.520MHz clock
408 */
409
410/**
411 * Register programming values for TV modes.
412 *
413 * These values account for -1s required.
414 */
415
416static const struct tv_mode tv_modes[] = {
417	{
418		.name		= "NTSC-M",
419		.clock		= 108000,
420		.refresh	= 29970,
421		.oversample	= TV_OVERSAMPLE_8X,
422		.component_only = 0,
423		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
424
425		.hsync_end	= 64,		    .hblank_end		= 124,
426		.hblank_start	= 836,		    .htotal		= 857,
427
428		.progressive	= false,	    .trilevel_sync = false,
429
430		.vsync_start_f1	= 6,		    .vsync_start_f2	= 7,
431		.vsync_len	= 6,
432
433		.veq_ena	= true,		    .veq_start_f1    	= 0,
434		.veq_start_f2	= 1,		    .veq_len		= 18,
435
436		.vi_end_f1	= 20,		    .vi_end_f2		= 21,
437		.nbr_end	= 240,
438
439		.burst_ena	= true,
440		.hburst_start	= 72,		    .hburst_len		= 34,
441		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240,
442		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240,
443		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,
444		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240,
445
446		/* desired 3.5800000 actual 3.5800000 clock 107.52 */
447		.dda1_inc	=    135,
448		.dda2_inc	=  20800,	    .dda2_size		=  27456,
449		.dda3_inc	=      0,	    .dda3_size		=      0,
450		.sc_reset	= TV_SC_RESET_EVERY_4,
451		.pal_burst	= false,
452
453		.composite_levels = &ntsc_m_levels_composite,
454		.composite_color = &ntsc_m_csc_composite,
455		.svideo_levels  = &ntsc_m_levels_svideo,
456		.svideo_color = &ntsc_m_csc_svideo,
457
458		.filter_table = filter_table,
459	},
460	{
461		.name		= "NTSC-443",
462		.clock		= 108000,
463		.refresh	= 29970,
464		.oversample	= TV_OVERSAMPLE_8X,
465		.component_only = 0,
466		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
467		.hsync_end	= 64,		    .hblank_end		= 124,
468		.hblank_start	= 836,		    .htotal		= 857,
469
470		.progressive	= false,	    .trilevel_sync = false,
471
472		.vsync_start_f1 = 6,		    .vsync_start_f2	= 7,
473		.vsync_len	= 6,
474
475		.veq_ena	= true,		    .veq_start_f1    	= 0,
476		.veq_start_f2	= 1,		    .veq_len		= 18,
477
478		.vi_end_f1	= 20,		    .vi_end_f2		= 21,
479		.nbr_end	= 240,
480
481		.burst_ena	= true,
482		.hburst_start	= 72,		    .hburst_len		= 34,
483		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240,
484		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240,
485		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,
486		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240,
487
488		/* desired 4.4336180 actual 4.4336180 clock 107.52 */
489		.dda1_inc       =    168,
490		.dda2_inc       =   4093,       .dda2_size      =  27456,
491		.dda3_inc       =    310,       .dda3_size      =    525,
492		.sc_reset   = TV_SC_RESET_NEVER,
493		.pal_burst  = false,
494
495		.composite_levels = &ntsc_m_levels_composite,
496		.composite_color = &ntsc_m_csc_composite,
497		.svideo_levels  = &ntsc_m_levels_svideo,
498		.svideo_color = &ntsc_m_csc_svideo,
499
500		.filter_table = filter_table,
501	},
502	{
503		.name		= "NTSC-J",
504		.clock		= 108000,
505		.refresh	= 29970,
506		.oversample	= TV_OVERSAMPLE_8X,
507		.component_only = 0,
508
509		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
510		.hsync_end	= 64,		    .hblank_end		= 124,
511		.hblank_start = 836,	    .htotal		= 857,
512
513		.progressive	= false,    .trilevel_sync = false,
514
515		.vsync_start_f1	= 6,	    .vsync_start_f2	= 7,
516		.vsync_len	= 6,
517
518		.veq_ena	= true,		    .veq_start_f1    	= 0,
519		.veq_start_f2 = 1,	    .veq_len		= 18,
520
521		.vi_end_f1	= 20,		    .vi_end_f2		= 21,
522		.nbr_end	= 240,
523
524		.burst_ena	= true,
525		.hburst_start	= 72,		    .hburst_len		= 34,
526		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240,
527		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240,
528		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,
529		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240,
530
531		/* desired 3.5800000 actual 3.5800000 clock 107.52 */
532		.dda1_inc	=    135,
533		.dda2_inc	=  20800,	    .dda2_size		=  27456,
534		.dda3_inc	=      0,	    .dda3_size		=      0,
535		.sc_reset	= TV_SC_RESET_EVERY_4,
536		.pal_burst	= false,
537
538		.composite_levels = &ntsc_j_levels_composite,
539		.composite_color = &ntsc_j_csc_composite,
540		.svideo_levels  = &ntsc_j_levels_svideo,
541		.svideo_color = &ntsc_j_csc_svideo,
542
543		.filter_table = filter_table,
544	},
545	{
546		.name		= "PAL-M",
547		.clock		= 108000,
548		.refresh	= 29970,
549		.oversample	= TV_OVERSAMPLE_8X,
550		.component_only = 0,
551
552		/* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
553		.hsync_end	= 64,		  .hblank_end		= 124,
554		.hblank_start = 836,	  .htotal		= 857,
555
556		.progressive	= false,	    .trilevel_sync = false,
557
558		.vsync_start_f1	= 6,		    .vsync_start_f2	= 7,
559		.vsync_len	= 6,
560
561		.veq_ena	= true,		    .veq_start_f1    	= 0,
562		.veq_start_f2	= 1,		    .veq_len		= 18,
563
564		.vi_end_f1	= 20,		    .vi_end_f2		= 21,
565		.nbr_end	= 240,
566
567		.burst_ena	= true,
568		.hburst_start	= 72,		    .hburst_len		= 34,
569		.vburst_start_f1 = 9,		    .vburst_end_f1	= 240,
570		.vburst_start_f2 = 10,		    .vburst_end_f2	= 240,
571		.vburst_start_f3 = 9,		    .vburst_end_f3	= 240,
572		.vburst_start_f4 = 10,		    .vburst_end_f4	= 240,
573
574		/* desired 3.5800000 actual 3.5800000 clock 107.52 */
575		.dda1_inc	=    135,
576		.dda2_inc	=  16704,	    .dda2_size		=  27456,
577		.dda3_inc	=      0,	    .dda3_size		=      0,
578		.sc_reset	= TV_SC_RESET_EVERY_8,
579		.pal_burst  = true,
580
581		.composite_levels = &pal_m_levels_composite,
582		.composite_color = &pal_m_csc_composite,
583		.svideo_levels  = &pal_m_levels_svideo,
584		.svideo_color = &pal_m_csc_svideo,
585
586		.filter_table = filter_table,
587	},
588	{
589		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
590		.name	    = "PAL-N",
591		.clock		= 108000,
592		.refresh	= 25000,
593		.oversample	= TV_OVERSAMPLE_8X,
594		.component_only = 0,
595
596		.hsync_end	= 64,		    .hblank_end		= 128,
597		.hblank_start = 844,	    .htotal		= 863,
598
599		.progressive  = false,    .trilevel_sync = false,
600
601
602		.vsync_start_f1	= 6,	   .vsync_start_f2	= 7,
603		.vsync_len	= 6,
604
605		.veq_ena	= true,		    .veq_start_f1    	= 0,
606		.veq_start_f2	= 1,		    .veq_len		= 18,
607
608		.vi_end_f1	= 24,		    .vi_end_f2		= 25,
609		.nbr_end	= 286,
610
611		.burst_ena	= true,
612		.hburst_start = 73,	    	    .hburst_len		= 34,
613		.vburst_start_f1 = 8,	    .vburst_end_f1	= 285,
614		.vburst_start_f2 = 8,	    .vburst_end_f2	= 286,
615		.vburst_start_f3 = 9,	    .vburst_end_f3	= 286,
616		.vburst_start_f4 = 9,	    .vburst_end_f4	= 285,
617
618
619		/* desired 4.4336180 actual 4.4336180 clock 107.52 */
620		.dda1_inc       =    135,
621		.dda2_inc       =  23578,       .dda2_size      =  27648,
622		.dda3_inc       =    134,       .dda3_size      =    625,
623		.sc_reset   = TV_SC_RESET_EVERY_8,
624		.pal_burst  = true,
625
626		.composite_levels = &pal_n_levels_composite,
627		.composite_color = &pal_n_csc_composite,
628		.svideo_levels  = &pal_n_levels_svideo,
629		.svideo_color = &pal_n_csc_svideo,
630
631		.filter_table = filter_table,
632	},
633	{
634		/* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
635		.name	    = "PAL",
636		.clock		= 108000,
637		.refresh	= 25000,
638		.oversample	= TV_OVERSAMPLE_8X,
639		.component_only = 0,
640
641		.hsync_end	= 64,		    .hblank_end		= 142,
642		.hblank_start	= 844,	    .htotal		= 863,
643
644		.progressive	= false,    .trilevel_sync = false,
645
646		.vsync_start_f1	= 5,	    .vsync_start_f2	= 6,
647		.vsync_len	= 5,
648
649		.veq_ena	= true,		    .veq_start_f1    	= 0,
650		.veq_start_f2	= 1,	    .veq_len		= 15,
651
652		.vi_end_f1	= 24,		    .vi_end_f2		= 25,
653		.nbr_end	= 286,
654
655		.burst_ena	= true,
656		.hburst_start	= 73,		    .hburst_len		= 32,
657		.vburst_start_f1 = 8,		    .vburst_end_f1	= 285,
658		.vburst_start_f2 = 8,		    .vburst_end_f2	= 286,
659		.vburst_start_f3 = 9,		    .vburst_end_f3	= 286,
660		.vburst_start_f4 = 9,		    .vburst_end_f4	= 285,
661
662		/* desired 4.4336180 actual 4.4336180 clock 107.52 */
663		.dda1_inc       =    168,
664		.dda2_inc       =   4122,       .dda2_size      =  27648,
665		.dda3_inc       =     67,       .dda3_size      =    625,
666		.sc_reset   = TV_SC_RESET_EVERY_8,
667		.pal_burst  = true,
668
669		.composite_levels = &pal_levels_composite,
670		.composite_color = &pal_csc_composite,
671		.svideo_levels  = &pal_levels_svideo,
672		.svideo_color = &pal_csc_svideo,
673
674		.filter_table = filter_table,
675	},
676	{
677		.name       = "480p@59.94Hz",
678		.clock 	= 107520,
679		.refresh	= 59940,
680		.oversample     = TV_OVERSAMPLE_4X,
681		.component_only = 1,
682
683		.hsync_end      = 64,               .hblank_end         = 122,
684		.hblank_start   = 842,              .htotal             = 857,
685
686		.progressive    = true,.trilevel_sync = false,
687
688		.vsync_start_f1 = 12,               .vsync_start_f2     = 12,
689		.vsync_len      = 12,
690
691		.veq_ena        = false,
692
693		.vi_end_f1      = 44,               .vi_end_f2          = 44,
694		.nbr_end        = 479,
695
696		.burst_ena      = false,
697
698		.filter_table = filter_table,
699	},
700	{
701		.name       = "480p@60Hz",
702		.clock 	= 107520,
703		.refresh	= 60000,
704		.oversample     = TV_OVERSAMPLE_4X,
705		.component_only = 1,
706
707		.hsync_end      = 64,               .hblank_end         = 122,
708		.hblank_start   = 842,              .htotal             = 856,
709
710		.progressive    = true,.trilevel_sync = false,
711
712		.vsync_start_f1 = 12,               .vsync_start_f2     = 12,
713		.vsync_len      = 12,
714
715		.veq_ena        = false,
716
717		.vi_end_f1      = 44,               .vi_end_f2          = 44,
718		.nbr_end        = 479,
719
720		.burst_ena      = false,
721
722		.filter_table = filter_table,
723	},
724	{
725		.name       = "576p",
726		.clock 	= 107520,
727		.refresh	= 50000,
728		.oversample     = TV_OVERSAMPLE_4X,
729		.component_only = 1,
730
731		.hsync_end      = 64,               .hblank_end         = 139,
732		.hblank_start   = 859,              .htotal             = 863,
733
734		.progressive    = true,		.trilevel_sync = false,
735
736		.vsync_start_f1 = 10,               .vsync_start_f2     = 10,
737		.vsync_len      = 10,
738
739		.veq_ena        = false,
740
741		.vi_end_f1      = 48,               .vi_end_f2          = 48,
742		.nbr_end        = 575,
743
744		.burst_ena      = false,
745
746		.filter_table = filter_table,
747	},
748	{
749		.name       = "720p@60Hz",
750		.clock		= 148800,
751		.refresh	= 60000,
752		.oversample     = TV_OVERSAMPLE_2X,
753		.component_only = 1,
754
755		.hsync_end      = 80,               .hblank_end         = 300,
756		.hblank_start   = 1580,             .htotal             = 1649,
757
758		.progressive    = true, 	    .trilevel_sync = true,
759
760		.vsync_start_f1 = 10,               .vsync_start_f2     = 10,
761		.vsync_len      = 10,
762
763		.veq_ena        = false,
764
765		.vi_end_f1      = 29,               .vi_end_f2          = 29,
766		.nbr_end        = 719,
767
768		.burst_ena      = false,
769
770		.filter_table = filter_table,
771	},
772	{
773		.name       = "720p@59.94Hz",
774		.clock		= 148800,
775		.refresh	= 59940,
776		.oversample     = TV_OVERSAMPLE_2X,
777		.component_only = 1,
778
779		.hsync_end      = 80,               .hblank_end         = 300,
780		.hblank_start   = 1580,             .htotal             = 1651,
781
782		.progressive    = true, 	    .trilevel_sync = true,
783
784		.vsync_start_f1 = 10,               .vsync_start_f2     = 10,
785		.vsync_len      = 10,
786
787		.veq_ena        = false,
788
789		.vi_end_f1      = 29,               .vi_end_f2          = 29,
790		.nbr_end        = 719,
791
792		.burst_ena      = false,
793
794		.filter_table = filter_table,
795	},
796	{
797		.name       = "720p@50Hz",
798		.clock		= 148800,
799		.refresh	= 50000,
800		.oversample     = TV_OVERSAMPLE_2X,
801		.component_only = 1,
802
803		.hsync_end      = 80,               .hblank_end         = 300,
804		.hblank_start   = 1580,             .htotal             = 1979,
805
806		.progressive    = true, 	        .trilevel_sync = true,
807
808		.vsync_start_f1 = 10,               .vsync_start_f2     = 10,
809		.vsync_len      = 10,
810
811		.veq_ena        = false,
812
813		.vi_end_f1      = 29,               .vi_end_f2          = 29,
814		.nbr_end        = 719,
815
816		.burst_ena      = false,
817
818		.filter_table = filter_table,
819		.max_srcw = 800
820	},
821	{
822		.name       = "1080i@50Hz",
823		.clock		= 148800,
824		.refresh	= 25000,
825		.oversample     = TV_OVERSAMPLE_2X,
826		.component_only = 1,
827
828		.hsync_end      = 88,               .hblank_end         = 235,
829		.hblank_start   = 2155,             .htotal             = 2639,
830
831		.progressive    = false, 	    .trilevel_sync = true,
832
833		.vsync_start_f1 = 4,              .vsync_start_f2     = 5,
834		.vsync_len      = 10,
835
836		.veq_ena	= true,		    .veq_start_f1    	= 4,
837		.veq_start_f2   = 4,	    .veq_len		= 10,
838
839
840		.vi_end_f1      = 21,           .vi_end_f2          = 22,
841		.nbr_end        = 539,
842
843		.burst_ena      = false,
844
845		.filter_table = filter_table,
846	},
847	{
848		.name       = "1080i@60Hz",
849		.clock		= 148800,
850		.refresh	= 30000,
851		.oversample     = TV_OVERSAMPLE_2X,
852		.component_only = 1,
853
854		.hsync_end      = 88,               .hblank_end         = 235,
855		.hblank_start   = 2155,             .htotal             = 2199,
856
857		.progressive    = false, 	    .trilevel_sync = true,
858
859		.vsync_start_f1 = 4,               .vsync_start_f2     = 5,
860		.vsync_len      = 10,
861
862		.veq_ena	= true,		    .veq_start_f1    	= 4,
863		.veq_start_f2	= 4,		    .veq_len		= 10,
864
865
866		.vi_end_f1      = 21,               .vi_end_f2          = 22,
867		.nbr_end        = 539,
868
869		.burst_ena      = false,
870
871		.filter_table = filter_table,
872	},
873	{
874		.name       = "1080i@59.94Hz",
875		.clock		= 148800,
876		.refresh	= 29970,
877		.oversample     = TV_OVERSAMPLE_2X,
878		.component_only = 1,
879
880		.hsync_end      = 88,               .hblank_end         = 235,
881		.hblank_start   = 2155,             .htotal             = 2201,
882
883		.progressive    = false, 	    .trilevel_sync = true,
884
885		.vsync_start_f1 = 4,            .vsync_start_f2    = 5,
886		.vsync_len      = 10,
887
888		.veq_ena	= true,		    .veq_start_f1	= 4,
889		.veq_start_f2 = 4,	    	    .veq_len = 10,
890
891
892		.vi_end_f1      = 21,           .vi_end_f2         	= 22,
893		.nbr_end        = 539,
894
895		.burst_ena      = false,
896
897		.filter_table = filter_table,
898	},
899};
900
901static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
902{
903	return container_of(encoder, struct intel_tv, base.base);
904}
905
906static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
907{
908	return container_of(intel_attached_encoder(connector),
909			    struct intel_tv,
910			    base);
911}
912
913static void
914intel_tv_dpms(struct drm_encoder *encoder, int mode)
915{
916	struct drm_device *dev = encoder->dev;
917	struct drm_i915_private *dev_priv = dev->dev_private;
918
919	switch(mode) {
920	case DRM_MODE_DPMS_ON:
921		I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
922		break;
923	case DRM_MODE_DPMS_STANDBY:
924	case DRM_MODE_DPMS_SUSPEND:
925	case DRM_MODE_DPMS_OFF:
926		I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
927		break;
928	}
929}
930
931static const struct tv_mode *
932intel_tv_mode_lookup(const char *tv_format)
933{
934	int i;
935
936	for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
937		const struct tv_mode *tv_mode = &tv_modes[i];
938
939		if (!strcmp(tv_format, tv_mode->name))
940			return tv_mode;
941	}
942	return NULL;
943}
944
945static const struct tv_mode *
946intel_tv_mode_find(struct intel_tv *intel_tv)
947{
948	return intel_tv_mode_lookup(intel_tv->tv_format);
949}
950
951static enum drm_mode_status
952intel_tv_mode_valid(struct drm_connector *connector,
953		    struct drm_display_mode *mode)
954{
955	struct intel_tv *intel_tv = intel_attached_tv(connector);
956	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
957
958	/* Ensure TV refresh is close to desired refresh */
959	if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
960				< 1000)
961		return MODE_OK;
962
963	return MODE_CLOCK_RANGE;
964}
965
966
967static bool
968intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
969		    struct drm_display_mode *adjusted_mode)
970{
971	struct drm_device *dev = encoder->dev;
972	struct drm_mode_config *drm_config = &dev->mode_config;
973	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
974	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
975	struct drm_encoder *other_encoder;
976
977	if (!tv_mode)
978		return false;
979
980	/* FIXME: lock encoder list */
981	list_for_each_entry(other_encoder, &drm_config->encoder_list, head) {
982		if (other_encoder != encoder &&
983		    other_encoder->crtc == encoder->crtc)
984			return false;
985	}
986
987	adjusted_mode->clock = tv_mode->clock;
988	return true;
989}
990
991static void
992intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
993		  struct drm_display_mode *adjusted_mode)
994{
995	struct drm_device *dev = encoder->dev;
996	struct drm_i915_private *dev_priv = dev->dev_private;
997	struct drm_crtc *crtc = encoder->crtc;
998	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
999	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
1000	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1001	u32 tv_ctl;
1002	u32 hctl1, hctl2, hctl3;
1003	u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1004	u32 scctl1, scctl2, scctl3;
1005	int i, j;
1006	const struct video_levels *video_levels;
1007	const struct color_conversion *color_conversion;
1008	bool burst_ena;
1009	int pipe = intel_crtc->pipe;
1010
1011	if (!tv_mode)
1012		return;	/* can't happen (mode_prepare prevents this) */
1013
1014	tv_ctl = I915_READ(TV_CTL);
1015	tv_ctl &= TV_CTL_SAVE;
1016
1017	switch (intel_tv->type) {
1018	default:
1019	case DRM_MODE_CONNECTOR_Unknown:
1020	case DRM_MODE_CONNECTOR_Composite:
1021		tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1022		video_levels = tv_mode->composite_levels;
1023		color_conversion = tv_mode->composite_color;
1024		burst_ena = tv_mode->burst_ena;
1025		break;
1026	case DRM_MODE_CONNECTOR_Component:
1027		tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1028		video_levels = &component_levels;
1029		if (tv_mode->burst_ena)
1030			color_conversion = &sdtv_csc_yprpb;
1031		else
1032			color_conversion = &hdtv_csc_yprpb;
1033		burst_ena = false;
1034		break;
1035	case DRM_MODE_CONNECTOR_SVIDEO:
1036		tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1037		video_levels = tv_mode->svideo_levels;
1038		color_conversion = tv_mode->svideo_color;
1039		burst_ena = tv_mode->burst_ena;
1040		break;
1041	}
1042	hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1043		(tv_mode->htotal << TV_HTOTAL_SHIFT);
1044
1045	hctl2 = (tv_mode->hburst_start << 16) |
1046		(tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1047
1048	if (burst_ena)
1049		hctl2 |= TV_BURST_ENA;
1050
1051	hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1052		(tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1053
1054	vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1055		(tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1056		(tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1057
1058	vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1059		(tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1060		(tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1061
1062	vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1063		(tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1064		(tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1065
1066	if (tv_mode->veq_ena)
1067		vctl3 |= TV_EQUAL_ENA;
1068
1069	vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1070		(tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1071
1072	vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1073		(tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1074
1075	vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1076		(tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1077
1078	vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1079		(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1080
1081	if (intel_crtc->pipe == 1)
1082		tv_ctl |= TV_ENC_PIPEB_SELECT;
1083	tv_ctl |= tv_mode->oversample;
1084
1085	if (tv_mode->progressive)
1086		tv_ctl |= TV_PROGRESSIVE;
1087	if (tv_mode->trilevel_sync)
1088		tv_ctl |= TV_TRILEVEL_SYNC;
1089	if (tv_mode->pal_burst)
1090		tv_ctl |= TV_PAL_BURST;
1091
1092	scctl1 = 0;
1093	if (tv_mode->dda1_inc)
1094		scctl1 |= TV_SC_DDA1_EN;
1095	if (tv_mode->dda2_inc)
1096		scctl1 |= TV_SC_DDA2_EN;
1097	if (tv_mode->dda3_inc)
1098		scctl1 |= TV_SC_DDA3_EN;
1099	scctl1 |= tv_mode->sc_reset;
1100	if (video_levels)
1101		scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1102	scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1103
1104	scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1105		tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1106
1107	scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1108		tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1109
1110	/* Enable two fixes for the chips that need them. */
1111	if (dev->pci_device < 0x2772)
1112		tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1113
1114	I915_WRITE(TV_H_CTL_1, hctl1);
1115	I915_WRITE(TV_H_CTL_2, hctl2);
1116	I915_WRITE(TV_H_CTL_3, hctl3);
1117	I915_WRITE(TV_V_CTL_1, vctl1);
1118	I915_WRITE(TV_V_CTL_2, vctl2);
1119	I915_WRITE(TV_V_CTL_3, vctl3);
1120	I915_WRITE(TV_V_CTL_4, vctl4);
1121	I915_WRITE(TV_V_CTL_5, vctl5);
1122	I915_WRITE(TV_V_CTL_6, vctl6);
1123	I915_WRITE(TV_V_CTL_7, vctl7);
1124	I915_WRITE(TV_SC_CTL_1, scctl1);
1125	I915_WRITE(TV_SC_CTL_2, scctl2);
1126	I915_WRITE(TV_SC_CTL_3, scctl3);
1127
1128	if (color_conversion) {
1129		I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1130			   color_conversion->gy);
1131		I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
1132			   color_conversion->ay);
1133		I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1134			   color_conversion->gu);
1135		I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1136			   color_conversion->au);
1137		I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1138			   color_conversion->gv);
1139		I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1140			   color_conversion->av);
1141	}
1142
1143	if (INTEL_INFO(dev)->gen >= 4)
1144		I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1145	else
1146		I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1147
1148	if (video_levels)
1149		I915_WRITE(TV_CLR_LEVEL,
1150			   ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1151			    (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1152	{
1153		int pipeconf_reg = PIPECONF(pipe);
1154		int dspcntr_reg = DSPCNTR(pipe);
1155		int pipeconf = I915_READ(pipeconf_reg);
1156		int dspcntr = I915_READ(dspcntr_reg);
1157		int dspbase_reg = DSPADDR(pipe);
1158		int xpos = 0x0, ypos = 0x0;
1159		unsigned int xsize, ysize;
1160		/* Pipe must be off here */
1161		I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1162		/* Flush the plane changes */
1163		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1164
1165		/* Wait for vblank for the disable to take effect */
1166		if (IS_GEN2(dev))
1167			intel_wait_for_vblank(dev, intel_crtc->pipe);
1168
1169		I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
1170		/* Wait for vblank for the disable to take effect. */
1171		intel_wait_for_pipe_off(dev, intel_crtc->pipe);
1172
1173		/* Filter ctl must be set before TV_WIN_SIZE */
1174		I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1175		xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1176		if (tv_mode->progressive)
1177			ysize = tv_mode->nbr_end + 1;
1178		else
1179			ysize = 2*tv_mode->nbr_end + 1;
1180
1181		xpos += intel_tv->margin[TV_MARGIN_LEFT];
1182		ypos += intel_tv->margin[TV_MARGIN_TOP];
1183		xsize -= (intel_tv->margin[TV_MARGIN_LEFT] +
1184			  intel_tv->margin[TV_MARGIN_RIGHT]);
1185		ysize -= (intel_tv->margin[TV_MARGIN_TOP] +
1186			  intel_tv->margin[TV_MARGIN_BOTTOM]);
1187		I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1188		I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1189
1190		I915_WRITE(pipeconf_reg, pipeconf);
1191		I915_WRITE(dspcntr_reg, dspcntr);
1192		/* Flush the plane changes */
1193		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1194	}
1195
1196	j = 0;
1197	for (i = 0; i < 60; i++)
1198		I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1199	for (i = 0; i < 60; i++)
1200		I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1201	for (i = 0; i < 43; i++)
1202		I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1203	for (i = 0; i < 43; i++)
1204		I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1205	I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1206	I915_WRITE(TV_CTL, tv_ctl);
1207}
1208
1209static const struct drm_display_mode reported_modes[] = {
1210	{
1211		.name = "NTSC 480i",
1212		.clock = 107520,
1213		.hdisplay = 1280,
1214		.hsync_start = 1368,
1215		.hsync_end = 1496,
1216		.htotal = 1712,
1217
1218		.vdisplay = 1024,
1219		.vsync_start = 1027,
1220		.vsync_end = 1034,
1221		.vtotal = 1104,
1222		.type = DRM_MODE_TYPE_DRIVER,
1223	},
1224};
1225
1226/**
1227 * Detects TV presence by checking for load.
1228 *
1229 * Requires that the current pipe's DPLL is active.
1230
1231 * \return true if TV is connected.
1232 * \return false if TV is disconnected.
1233 */
1234static int
1235intel_tv_detect_type (struct intel_tv *intel_tv,
1236		      struct drm_connector *connector)
1237{
1238	struct drm_encoder *encoder = &intel_tv->base.base;
1239	struct drm_device *dev = encoder->dev;
1240	struct drm_i915_private *dev_priv = dev->dev_private;
1241	unsigned long irqflags;
1242	u32 tv_ctl, save_tv_ctl;
1243	u32 tv_dac, save_tv_dac;
1244	int type;
1245
1246	/* Disable TV interrupts around load detect or we'll recurse */
1247	if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1248		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
1249		i915_disable_pipestat(dev_priv, 0,
1250				      PIPE_HOTPLUG_INTERRUPT_ENABLE |
1251				      PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
1252		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
1253	}
1254
1255	save_tv_dac = tv_dac = I915_READ(TV_DAC);
1256	save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1257
1258	/* Poll for TV detection */
1259	tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
1260	tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1261
1262	tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1263	tv_dac |= (TVDAC_STATE_CHG_EN |
1264		   TVDAC_A_SENSE_CTL |
1265		   TVDAC_B_SENSE_CTL |
1266		   TVDAC_C_SENSE_CTL |
1267		   DAC_CTL_OVERRIDE |
1268		   DAC_A_0_7_V |
1269		   DAC_B_0_7_V |
1270		   DAC_C_0_7_V);
1271
1272	I915_WRITE(TV_CTL, tv_ctl);
1273	I915_WRITE(TV_DAC, tv_dac);
1274	POSTING_READ(TV_DAC);
1275
1276	intel_wait_for_vblank(intel_tv->base.base.dev,
1277			      to_intel_crtc(intel_tv->base.base.crtc)->pipe);
1278
1279	type = -1;
1280	if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
1281		DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1282		/*
1283		 *  A B C
1284		 *  0 1 1 Composite
1285		 *  1 0 X svideo
1286		 *  0 0 0 Component
1287		 */
1288		if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1289			DRM_DEBUG_KMS("Detected Composite TV connection\n");
1290			type = DRM_MODE_CONNECTOR_Composite;
1291		} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1292			DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1293			type = DRM_MODE_CONNECTOR_SVIDEO;
1294		} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1295			DRM_DEBUG_KMS("Detected Component TV connection\n");
1296			type = DRM_MODE_CONNECTOR_Component;
1297		} else {
1298			DRM_DEBUG_KMS("Unrecognised TV connection\n");
1299		}
1300	}
1301
1302	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1303	I915_WRITE(TV_CTL, save_tv_ctl);
1304
1305	/* Restore interrupt config */
1306	if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1307		spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
1308		i915_enable_pipestat(dev_priv, 0,
1309				     PIPE_HOTPLUG_INTERRUPT_ENABLE |
1310				     PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
1311		spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
1312	}
1313
1314	return type;
1315}
1316
1317/*
1318 * Here we set accurate tv format according to connector type
1319 * i.e Component TV should not be assigned by NTSC or PAL
1320 */
1321static void intel_tv_find_better_format(struct drm_connector *connector)
1322{
1323	struct intel_tv *intel_tv = intel_attached_tv(connector);
1324	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1325	int i;
1326
1327	if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1328		tv_mode->component_only)
1329		return;
1330
1331
1332	for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) {
1333		tv_mode = tv_modes + i;
1334
1335		if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1336			tv_mode->component_only)
1337			break;
1338	}
1339
1340	intel_tv->tv_format = tv_mode->name;
1341	drm_connector_property_set_value(connector,
1342		connector->dev->mode_config.tv_mode_property, i);
1343}
1344
1345/**
1346 * Detect the TV connection.
1347 *
1348 * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
1349 * we have a pipe programmed in order to probe the TV.
1350 */
1351static enum drm_connector_status
1352intel_tv_detect(struct drm_connector *connector, bool force)
1353{
1354	struct drm_display_mode mode;
1355	struct intel_tv *intel_tv = intel_attached_tv(connector);
1356	int type;
1357
1358	mode = reported_modes[0];
1359	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1360
1361	if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
1362		type = intel_tv_detect_type(intel_tv, connector);
1363	} else if (force) {
1364		struct drm_crtc *crtc;
1365		int dpms_mode;
1366
1367		crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
1368						  &mode, &dpms_mode);
1369		if (crtc) {
1370			type = intel_tv_detect_type(intel_tv, connector);
1371			intel_release_load_detect_pipe(&intel_tv->base, connector,
1372						       dpms_mode);
1373		} else
1374			return connector_status_unknown;
1375	} else
1376		return connector->status;
1377
1378	if (type < 0)
1379		return connector_status_disconnected;
1380
1381	intel_tv->type = type;
1382	intel_tv_find_better_format(connector);
1383
1384	return connector_status_connected;
1385}
1386
1387static const struct input_res {
1388	const char *name;
1389	int w, h;
1390} input_res_table[] = {
1391	{"640x480", 640, 480},
1392	{"800x600", 800, 600},
1393	{"1024x768", 1024, 768},
1394	{"1280x1024", 1280, 1024},
1395	{"848x480", 848, 480},
1396	{"1280x720", 1280, 720},
1397	{"1920x1080", 1920, 1080},
1398};
1399
1400/*
1401 * Chose preferred mode  according to line number of TV format
1402 */
1403static void
1404intel_tv_chose_preferred_modes(struct drm_connector *connector,
1405			       struct drm_display_mode *mode_ptr)
1406{
1407	struct intel_tv *intel_tv = intel_attached_tv(connector);
1408	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1409
1410	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1411		mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1412	else if (tv_mode->nbr_end > 480) {
1413		if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1414			if (mode_ptr->vdisplay == 720)
1415				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1416		} else if (mode_ptr->vdisplay == 1080)
1417				mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1418	}
1419}
1420
1421/**
1422 * Stub get_modes function.
1423 *
1424 * This should probably return a set of fixed modes, unless we can figure out
1425 * how to probe modes off of TV connections.
1426 */
1427
1428static int
1429intel_tv_get_modes(struct drm_connector *connector)
1430{
1431	struct drm_display_mode *mode_ptr;
1432	struct intel_tv *intel_tv = intel_attached_tv(connector);
1433	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1434	int j, count = 0;
1435	u64 tmp;
1436
1437	for (j = 0; j < ARRAY_SIZE(input_res_table);
1438	     j++) {
1439		const struct input_res *input = &input_res_table[j];
1440		unsigned int hactive_s = input->w;
1441		unsigned int vactive_s = input->h;
1442
1443		if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1444			continue;
1445
1446		if (input->w > 1024 && (!tv_mode->progressive
1447					&& !tv_mode->component_only))
1448			continue;
1449
1450		mode_ptr = drm_mode_create(connector->dev);
1451		if (!mode_ptr)
1452			continue;
1453		strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1454
1455		mode_ptr->hdisplay = hactive_s;
1456		mode_ptr->hsync_start = hactive_s + 1;
1457		mode_ptr->hsync_end = hactive_s + 64;
1458		if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1459			mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1460		mode_ptr->htotal = hactive_s + 96;
1461
1462		mode_ptr->vdisplay = vactive_s;
1463		mode_ptr->vsync_start = vactive_s + 1;
1464		mode_ptr->vsync_end = vactive_s + 32;
1465		if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1466			mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
1467		mode_ptr->vtotal = vactive_s + 33;
1468
1469		tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
1470		tmp *= mode_ptr->htotal;
1471		tmp = div_u64(tmp, 1000000);
1472		mode_ptr->clock = (int) tmp;
1473
1474		mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1475		intel_tv_chose_preferred_modes(connector, mode_ptr);
1476		drm_mode_probed_add(connector, mode_ptr);
1477		count++;
1478	}
1479
1480	return count;
1481}
1482
1483static void
1484intel_tv_destroy (struct drm_connector *connector)
1485{
1486	drm_sysfs_connector_remove(connector);
1487	drm_connector_cleanup(connector);
1488	kfree(connector);
1489}
1490
1491
1492static int
1493intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
1494		      uint64_t val)
1495{
1496	struct drm_device *dev = connector->dev;
1497	struct intel_tv *intel_tv = intel_attached_tv(connector);
1498	struct drm_crtc *crtc = intel_tv->base.base.crtc;
1499	int ret = 0;
1500	bool changed = false;
1501
1502	ret = drm_connector_property_set_value(connector, property, val);
1503	if (ret < 0)
1504		goto out;
1505
1506	if (property == dev->mode_config.tv_left_margin_property &&
1507		intel_tv->margin[TV_MARGIN_LEFT] != val) {
1508		intel_tv->margin[TV_MARGIN_LEFT] = val;
1509		changed = true;
1510	} else if (property == dev->mode_config.tv_right_margin_property &&
1511		intel_tv->margin[TV_MARGIN_RIGHT] != val) {
1512		intel_tv->margin[TV_MARGIN_RIGHT] = val;
1513		changed = true;
1514	} else if (property == dev->mode_config.tv_top_margin_property &&
1515		intel_tv->margin[TV_MARGIN_TOP] != val) {
1516		intel_tv->margin[TV_MARGIN_TOP] = val;
1517		changed = true;
1518	} else if (property == dev->mode_config.tv_bottom_margin_property &&
1519		intel_tv->margin[TV_MARGIN_BOTTOM] != val) {
1520		intel_tv->margin[TV_MARGIN_BOTTOM] = val;
1521		changed = true;
1522	} else if (property == dev->mode_config.tv_mode_property) {
1523		if (val >= ARRAY_SIZE(tv_modes)) {
1524			ret = -EINVAL;
1525			goto out;
1526		}
1527		if (!strcmp(intel_tv->tv_format, tv_modes[val].name))
1528			goto out;
1529
1530		intel_tv->tv_format = tv_modes[val].name;
1531		changed = true;
1532	} else {
1533		ret = -EINVAL;
1534		goto out;
1535	}
1536
1537	if (changed && crtc)
1538		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
1539				crtc->y, crtc->fb);
1540out:
1541	return ret;
1542}
1543
1544static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
1545	.dpms = intel_tv_dpms,
1546	.mode_fixup = intel_tv_mode_fixup,
1547	.prepare = intel_encoder_prepare,
1548	.mode_set = intel_tv_mode_set,
1549	.commit = intel_encoder_commit,
1550};
1551
1552static const struct drm_connector_funcs intel_tv_connector_funcs = {
1553	.dpms = drm_helper_connector_dpms,
1554	.detect = intel_tv_detect,
1555	.destroy = intel_tv_destroy,
1556	.set_property = intel_tv_set_property,
1557	.fill_modes = drm_helper_probe_single_connector_modes,
1558};
1559
1560static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1561	.mode_valid = intel_tv_mode_valid,
1562	.get_modes = intel_tv_get_modes,
1563	.best_encoder = intel_best_encoder,
1564};
1565
1566static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1567	.destroy = intel_encoder_destroy,
1568};
1569
1570/*
1571 * Enumerate the child dev array parsed from VBT to check whether
1572 * the integrated TV is present.
1573 * If it is present, return 1.
1574 * If it is not present, return false.
1575 * If no child dev is parsed from VBT, it assumes that the TV is present.
1576 */
1577static int tv_is_present_in_vbt(struct drm_device *dev)
1578{
1579	struct drm_i915_private *dev_priv = dev->dev_private;
1580	struct child_device_config *p_child;
1581	int i, ret;
1582
1583	if (!dev_priv->child_dev_num)
1584		return 1;
1585
1586	ret = 0;
1587	for (i = 0; i < dev_priv->child_dev_num; i++) {
1588		p_child = dev_priv->child_dev + i;
1589		/*
1590		 * If the device type is not TV, continue.
1591		 */
1592		if (p_child->device_type != DEVICE_TYPE_INT_TV &&
1593			p_child->device_type != DEVICE_TYPE_TV)
1594			continue;
1595		/* Only when the addin_offset is non-zero, it is regarded
1596		 * as present.
1597		 */
1598		if (p_child->addin_offset) {
1599			ret = 1;
1600			break;
1601		}
1602	}
1603	return ret;
1604}
1605
1606void
1607intel_tv_init(struct drm_device *dev)
1608{
1609	struct drm_i915_private *dev_priv = dev->dev_private;
1610	struct drm_connector *connector;
1611	struct intel_tv *intel_tv;
1612	struct intel_encoder *intel_encoder;
1613	struct intel_connector *intel_connector;
1614	u32 tv_dac_on, tv_dac_off, save_tv_dac;
1615	char *tv_format_names[ARRAY_SIZE(tv_modes)];
1616	int i, initial_mode = 0;
1617
1618	if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1619		return;
1620
1621	if (!tv_is_present_in_vbt(dev)) {
1622		DRM_DEBUG_KMS("Integrated TV is not present.\n");
1623		return;
1624	}
1625	/* Even if we have an encoder we may not have a connector */
1626	if (!dev_priv->int_tv_support)
1627		return;
1628
1629	/*
1630	 * Sanity check the TV output by checking to see if the
1631	 * DAC register holds a value
1632	 */
1633	save_tv_dac = I915_READ(TV_DAC);
1634
1635	I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1636	tv_dac_on = I915_READ(TV_DAC);
1637
1638	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1639	tv_dac_off = I915_READ(TV_DAC);
1640
1641	I915_WRITE(TV_DAC, save_tv_dac);
1642
1643	/*
1644	 * If the register does not hold the state change enable
1645	 * bit, (either as a 0 or a 1), assume it doesn't really
1646	 * exist
1647	 */
1648	if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1649	    (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1650		return;
1651
1652	intel_tv = kzalloc(sizeof(struct intel_tv), GFP_KERNEL);
1653	if (!intel_tv) {
1654		return;
1655	}
1656
1657	intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
1658	if (!intel_connector) {
1659		kfree(intel_tv);
1660		return;
1661	}
1662
1663	intel_encoder = &intel_tv->base;
1664	connector = &intel_connector->base;
1665
1666	/* The documentation, for the older chipsets at least, recommend
1667	 * using a polling method rather than hotplug detection for TVs.
1668	 * This is because in order to perform the hotplug detection, the PLLs
1669	 * for the TV must be kept alive increasing power drain and starving
1670	 * bandwidth from other encoders. Notably for instance, it causes
1671	 * pipe underruns on Crestline when this encoder is supposedly idle.
1672	 *
1673	 * More recent chipsets favour HDMI rather than integrated S-Video.
1674	 */
1675	connector->polled =
1676		DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
1677
1678	drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1679			   DRM_MODE_CONNECTOR_SVIDEO);
1680
1681	drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1682			 DRM_MODE_ENCODER_TVDAC);
1683
1684	intel_connector_attach_encoder(intel_connector, intel_encoder);
1685	intel_encoder->type = INTEL_OUTPUT_TVOUT;
1686	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1687	intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
1688	intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
1689	intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
1690	intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1691
1692	/* BIOS margin values */
1693	intel_tv->margin[TV_MARGIN_LEFT] = 54;
1694	intel_tv->margin[TV_MARGIN_TOP] = 36;
1695	intel_tv->margin[TV_MARGIN_RIGHT] = 46;
1696	intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
1697
1698	intel_tv->tv_format = tv_modes[initial_mode].name;
1699
1700	drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
1701	drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1702	connector->interlace_allowed = false;
1703	connector->doublescan_allowed = false;
1704
1705	/* Create TV properties then attach current values */
1706	for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
1707		tv_format_names[i] = (char *)tv_modes[i].name;
1708	drm_mode_create_tv_properties(dev,
1709				      ARRAY_SIZE(tv_modes),
1710				      tv_format_names);
1711
1712	drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
1713				   initial_mode);
1714	drm_connector_attach_property(connector,
1715				   dev->mode_config.tv_left_margin_property,
1716				   intel_tv->margin[TV_MARGIN_LEFT]);
1717	drm_connector_attach_property(connector,
1718				   dev->mode_config.tv_top_margin_property,
1719				   intel_tv->margin[TV_MARGIN_TOP]);
1720	drm_connector_attach_property(connector,
1721				   dev->mode_config.tv_right_margin_property,
1722				   intel_tv->margin[TV_MARGIN_RIGHT]);
1723	drm_connector_attach_property(connector,
1724				   dev->mode_config.tv_bottom_margin_property,
1725				   intel_tv->margin[TV_MARGIN_BOTTOM]);
1726	drm_sysfs_connector_add(connector);
1727}
1728