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