drm/i915/tv: Deobfuscate preferred mode selection
[linux-2.6-block.git] / drivers / gpu / drm / i915 / intel_tv.c
CommitLineData
79e53945
JB
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
c6f95f27 33#include <drm/drm_atomic_helper.h>
760285e7
DH
34#include <drm/drm_crtc.h>
35#include <drm/drm_edid.h>
79e53945 36#include "intel_drv.h"
760285e7 37#include <drm/i915_drm.h>
79e53945
JB
38#include "i915_drv.h"
39
40enum tv_margin {
41 TV_MARGIN_LEFT, TV_MARGIN_TOP,
42 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
43};
44
ea5b213a
CW
45struct intel_tv {
46 struct intel_encoder base;
47
79e53945 48 int type;
79e53945
JB
49};
50
51struct video_levels {
db49296b
TU
52 u16 blank, black;
53 u8 burst;
79e53945
JB
54};
55
56struct color_conversion {
57 u16 ry, gy, by, ay;
58 u16 ru, gu, bu, au;
59 u16 rv, gv, bv, av;
60};
61
62static const u32 filter_table[] = {
63 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
64 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
65 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
66 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
67 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
68 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
69 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
70 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
71 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
72 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
73 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
74 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
75 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
76 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
77 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
78 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
79 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
80 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
81 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
82 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
83 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
84 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
85 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
86 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
87 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
88 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
89 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
90 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
91 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
92 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
93 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
94 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
95 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
96 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
97 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
98 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
99 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
100 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
101 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
102 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
103 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
104 0x2D002CC0, 0x30003640, 0x2D0036C0,
105 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
106 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
107 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
108 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
109 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
110 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
111 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
112 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
113 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
114 0x28003100, 0x28002F00, 0x00003100,
115};
116
117/*
118 * Color conversion values have 3 separate fixed point formats:
119 *
120 * 10 bit fields (ay, au)
121 * 1.9 fixed point (b.bbbbbbbbb)
122 * 11 bit fields (ry, by, ru, gu, gv)
123 * exp.mantissa (ee.mmmmmmmmm)
124 * ee = 00 = 10^-1 (0.mmmmmmmmm)
125 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
126 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
127 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
128 * 12 bit fields (gy, rv, bu)
129 * exp.mantissa (eee.mmmmmmmmm)
130 * eee = 000 = 10^-1 (0.mmmmmmmmm)
131 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
132 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
133 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
134 * eee = 100 = reserved
135 * eee = 101 = reserved
136 * eee = 110 = reserved
137 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
138 *
139 * Saturation and contrast are 8 bits, with their own representation:
140 * 8 bit field (saturation, contrast)
141 * exp.mantissa (ee.mmmmmm)
142 * ee = 00 = 10^-1 (0.mmmmmm)
143 * ee = 01 = 10^0 (m.mmmmm)
144 * ee = 10 = 10^1 (mm.mmmm)
145 * ee = 11 = 10^2 (mmm.mmm)
146 *
147 * Simple conversion function:
148 *
149 * static u32
150 * float_to_csc_11(float f)
151 * {
152 * u32 exp;
153 * u32 mant;
154 * u32 ret;
155 *
156 * if (f < 0)
157 * f = -f;
158 *
159 * if (f >= 1) {
160 * exp = 0x7;
0206e353 161 * mant = 1 << 8;
79e53945
JB
162 * } else {
163 * for (exp = 0; exp < 3 && f < 0.5; exp++)
0206e353 164 * f *= 2.0;
79e53945
JB
165 * mant = (f * (1 << 9) + 0.5);
166 * if (mant >= (1 << 9))
167 * mant = (1 << 9) - 1;
168 * }
169 * ret = (exp << 9) | mant;
170 * return ret;
171 * }
172 */
173
174/*
175 * Behold, magic numbers! If we plant them they might grow a big
176 * s-video cable to the sky... or something.
177 *
178 * Pre-converted to appropriate hex value.
179 */
180
181/*
182 * PAL & NTSC values for composite & s-video connections
183 */
184static const struct color_conversion ntsc_m_csc_composite = {
185 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
ba01079c
ZW
186 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
187 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
79e53945
JB
188};
189
190static const struct video_levels ntsc_m_levels_composite = {
191 .blank = 225, .black = 267, .burst = 113,
192};
193
194static const struct color_conversion ntsc_m_csc_svideo = {
ba01079c
ZW
195 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
196 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
197 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
79e53945
JB
198};
199
200static const struct video_levels ntsc_m_levels_svideo = {
201 .blank = 266, .black = 316, .burst = 133,
202};
203
204static const struct color_conversion ntsc_j_csc_composite = {
205 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
ba01079c
ZW
206 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
207 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
79e53945
JB
208};
209
210static const struct video_levels ntsc_j_levels_composite = {
211 .blank = 225, .black = 225, .burst = 113,
212};
213
214static const struct color_conversion ntsc_j_csc_svideo = {
215 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
ba01079c
ZW
216 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
217 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
79e53945
JB
218};
219
220static const struct video_levels ntsc_j_levels_svideo = {
221 .blank = 266, .black = 266, .burst = 133,
222};
223
224static const struct color_conversion pal_csc_composite = {
225 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
ba01079c
ZW
226 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
227 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
79e53945
JB
228};
229
230static const struct video_levels pal_levels_composite = {
231 .blank = 237, .black = 237, .burst = 118,
232};
233
234static const struct color_conversion pal_csc_svideo = {
235 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
ba01079c
ZW
236 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
237 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
79e53945
JB
238};
239
240static const struct video_levels pal_levels_svideo = {
241 .blank = 280, .black = 280, .burst = 139,
242};
243
244static const struct color_conversion pal_m_csc_composite = {
245 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
ba01079c
ZW
246 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
247 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
79e53945
JB
248};
249
250static const struct video_levels pal_m_levels_composite = {
251 .blank = 225, .black = 267, .burst = 113,
252};
253
254static const struct color_conversion pal_m_csc_svideo = {
ba01079c
ZW
255 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
256 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
257 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
79e53945
JB
258};
259
260static const struct video_levels pal_m_levels_svideo = {
261 .blank = 266, .black = 316, .burst = 133,
262};
263
264static const struct color_conversion pal_n_csc_composite = {
265 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
ba01079c
ZW
266 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
267 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
79e53945
JB
268};
269
270static const struct video_levels pal_n_levels_composite = {
271 .blank = 225, .black = 267, .burst = 118,
272};
273
274static const struct color_conversion pal_n_csc_svideo = {
ba01079c
ZW
275 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
276 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
277 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
79e53945
JB
278};
279
280static const struct video_levels pal_n_levels_svideo = {
281 .blank = 266, .black = 316, .burst = 139,
282};
283
284/*
285 * Component connections
286 */
287static const struct color_conversion sdtv_csc_yprpb = {
ba01079c
ZW
288 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
289 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
290 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
79e53945
JB
291};
292
79e53945 293static const struct color_conversion hdtv_csc_yprpb = {
ba01079c
ZW
294 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
295 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
296 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
79e53945
JB
297};
298
79e53945
JB
299static const struct video_levels component_levels = {
300 .blank = 279, .black = 279, .burst = 0,
301};
302
303
304struct tv_mode {
763a4a01 305 const char *name;
db49296b
TU
306
307 u32 clock;
308 u16 refresh; /* in millihertz (for precision) */
4f503798 309 u8 oversample;
db49296b
TU
310 u8 hsync_end;
311 u16 hblank_start, hblank_end, htotal;
312 bool progressive : 1, trilevel_sync : 1, component_only : 1;
313 u8 vsync_start_f1, vsync_start_f2, vsync_len;
314 bool veq_ena : 1;
315 u8 veq_start_f1, veq_start_f2, veq_len;
316 u8 vi_end_f1, vi_end_f2;
317 u16 nbr_end;
318 bool burst_ena : 1;
319 u8 hburst_start, hburst_len;
320 u8 vburst_start_f1;
321 u16 vburst_end_f1;
322 u8 vburst_start_f2;
323 u16 vburst_end_f2;
324 u8 vburst_start_f3;
325 u16 vburst_end_f3;
326 u8 vburst_start_f4;
327 u16 vburst_end_f4;
79e53945
JB
328 /*
329 * subcarrier programming
330 */
db49296b
TU
331 u16 dda2_size, dda3_size;
332 u8 dda1_inc;
333 u16 dda2_inc, dda3_inc;
79e53945 334 u32 sc_reset;
db49296b 335 bool pal_burst : 1;
79e53945
JB
336 /*
337 * blank/black levels
338 */
339 const struct video_levels *composite_levels, *svideo_levels;
340 const struct color_conversion *composite_color, *svideo_color;
341 const u32 *filter_table;
db49296b 342 u16 max_srcw;
79e53945
JB
343};
344
345
346/*
347 * Sub carrier DDA
348 *
349 * I think this works as follows:
350 *
351 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
352 *
353 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
354 *
355 * So,
356 * dda1_ideal = subcarrier/pixel * 4096
357 * dda1_inc = floor (dda1_ideal)
358 * dda2 = dda1_ideal - dda1_inc
359 *
360 * then pick a ratio for dda2 that gives the closest approximation. If
361 * you can't get close enough, you can play with dda3 as well. This
362 * seems likely to happen when dda2 is small as the jumps would be larger
363 *
364 * To invert this,
365 *
366 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
367 *
368 * The constants below were all computed using a 107.520MHz clock
369 */
370
3930f18a 371/*
79e53945
JB
372 * Register programming values for TV modes.
373 *
374 * These values account for -1s required.
375 */
005568be 376static const struct tv_mode tv_modes[] = {
79e53945
JB
377 {
378 .name = "NTSC-M",
ba01079c 379 .clock = 108000,
23bd15ec 380 .refresh = 59940,
4f503798 381 .oversample = 8,
56f62308 382 .component_only = false,
79e53945
JB
383 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
384
385 .hsync_end = 64, .hblank_end = 124,
386 .hblank_start = 836, .htotal = 857,
387
388 .progressive = false, .trilevel_sync = false,
389
390 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
391 .vsync_len = 6,
392
0206e353 393 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
394 .veq_start_f2 = 1, .veq_len = 18,
395
396 .vi_end_f1 = 20, .vi_end_f2 = 21,
397 .nbr_end = 240,
398
399 .burst_ena = true,
400 .hburst_start = 72, .hburst_len = 34,
401 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
402 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
403 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
404 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
405
406 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
ba01079c
ZW
407 .dda1_inc = 135,
408 .dda2_inc = 20800, .dda2_size = 27456,
79e53945
JB
409 .dda3_inc = 0, .dda3_size = 0,
410 .sc_reset = TV_SC_RESET_EVERY_4,
411 .pal_burst = false,
412
413 .composite_levels = &ntsc_m_levels_composite,
414 .composite_color = &ntsc_m_csc_composite,
415 .svideo_levels = &ntsc_m_levels_svideo,
416 .svideo_color = &ntsc_m_csc_svideo,
417
418 .filter_table = filter_table,
419 },
420 {
421 .name = "NTSC-443",
ba01079c 422 .clock = 108000,
23bd15ec 423 .refresh = 59940,
4f503798 424 .oversample = 8,
56f62308 425 .component_only = false,
79e53945
JB
426 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
427 .hsync_end = 64, .hblank_end = 124,
428 .hblank_start = 836, .htotal = 857,
429
430 .progressive = false, .trilevel_sync = false,
431
432 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
433 .vsync_len = 6,
434
0206e353 435 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
436 .veq_start_f2 = 1, .veq_len = 18,
437
438 .vi_end_f1 = 20, .vi_end_f2 = 21,
439 .nbr_end = 240,
440
3ca87e82 441 .burst_ena = true,
79e53945
JB
442 .hburst_start = 72, .hburst_len = 34,
443 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
444 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
445 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
446 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
447
448 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
449 .dda1_inc = 168,
ba01079c
ZW
450 .dda2_inc = 4093, .dda2_size = 27456,
451 .dda3_inc = 310, .dda3_size = 525,
452 .sc_reset = TV_SC_RESET_NEVER,
453 .pal_burst = false,
79e53945
JB
454
455 .composite_levels = &ntsc_m_levels_composite,
456 .composite_color = &ntsc_m_csc_composite,
457 .svideo_levels = &ntsc_m_levels_svideo,
458 .svideo_color = &ntsc_m_csc_svideo,
459
460 .filter_table = filter_table,
461 },
462 {
463 .name = "NTSC-J",
ba01079c 464 .clock = 108000,
23bd15ec 465 .refresh = 59940,
4f503798 466 .oversample = 8,
56f62308 467 .component_only = false,
79e53945
JB
468
469 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
470 .hsync_end = 64, .hblank_end = 124,
471 .hblank_start = 836, .htotal = 857,
472
473 .progressive = false, .trilevel_sync = false,
474
475 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
476 .vsync_len = 6,
477
0206e353 478 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
479 .veq_start_f2 = 1, .veq_len = 18,
480
481 .vi_end_f1 = 20, .vi_end_f2 = 21,
482 .nbr_end = 240,
483
484 .burst_ena = true,
485 .hburst_start = 72, .hburst_len = 34,
486 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
487 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
488 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
489 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
490
491 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
ba01079c
ZW
492 .dda1_inc = 135,
493 .dda2_inc = 20800, .dda2_size = 27456,
79e53945
JB
494 .dda3_inc = 0, .dda3_size = 0,
495 .sc_reset = TV_SC_RESET_EVERY_4,
496 .pal_burst = false,
497
498 .composite_levels = &ntsc_j_levels_composite,
499 .composite_color = &ntsc_j_csc_composite,
500 .svideo_levels = &ntsc_j_levels_svideo,
501 .svideo_color = &ntsc_j_csc_svideo,
502
503 .filter_table = filter_table,
504 },
505 {
506 .name = "PAL-M",
ba01079c 507 .clock = 108000,
23bd15ec 508 .refresh = 59940,
4f503798 509 .oversample = 8,
56f62308 510 .component_only = false,
79e53945
JB
511
512 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
513 .hsync_end = 64, .hblank_end = 124,
514 .hblank_start = 836, .htotal = 857,
515
516 .progressive = false, .trilevel_sync = false,
517
518 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
519 .vsync_len = 6,
520
0206e353 521 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
522 .veq_start_f2 = 1, .veq_len = 18,
523
524 .vi_end_f1 = 20, .vi_end_f2 = 21,
525 .nbr_end = 240,
526
527 .burst_ena = true,
528 .hburst_start = 72, .hburst_len = 34,
529 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
530 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
531 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
532 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
533
534 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
ba01079c
ZW
535 .dda1_inc = 135,
536 .dda2_inc = 16704, .dda2_size = 27456,
79e53945 537 .dda3_inc = 0, .dda3_size = 0,
ba01079c
ZW
538 .sc_reset = TV_SC_RESET_EVERY_8,
539 .pal_burst = true,
79e53945
JB
540
541 .composite_levels = &pal_m_levels_composite,
542 .composite_color = &pal_m_csc_composite,
543 .svideo_levels = &pal_m_levels_svideo,
544 .svideo_color = &pal_m_csc_svideo,
545
546 .filter_table = filter_table,
547 },
548 {
549 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
550 .name = "PAL-N",
ba01079c 551 .clock = 108000,
23bd15ec 552 .refresh = 50000,
4f503798 553 .oversample = 8,
56f62308 554 .component_only = false,
79e53945
JB
555
556 .hsync_end = 64, .hblank_end = 128,
557 .hblank_start = 844, .htotal = 863,
558
559 .progressive = false, .trilevel_sync = false,
560
561
562 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
563 .vsync_len = 6,
564
0206e353 565 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
566 .veq_start_f2 = 1, .veq_len = 18,
567
568 .vi_end_f1 = 24, .vi_end_f2 = 25,
569 .nbr_end = 286,
570
571 .burst_ena = true,
0206e353 572 .hburst_start = 73, .hburst_len = 34,
79e53945
JB
573 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
574 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
575 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
576 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
577
578
579 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
ba01079c
ZW
580 .dda1_inc = 135,
581 .dda2_inc = 23578, .dda2_size = 27648,
582 .dda3_inc = 134, .dda3_size = 625,
79e53945
JB
583 .sc_reset = TV_SC_RESET_EVERY_8,
584 .pal_burst = true,
585
586 .composite_levels = &pal_n_levels_composite,
587 .composite_color = &pal_n_csc_composite,
588 .svideo_levels = &pal_n_levels_svideo,
589 .svideo_color = &pal_n_csc_svideo,
590
591 .filter_table = filter_table,
592 },
593 {
594 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
595 .name = "PAL",
ba01079c 596 .clock = 108000,
23bd15ec 597 .refresh = 50000,
4f503798 598 .oversample = 8,
56f62308 599 .component_only = false,
79e53945 600
ba01079c 601 .hsync_end = 64, .hblank_end = 142,
79e53945
JB
602 .hblank_start = 844, .htotal = 863,
603
604 .progressive = false, .trilevel_sync = false,
605
606 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
607 .vsync_len = 5,
608
0206e353 609 .veq_ena = true, .veq_start_f1 = 0,
79e53945
JB
610 .veq_start_f2 = 1, .veq_len = 15,
611
612 .vi_end_f1 = 24, .vi_end_f2 = 25,
613 .nbr_end = 286,
614
615 .burst_ena = true,
616 .hburst_start = 73, .hburst_len = 32,
617 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
618 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
619 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
620 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
621
622 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
623 .dda1_inc = 168,
ba01079c
ZW
624 .dda2_inc = 4122, .dda2_size = 27648,
625 .dda3_inc = 67, .dda3_size = 625,
79e53945
JB
626 .sc_reset = TV_SC_RESET_EVERY_8,
627 .pal_burst = true,
628
629 .composite_levels = &pal_levels_composite,
630 .composite_color = &pal_csc_composite,
631 .svideo_levels = &pal_levels_svideo,
632 .svideo_color = &pal_csc_svideo,
633
634 .filter_table = filter_table,
635 },
9589919f
RV
636 {
637 .name = "480p",
d5152823 638 .clock = 108000,
9589919f 639 .refresh = 59940,
4f503798 640 .oversample = 4,
56f62308 641 .component_only = true,
9589919f
RV
642
643 .hsync_end = 64, .hblank_end = 122,
644 .hblank_start = 842, .htotal = 857,
645
646 .progressive = true, .trilevel_sync = false,
647
648 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
649 .vsync_len = 12,
650
651 .veq_ena = false,
652
653 .vi_end_f1 = 44, .vi_end_f2 = 44,
654 .nbr_end = 479,
655
656 .burst_ena = false,
657
658 .filter_table = filter_table,
659 },
660 {
661 .name = "576p",
d5152823 662 .clock = 108000,
9589919f 663 .refresh = 50000,
4f503798 664 .oversample = 4,
56f62308 665 .component_only = true,
9589919f
RV
666
667 .hsync_end = 64, .hblank_end = 139,
668 .hblank_start = 859, .htotal = 863,
669
670 .progressive = true, .trilevel_sync = false,
671
672 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
673 .vsync_len = 10,
674
675 .veq_ena = false,
676
677 .vi_end_f1 = 48, .vi_end_f2 = 48,
678 .nbr_end = 575,
679
680 .burst_ena = false,
681
682 .filter_table = filter_table,
683 },
79e53945
JB
684 {
685 .name = "720p@60Hz",
d5152823 686 .clock = 148500,
79e53945 687 .refresh = 60000,
4f503798 688 .oversample = 2,
56f62308 689 .component_only = true,
79e53945
JB
690
691 .hsync_end = 80, .hblank_end = 300,
692 .hblank_start = 1580, .htotal = 1649,
693
0206e353 694 .progressive = true, .trilevel_sync = true,
79e53945
JB
695
696 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
697 .vsync_len = 10,
698
699 .veq_ena = false,
700
701 .vi_end_f1 = 29, .vi_end_f2 = 29,
702 .nbr_end = 719,
703
704 .burst_ena = false,
705
706 .filter_table = filter_table,
707 },
79e53945
JB
708 {
709 .name = "720p@50Hz",
d5152823 710 .clock = 148500,
79e53945 711 .refresh = 50000,
4f503798 712 .oversample = 2,
56f62308 713 .component_only = true,
79e53945
JB
714
715 .hsync_end = 80, .hblank_end = 300,
716 .hblank_start = 1580, .htotal = 1979,
717
0206e353 718 .progressive = true, .trilevel_sync = true,
79e53945
JB
719
720 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
721 .vsync_len = 10,
722
723 .veq_ena = false,
724
725 .vi_end_f1 = 29, .vi_end_f2 = 29,
726 .nbr_end = 719,
727
728 .burst_ena = false,
729
730 .filter_table = filter_table,
731 .max_srcw = 800
732 },
733 {
734 .name = "1080i@50Hz",
d5152823 735 .clock = 148500,
23bd15ec 736 .refresh = 50000,
4f503798 737 .oversample = 2,
56f62308 738 .component_only = true,
79e53945
JB
739
740 .hsync_end = 88, .hblank_end = 235,
741 .hblank_start = 2155, .htotal = 2639,
742
0206e353 743 .progressive = false, .trilevel_sync = true,
79e53945
JB
744
745 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
746 .vsync_len = 10,
747
0206e353 748 .veq_ena = true, .veq_start_f1 = 4,
79e53945
JB
749 .veq_start_f2 = 4, .veq_len = 10,
750
751
752 .vi_end_f1 = 21, .vi_end_f2 = 22,
753 .nbr_end = 539,
754
755 .burst_ena = false,
756
757 .filter_table = filter_table,
758 },
759 {
760 .name = "1080i@60Hz",
d5152823 761 .clock = 148500,
23bd15ec 762 .refresh = 60000,
4f503798 763 .oversample = 2,
56f62308 764 .component_only = true,
79e53945
JB
765
766 .hsync_end = 88, .hblank_end = 235,
767 .hblank_start = 2155, .htotal = 2199,
768
0206e353 769 .progressive = false, .trilevel_sync = true,
79e53945
JB
770
771 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
772 .vsync_len = 10,
773
0206e353 774 .veq_ena = true, .veq_start_f1 = 4,
79e53945
JB
775 .veq_start_f2 = 4, .veq_len = 10,
776
777
778 .vi_end_f1 = 21, .vi_end_f2 = 22,
779 .nbr_end = 539,
780
781 .burst_ena = false,
782
79e53945
JB
783 .filter_table = filter_table,
784 },
785};
786
cd91ef23 787static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
ea5b213a 788{
cd91ef23 789 return container_of(encoder, struct intel_tv, base);
ea5b213a
CW
790}
791
df0e9248
CW
792static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
793{
cd91ef23 794 return enc_to_tv(intel_attached_encoder(connector));
df0e9248
CW
795}
796
9a8ee983
DV
797static bool
798intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
799{
4add0f6b 800 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
9a8ee983
DV
801 u32 tmp = I915_READ(TV_CTL);
802
4add0f6b 803 *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
9a8ee983 804
4add0f6b 805 return tmp & TV_ENC_ENABLE;
9a8ee983
DV
806}
807
79e53945 808static void
fd6bbda9 809intel_enable_tv(struct intel_encoder *encoder,
5f88a9c6
VS
810 const struct intel_crtc_state *pipe_config,
811 const struct drm_connector_state *conn_state)
79e53945 812{
6b5756a0 813 struct drm_device *dev = encoder->base.dev;
fac5e23e 814 struct drm_i915_private *dev_priv = to_i915(dev);
79e53945 815
7a98948f 816 /* Prevents vblank waits from timing out in intel_tv_detect_type() */
0f0f74bc 817 intel_wait_for_vblank(dev_priv,
a7f519ba 818 to_intel_crtc(pipe_config->base.crtc)->pipe);
7a98948f 819
6b5756a0
DV
820 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
821}
822
823static void
fd6bbda9 824intel_disable_tv(struct intel_encoder *encoder,
5f88a9c6
VS
825 const struct intel_crtc_state *old_crtc_state,
826 const struct drm_connector_state *old_conn_state)
6b5756a0
DV
827{
828 struct drm_device *dev = encoder->base.dev;
fac5e23e 829 struct drm_i915_private *dev_priv = to_i915(dev);
6b5756a0
DV
830
831 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
79e53945
JB
832}
833
5f88a9c6 834static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
79e53945 835{
0e891b3f 836 int format = conn_state->tv.mode;
79e53945 837
0e891b3f 838 return &tv_modes[format];
79e53945
JB
839}
840
841static enum drm_mode_status
763a4a01
CW
842intel_tv_mode_valid(struct drm_connector *connector,
843 struct drm_display_mode *mode)
79e53945 844{
0e891b3f 845 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
54c032b3
MK
846 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
847
e4dd27aa
VS
848 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
849 return MODE_NO_DBLESCAN;
850
54c032b3
MK
851 if (mode->clock > max_dotclk)
852 return MODE_CLOCK_HIGH;
79e53945
JB
853
854 /* Ensure TV refresh is close to desired refresh */
0d0884ce
ZY
855 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
856 < 1000)
79e53945 857 return MODE_OK;
763a4a01 858
79e53945
JB
859 return MODE_CLOCK_RANGE;
860}
861
65ddf7f9
VS
862static int
863intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
864{
865 if (tv_mode->progressive)
866 return tv_mode->nbr_end + 1;
867 else
868 return 2 * (tv_mode->nbr_end + 1);
869}
79e53945 870
7a495cfd
DV
871static void
872intel_tv_get_config(struct intel_encoder *encoder,
5cec258b 873 struct intel_crtc_state *pipe_config)
7a495cfd 874{
e1214b95
VS
875 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
876
2d112de7 877 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
7a495cfd
DV
878}
879
204474a6 880static int
5d2d38dd 881intel_tv_compute_config(struct intel_encoder *encoder,
0a478c27
ML
882 struct intel_crtc_state *pipe_config,
883 struct drm_connector_state *conn_state)
79e53945 884{
0e891b3f 885 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
e4dd27aa
VS
886 struct drm_display_mode *adjusted_mode =
887 &pipe_config->base.adjusted_mode;
79e53945
JB
888
889 if (!tv_mode)
204474a6 890 return -EINVAL;
79e53945 891
e4dd27aa 892 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
204474a6 893 return -EINVAL;
e4dd27aa 894
d9facae6 895 pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
e4dd27aa 896 adjusted_mode->crtc_clock = tv_mode->clock;
5d2d38dd
DV
897 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
898 pipe_config->pipe_bpp = 8*3;
899
1062b815 900 /* TV has it's own notion of sync and other mode flags, so clear them. */
e4dd27aa 901 adjusted_mode->flags = 0;
1062b815
DV
902
903 /*
904 * FIXME: We don't check whether the input mode is actually what we want
905 * or whether userspace is doing something stupid.
906 */
907
204474a6 908 return 0;
79e53945
JB
909}
910
8cb92203
DV
911static void
912set_tv_mode_timings(struct drm_i915_private *dev_priv,
913 const struct tv_mode *tv_mode,
914 bool burst_ena)
915{
916 u32 hctl1, hctl2, hctl3;
917 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
918
919 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
920 (tv_mode->htotal << TV_HTOTAL_SHIFT);
921
922 hctl2 = (tv_mode->hburst_start << 16) |
923 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
924
925 if (burst_ena)
926 hctl2 |= TV_BURST_ENA;
927
928 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
929 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
930
931 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
932 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
933 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
934
935 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
936 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
937 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
938
939 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
940 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
941 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
942
943 if (tv_mode->veq_ena)
944 vctl3 |= TV_EQUAL_ENA;
945
946 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
947 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
948
949 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
950 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
951
952 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
953 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
954
955 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
956 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
957
958 I915_WRITE(TV_H_CTL_1, hctl1);
959 I915_WRITE(TV_H_CTL_2, hctl2);
960 I915_WRITE(TV_H_CTL_3, hctl3);
961 I915_WRITE(TV_V_CTL_1, vctl1);
962 I915_WRITE(TV_V_CTL_2, vctl2);
963 I915_WRITE(TV_V_CTL_3, vctl3);
964 I915_WRITE(TV_V_CTL_4, vctl4);
965 I915_WRITE(TV_V_CTL_5, vctl5);
966 I915_WRITE(TV_V_CTL_6, vctl6);
967 I915_WRITE(TV_V_CTL_7, vctl7);
968}
969
b8866ef8
DV
970static void set_color_conversion(struct drm_i915_private *dev_priv,
971 const struct color_conversion *color_conversion)
972{
973 if (!color_conversion)
974 return;
975
976 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
977 color_conversion->gy);
978 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
979 color_conversion->ay);
980 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
981 color_conversion->gu);
982 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
983 color_conversion->au);
984 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
985 color_conversion->gv);
986 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
987 color_conversion->av);
988}
989
fd6bbda9 990static void intel_tv_pre_enable(struct intel_encoder *encoder,
5f88a9c6
VS
991 const struct intel_crtc_state *pipe_config,
992 const struct drm_connector_state *conn_state)
79e53945 993{
66478475 994 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
a7f519ba 995 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
cd91ef23 996 struct intel_tv *intel_tv = enc_to_tv(encoder);
0e891b3f 997 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
79e53945 998 u32 tv_ctl;
79e53945
JB
999 u32 scctl1, scctl2, scctl3;
1000 int i, j;
1001 const struct video_levels *video_levels;
1002 const struct color_conversion *color_conversion;
1003 bool burst_ena;
bda5f532 1004 int xpos, ypos;
3fa2dd14 1005 unsigned int xsize, ysize;
79e53945
JB
1006
1007 if (!tv_mode)
1008 return; /* can't happen (mode_prepare prevents this) */
1009
d2d9f232
ZW
1010 tv_ctl = I915_READ(TV_CTL);
1011 tv_ctl &= TV_CTL_SAVE;
79e53945 1012
ea5b213a 1013 switch (intel_tv->type) {
79e53945
JB
1014 default:
1015 case DRM_MODE_CONNECTOR_Unknown:
1016 case DRM_MODE_CONNECTOR_Composite:
1017 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1018 video_levels = tv_mode->composite_levels;
1019 color_conversion = tv_mode->composite_color;
1020 burst_ena = tv_mode->burst_ena;
1021 break;
1022 case DRM_MODE_CONNECTOR_Component:
1023 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1024 video_levels = &component_levels;
1025 if (tv_mode->burst_ena)
1026 color_conversion = &sdtv_csc_yprpb;
1027 else
1028 color_conversion = &hdtv_csc_yprpb;
1029 burst_ena = false;
1030 break;
1031 case DRM_MODE_CONNECTOR_SVIDEO:
1032 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1033 video_levels = tv_mode->svideo_levels;
1034 color_conversion = tv_mode->svideo_color;
1035 burst_ena = tv_mode->burst_ena;
1036 break;
1037 }
79e53945 1038
4add0f6b 1039 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
4f503798
VS
1040
1041 switch (tv_mode->oversample) {
1042 case 8:
1043 tv_ctl |= TV_OVERSAMPLE_8X;
1044 break;
1045 case 4:
1046 tv_ctl |= TV_OVERSAMPLE_4X;
1047 break;
1048 case 2:
1049 tv_ctl |= TV_OVERSAMPLE_2X;
1050 break;
1051 default:
1052 tv_ctl |= TV_OVERSAMPLE_NONE;
1053 break;
1054 }
79e53945
JB
1055
1056 if (tv_mode->progressive)
1057 tv_ctl |= TV_PROGRESSIVE;
1058 if (tv_mode->trilevel_sync)
1059 tv_ctl |= TV_TRILEVEL_SYNC;
1060 if (tv_mode->pal_burst)
1061 tv_ctl |= TV_PAL_BURST;
d271817b 1062
79e53945 1063 scctl1 = 0;
d271817b 1064 if (tv_mode->dda1_inc)
79e53945 1065 scctl1 |= TV_SC_DDA1_EN;
79e53945
JB
1066 if (tv_mode->dda2_inc)
1067 scctl1 |= TV_SC_DDA2_EN;
79e53945
JB
1068 if (tv_mode->dda3_inc)
1069 scctl1 |= TV_SC_DDA3_EN;
79e53945 1070 scctl1 |= tv_mode->sc_reset;
d271817b
CW
1071 if (video_levels)
1072 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
79e53945
JB
1073 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1074
1075 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1076 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1077
1078 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1079 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1080
1081 /* Enable two fixes for the chips that need them. */
50a0bc90 1082 if (IS_I915GM(dev_priv))
79e53945
JB
1083 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1084
8cb92203
DV
1085 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1086
79e53945
JB
1087 I915_WRITE(TV_SC_CTL_1, scctl1);
1088 I915_WRITE(TV_SC_CTL_2, scctl2);
1089 I915_WRITE(TV_SC_CTL_3, scctl3);
1090
b8866ef8 1091 set_color_conversion(dev_priv, color_conversion);
79e53945 1092
66478475 1093 if (INTEL_GEN(dev_priv) >= 4)
d2d9f232
ZW
1094 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1095 else
1096 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1097
79e53945
JB
1098 if (video_levels)
1099 I915_WRITE(TV_CLR_LEVEL,
1100 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1101 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
3fa2dd14
DV
1102
1103 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
1104
1105 /* Filter ctl must be set before TV_WIN_SIZE */
1106 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1107 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
65ddf7f9 1108 ysize = intel_tv_mode_vdisplay(tv_mode);
3fa2dd14 1109
bda5f532
VS
1110 xpos = conn_state->tv.margins.left;
1111 ypos = conn_state->tv.margins.top;
0e891b3f
ML
1112 xsize -= (conn_state->tv.margins.left +
1113 conn_state->tv.margins.right);
1114 ysize -= (conn_state->tv.margins.top +
1115 conn_state->tv.margins.bottom);
3fa2dd14
DV
1116 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1117 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
79e53945
JB
1118
1119 j = 0;
1120 for (i = 0; i < 60; i++)
184d7c06 1121 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
79e53945 1122 for (i = 0; i < 60; i++)
184d7c06 1123 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
79e53945 1124 for (i = 0; i < 43; i++)
184d7c06 1125 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
79e53945 1126 for (i = 0; i < 43; i++)
184d7c06 1127 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
b8ed2a4f 1128 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
79e53945
JB
1129 I915_WRITE(TV_CTL, tv_ctl);
1130}
1131
1132static const struct drm_display_mode reported_modes[] = {
1133 {
1134 .name = "NTSC 480i",
d5152823 1135 .clock = 108000,
79e53945
JB
1136 .hdisplay = 1280,
1137 .hsync_start = 1368,
1138 .hsync_end = 1496,
1139 .htotal = 1712,
1140
1141 .vdisplay = 1024,
1142 .vsync_start = 1027,
1143 .vsync_end = 1034,
1144 .vtotal = 1104,
1145 .type = DRM_MODE_TYPE_DRIVER,
1146 },
1147};
1148
79e53945 1149static int
0206e353 1150intel_tv_detect_type(struct intel_tv *intel_tv,
8102e126 1151 struct drm_connector *connector)
79e53945 1152{
0eadc624 1153 struct drm_crtc *crtc = connector->state->crtc;
835bff7e 1154 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
0eadc624 1155 struct drm_device *dev = connector->dev;
fac5e23e 1156 struct drm_i915_private *dev_priv = to_i915(dev);
79e53945
JB
1157 u32 tv_ctl, save_tv_ctl;
1158 u32 tv_dac, save_tv_dac;
974b9331 1159 int type;
79e53945
JB
1160
1161 /* Disable TV interrupts around load detect or we'll recurse */
8102e126 1162 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
2795aa48 1163 spin_lock_irq(&dev_priv->irq_lock);
8102e126 1164 i915_disable_pipestat(dev_priv, 0,
755e9019
ID
1165 PIPE_HOTPLUG_INTERRUPT_STATUS |
1166 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
2795aa48 1167 spin_unlock_irq(&dev_priv->irq_lock);
8102e126 1168 }
79e53945 1169
974b9331
CW
1170 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1171 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1172
1173 /* Poll for TV detection */
4add0f6b 1174 tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
8ed9a5bc 1175 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
4add0f6b 1176 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
974b9331
CW
1177
1178 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
8ed9a5bc 1179 tv_dac |= (TVDAC_STATE_CHG_EN |
1180 TVDAC_A_SENSE_CTL |
1181 TVDAC_B_SENSE_CTL |
1182 TVDAC_C_SENSE_CTL |
1183 DAC_CTL_OVERRIDE |
1184 DAC_A_0_7_V |
1185 DAC_B_0_7_V |
1186 DAC_C_0_7_V);
974b9331 1187
d42c9e2c
DV
1188
1189 /*
1190 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1191 * the TV is misdetected. This is hardware requirement.
1192 */
50a0bc90 1193 if (IS_GM45(dev_priv))
d42c9e2c
DV
1194 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1195 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1196
8ed9a5bc 1197 I915_WRITE(TV_CTL, tv_ctl);
1198 I915_WRITE(TV_DAC, tv_dac);
4f233eff 1199 POSTING_READ(TV_DAC);
4f233eff 1200
0f0f74bc 1201 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
29e1316a 1202
974b9331 1203 type = -1;
2bf71160
KP
1204 tv_dac = I915_READ(TV_DAC);
1205 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1206 /*
1207 * A B C
1208 * 0 1 1 Composite
1209 * 1 0 X svideo
1210 * 0 0 0 Component
1211 */
1212 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1213 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1214 type = DRM_MODE_CONNECTOR_Composite;
1215 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1216 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1217 type = DRM_MODE_CONNECTOR_SVIDEO;
1218 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1219 DRM_DEBUG_KMS("Detected Component TV connection\n");
1220 type = DRM_MODE_CONNECTOR_Component;
1221 } else {
1222 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1223 type = -1;
79e53945
JB
1224 }
1225
974b9331
CW
1226 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1227 I915_WRITE(TV_CTL, save_tv_ctl);
bf2125e2
DV
1228 POSTING_READ(TV_CTL);
1229
1230 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
0f0f74bc 1231 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
974b9331 1232
79e53945 1233 /* Restore interrupt config */
8102e126 1234 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
2795aa48 1235 spin_lock_irq(&dev_priv->irq_lock);
8102e126 1236 i915_enable_pipestat(dev_priv, 0,
755e9019
ID
1237 PIPE_HOTPLUG_INTERRUPT_STATUS |
1238 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
2795aa48 1239 spin_unlock_irq(&dev_priv->irq_lock);
8102e126 1240 }
79e53945
JB
1241
1242 return type;
1243}
1244
213c2e64
ML
1245/*
1246 * Here we set accurate tv format according to connector type
1247 * i.e Component TV should not be assigned by NTSC or PAL
1248 */
1249static void intel_tv_find_better_format(struct drm_connector *connector)
1250{
df0e9248 1251 struct intel_tv *intel_tv = intel_attached_tv(connector);
0e891b3f 1252 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
213c2e64
ML
1253 int i;
1254
ea5b213a 1255 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
213c2e64
ML
1256 tv_mode->component_only)
1257 return;
1258
1259
53abb679 1260 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
213c2e64
ML
1261 tv_mode = tv_modes + i;
1262
ea5b213a 1263 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
213c2e64
ML
1264 tv_mode->component_only)
1265 break;
1266 }
1267
0e891b3f 1268 connector->state->tv.mode = i;
213c2e64
ML
1269}
1270
6c5ed5ae
ML
1271static int
1272intel_tv_detect(struct drm_connector *connector,
1273 struct drm_modeset_acquire_ctx *ctx,
1274 bool force)
79e53945 1275{
79e53945 1276 struct drm_display_mode mode;
df0e9248 1277 struct intel_tv *intel_tv = intel_attached_tv(connector);
bbfb44e8 1278 enum drm_connector_status status;
ea5b213a 1279 int type;
79e53945 1280
164c8598 1281 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
c23cc417 1282 connector->base.id, connector->name,
164c8598
CW
1283 force);
1284
79e53945 1285 mode = reported_modes[0];
79e53945 1286
38de45c5 1287 if (force) {
8261b191 1288 struct intel_load_detect_pipe tmp;
6c5ed5ae 1289 int ret;
ea5b213a 1290
6c5ed5ae
ML
1291 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1292 if (ret < 0)
1293 return ret;
208bf9fd 1294
6c5ed5ae 1295 if (ret > 0) {
8102e126 1296 type = intel_tv_detect_type(intel_tv, connector);
6c5ed5ae 1297 intel_release_load_detect_pipe(connector, &tmp, ctx);
bbfb44e8
VS
1298 status = type < 0 ?
1299 connector_status_disconnected :
1300 connector_status_connected;
79e53945 1301 } else
bbfb44e8 1302 status = connector_status_unknown;
bf5a269a 1303
0e891b3f
ML
1304 if (status == connector_status_connected) {
1305 intel_tv->type = type;
1306 intel_tv_find_better_format(connector);
1307 }
d5627663 1308
0e891b3f
ML
1309 return status;
1310 } else
1311 return connector->status;
79e53945
JB
1312}
1313
763a4a01
CW
1314static const struct input_res {
1315 const char *name;
79e53945 1316 int w, h;
763a4a01 1317} input_res_table[] = {
79e53945
JB
1318 {"640x480", 640, 480},
1319 {"800x600", 800, 600},
1320 {"1024x768", 1024, 768},
1321 {"1280x1024", 1280, 1024},
1322 {"848x480", 848, 480},
1323 {"1280x720", 1280, 720},
1324 {"1920x1080", 1920, 1080},
1325};
1326
65ddf7f9
VS
1327/* Choose preferred mode according to line number of TV format */
1328static bool
1329intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
1330 const struct tv_mode *tv_mode)
1331{
1332 int vdisplay = intel_tv_mode_vdisplay(tv_mode);
1333
1334 /* prefer 480 line modes for all SD TV modes */
1335 if (vdisplay <= 576)
1336 vdisplay = 480;
1337
1338 return vdisplay == mode->vdisplay;
1339}
1340
bcae2ca8 1341static void
65ddf7f9
VS
1342intel_tv_set_mode_type(struct drm_display_mode *mode,
1343 const struct tv_mode *tv_mode)
bcae2ca8 1344{
65ddf7f9
VS
1345 mode->type = DRM_MODE_TYPE_DRIVER;
1346
1347 if (intel_tv_is_preferred_mode(mode, tv_mode))
1348 mode->type |= DRM_MODE_TYPE_PREFERRED;
bcae2ca8 1349}
1350
79e53945
JB
1351static int
1352intel_tv_get_modes(struct drm_connector *connector)
1353{
1354 struct drm_display_mode *mode_ptr;
0e891b3f 1355 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
02c5dd98
ZW
1356 int j, count = 0;
1357 u64 tmp;
79e53945 1358
04ad327f 1359 for (j = 0; j < ARRAY_SIZE(input_res_table);
79e53945 1360 j++) {
763a4a01 1361 const struct input_res *input = &input_res_table[j];
79e53945
JB
1362 unsigned int hactive_s = input->w;
1363 unsigned int vactive_s = input->h;
1364
1365 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1366 continue;
1367
1368 if (input->w > 1024 && (!tv_mode->progressive
1369 && !tv_mode->component_only))
1370 continue;
1371
02c5dd98
ZW
1372 mode_ptr = drm_mode_create(connector->dev);
1373 if (!mode_ptr)
1374 continue;
d6b4ea86 1375 strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
79e53945
JB
1376
1377 mode_ptr->hdisplay = hactive_s;
1378 mode_ptr->hsync_start = hactive_s + 1;
1379 mode_ptr->hsync_end = hactive_s + 64;
1380 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1381 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1382 mode_ptr->htotal = hactive_s + 96;
1383
1384 mode_ptr->vdisplay = vactive_s;
1385 mode_ptr->vsync_start = vactive_s + 1;
1386 mode_ptr->vsync_end = vactive_s + 32;
1387 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1388 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1389 mode_ptr->vtotal = vactive_s + 33;
1390
3123698f 1391 tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
02c5dd98
ZW
1392 tmp *= mode_ptr->htotal;
1393 tmp = div_u64(tmp, 1000000);
1394 mode_ptr->clock = (int) tmp;
79e53945 1395
65ddf7f9 1396 intel_tv_set_mode_type(mode_ptr, tv_mode);
79e53945 1397 drm_mode_probed_add(connector, mode_ptr);
02c5dd98 1398 count++;
79e53945
JB
1399 }
1400
02c5dd98 1401 return count;
79e53945
JB
1402}
1403
79e53945 1404static const struct drm_connector_funcs intel_tv_connector_funcs = {
1ebaa0b9 1405 .late_register = intel_connector_register,
c191eca1 1406 .early_unregister = intel_connector_unregister,
d4b26e4f 1407 .destroy = intel_connector_destroy,
79e53945 1408 .fill_modes = drm_helper_probe_single_connector_modes,
c6f95f27 1409 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
98969725 1410 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
79e53945
JB
1411};
1412
0e891b3f
ML
1413static int intel_tv_atomic_check(struct drm_connector *connector,
1414 struct drm_connector_state *new_state)
1415{
1416 struct drm_crtc_state *new_crtc_state;
1417 struct drm_connector_state *old_state;
1418
1419 if (!new_state->crtc)
1420 return 0;
1421
1422 old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
1423 new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
1424
1425 if (old_state->tv.mode != new_state->tv.mode ||
1426 old_state->tv.margins.left != new_state->tv.margins.left ||
1427 old_state->tv.margins.right != new_state->tv.margins.right ||
1428 old_state->tv.margins.top != new_state->tv.margins.top ||
1429 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1430 /* Force a modeset. */
1431
1432 new_crtc_state->connectors_changed = true;
1433 }
1434
1435 return 0;
1436}
1437
79e53945 1438static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
6c5ed5ae 1439 .detect_ctx = intel_tv_detect,
79e53945
JB
1440 .mode_valid = intel_tv_mode_valid,
1441 .get_modes = intel_tv_get_modes,
0e891b3f 1442 .atomic_check = intel_tv_atomic_check,
79e53945
JB
1443};
1444
79e53945 1445static const struct drm_encoder_funcs intel_tv_enc_funcs = {
ea5b213a 1446 .destroy = intel_encoder_destroy,
79e53945
JB
1447};
1448
79e53945 1449void
c39055b0 1450intel_tv_init(struct drm_i915_private *dev_priv)
79e53945 1451{
c39055b0 1452 struct drm_device *dev = &dev_priv->drm;
79e53945 1453 struct drm_connector *connector;
ea5b213a 1454 struct intel_tv *intel_tv;
21d40d37 1455 struct intel_encoder *intel_encoder;
0c41ee2b 1456 struct intel_connector *intel_connector;
79e53945 1457 u32 tv_dac_on, tv_dac_off, save_tv_dac;
b7c914b3 1458 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
79e53945 1459 int i, initial_mode = 0;
0e891b3f 1460 struct drm_connector_state *state;
79e53945
JB
1461
1462 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1463 return;
1464
3bdd14d5 1465 if (!intel_bios_is_tv_present(dev_priv)) {
c3561438
ZY
1466 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1467 return;
1468 }
79e53945
JB
1469
1470 /*
1471 * Sanity check the TV output by checking to see if the
1472 * DAC register holds a value
1473 */
1474 save_tv_dac = I915_READ(TV_DAC);
1475
1476 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1477 tv_dac_on = I915_READ(TV_DAC);
1478
1479 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1480 tv_dac_off = I915_READ(TV_DAC);
1481
1482 I915_WRITE(TV_DAC, save_tv_dac);
1483
1484 /*
1485 * If the register does not hold the state change enable
1486 * bit, (either as a 0 or a 1), assume it doesn't really
1487 * exist
1488 */
1489 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1490 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1491 return;
1492
b14c5679 1493 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
ea5b213a 1494 if (!intel_tv) {
79e53945
JB
1495 return;
1496 }
f8aed700 1497
08d9bc92 1498 intel_connector = intel_connector_alloc();
0c41ee2b 1499 if (!intel_connector) {
ea5b213a 1500 kfree(intel_tv);
0c41ee2b
ZW
1501 return;
1502 }
1503
ea5b213a 1504 intel_encoder = &intel_tv->base;
0c41ee2b 1505 connector = &intel_connector->base;
0e891b3f 1506 state = connector->state;
79e53945 1507
3930f18a
CW
1508 /*
1509 * The documentation, for the older chipsets at least, recommend
8102e126
CW
1510 * using a polling method rather than hotplug detection for TVs.
1511 * This is because in order to perform the hotplug detection, the PLLs
1512 * for the TV must be kept alive increasing power drain and starving
1513 * bandwidth from other encoders. Notably for instance, it causes
1514 * pipe underruns on Crestline when this encoder is supposedly idle.
1515 *
1516 * More recent chipsets favour HDMI rather than integrated S-Video.
1517 */
821450c6 1518 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
8102e126 1519
79e53945
JB
1520 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1521 DRM_MODE_CONNECTOR_SVIDEO);
1522
4ef69c7a 1523 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
580d8ed5 1524 DRM_MODE_ENCODER_TVDAC, "TV");
79e53945 1525
5d2d38dd 1526 intel_encoder->compute_config = intel_tv_compute_config;
7a495cfd 1527 intel_encoder->get_config = intel_tv_get_config;
809a2a8b 1528 intel_encoder->pre_enable = intel_tv_pre_enable;
6b5756a0
DV
1529 intel_encoder->enable = intel_enable_tv;
1530 intel_encoder->disable = intel_disable_tv;
9a8ee983
DV
1531 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1532 intel_connector->get_hw_state = intel_connector_get_hw_state;
6b5756a0 1533
df0e9248 1534 intel_connector_attach_encoder(intel_connector, intel_encoder);
03cdc1d4 1535
21d40d37 1536 intel_encoder->type = INTEL_OUTPUT_TVOUT;
79f255a0 1537 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
03cdc1d4 1538 intel_encoder->port = PORT_NONE;
21d40d37 1539 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
bc079e8b 1540 intel_encoder->cloneable = 0;
4ef69c7a 1541 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
ea5b213a 1542 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
79e53945
JB
1543
1544 /* BIOS margin values */
0e891b3f
ML
1545 state->tv.margins.left = 54;
1546 state->tv.margins.top = 36;
1547 state->tv.margins.right = 46;
1548 state->tv.margins.bottom = 37;
79e53945 1549
0e891b3f 1550 state->tv.mode = initial_mode;
79e53945 1551
79e53945
JB
1552 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1553 connector->interlace_allowed = false;
1554 connector->doublescan_allowed = false;
1555
1556 /* Create TV properties then attach current values */
2991196f 1557 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
b7c914b3 1558 tv_format_names[i] = tv_modes[i].name;
763a4a01
CW
1559 drm_mode_create_tv_properties(dev,
1560 ARRAY_SIZE(tv_modes),
1561 tv_format_names);
79e53945 1562
662595df 1563 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
0e891b3f 1564 state->tv.mode);
662595df 1565 drm_object_attach_property(&connector->base,
79e53945 1566 dev->mode_config.tv_left_margin_property,
0e891b3f 1567 state->tv.margins.left);
662595df 1568 drm_object_attach_property(&connector->base,
79e53945 1569 dev->mode_config.tv_top_margin_property,
0e891b3f 1570 state->tv.margins.top);
662595df 1571 drm_object_attach_property(&connector->base,
79e53945 1572 dev->mode_config.tv_right_margin_property,
0e891b3f 1573 state->tv.margins.right);
662595df 1574 drm_object_attach_property(&connector->base,
79e53945 1575 dev->mode_config.tv_bottom_margin_property,
0e891b3f 1576 state->tv.margins.bottom);
79e53945 1577}