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