blob: 3af857a75fab94426389bc234a8cbd59bf98dcd1 [file] [log] [blame]
Jesse Barnes79e53942008-11-07 14:24:08 -08001/*
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
David Howells760285e2012-10-02 18:01:07 +010033#include <drm/drmP.h>
Matt Roperc6f95f22015-01-22 16:50:32 -080034#include <drm/drm_atomic_helper.h>
David Howells760285e2012-10-02 18:01:07 +010035#include <drm/drm_crtc.h>
36#include <drm/drm_edid.h>
Jesse Barnes79e53942008-11-07 14:24:08 -080037#include "intel_drv.h"
David Howells760285e2012-10-02 18:01:07 +010038#include <drm/i915_drm.h>
Jesse Barnes79e53942008-11-07 14:24:08 -080039#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 */
Chris Wilsonea5b2132010-08-04 13:50:23 +010047struct intel_tv {
48 struct intel_encoder base;
49
Jesse Barnes79e53942008-11-07 14:24:08 -080050 int type;
Chris Wilson763a4a02010-09-05 00:52:34 +010051 const char *tv_format;
Jesse Barnes79e53942008-11-07 14:24:08 -080052 int margin[4];
Jesse Barnes79e53942008-11-07 14:24:08 -080053};
54
55struct video_levels {
Tvrtko Ursulindb492962016-10-13 11:09:26 +010056 u16 blank, black;
57 u8 burst;
Jesse Barnes79e53942008-11-07 14:24:08 -080058};
59
60struct color_conversion {
61 u16 ry, gy, by, ay;
62 u16 ru, gu, bu, au;
63 u16 rv, gv, bv, av;
64};
65
66static const u32 filter_table[] = {
67 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
68 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
69 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
70 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
71 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
72 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
73 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
74 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
75 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
76 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
77 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
78 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
79 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
80 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
81 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
82 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
83 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
84 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
85 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
86 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
87 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
88 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
89 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
90 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
91 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
92 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
93 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
94 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
95 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
96 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
97 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
98 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
99 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
100 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
101 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
102 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
103 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
104 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
105 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
106 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
107 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
108 0x2D002CC0, 0x30003640, 0x2D0036C0,
109 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
110 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
111 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
112 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
113 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
114 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
115 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
116 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
117 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
118 0x28003100, 0x28002F00, 0x00003100,
119};
120
121/*
122 * Color conversion values have 3 separate fixed point formats:
123 *
124 * 10 bit fields (ay, au)
125 * 1.9 fixed point (b.bbbbbbbbb)
126 * 11 bit fields (ry, by, ru, gu, gv)
127 * exp.mantissa (ee.mmmmmmmmm)
128 * ee = 00 = 10^-1 (0.mmmmmmmmm)
129 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
130 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
131 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
132 * 12 bit fields (gy, rv, bu)
133 * exp.mantissa (eee.mmmmmmmmm)
134 * eee = 000 = 10^-1 (0.mmmmmmmmm)
135 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
136 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
137 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
138 * eee = 100 = reserved
139 * eee = 101 = reserved
140 * eee = 110 = reserved
141 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
142 *
143 * Saturation and contrast are 8 bits, with their own representation:
144 * 8 bit field (saturation, contrast)
145 * exp.mantissa (ee.mmmmmm)
146 * ee = 00 = 10^-1 (0.mmmmmm)
147 * ee = 01 = 10^0 (m.mmmmm)
148 * ee = 10 = 10^1 (mm.mmmm)
149 * ee = 11 = 10^2 (mmm.mmm)
150 *
151 * Simple conversion function:
152 *
153 * static u32
154 * float_to_csc_11(float f)
155 * {
156 * u32 exp;
157 * u32 mant;
158 * u32 ret;
159 *
160 * if (f < 0)
161 * f = -f;
162 *
163 * if (f >= 1) {
164 * exp = 0x7;
Akshay Joshi0206e352011-08-16 15:34:10 -0400165 * mant = 1 << 8;
Jesse Barnes79e53942008-11-07 14:24:08 -0800166 * } else {
167 * for (exp = 0; exp < 3 && f < 0.5; exp++)
Akshay Joshi0206e352011-08-16 15:34:10 -0400168 * f *= 2.0;
Jesse Barnes79e53942008-11-07 14:24:08 -0800169 * mant = (f * (1 << 9) + 0.5);
170 * if (mant >= (1 << 9))
171 * mant = (1 << 9) - 1;
172 * }
173 * ret = (exp << 9) | mant;
174 * return ret;
175 * }
176 */
177
178/*
179 * Behold, magic numbers! If we plant them they might grow a big
180 * s-video cable to the sky... or something.
181 *
182 * Pre-converted to appropriate hex value.
183 */
184
185/*
186 * PAL & NTSC values for composite & s-video connections
187 */
188static const struct color_conversion ntsc_m_csc_composite = {
189 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800190 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
191 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800192};
193
194static const struct video_levels ntsc_m_levels_composite = {
195 .blank = 225, .black = 267, .burst = 113,
196};
197
198static const struct color_conversion ntsc_m_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800199 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
200 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
201 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800202};
203
204static const struct video_levels ntsc_m_levels_svideo = {
205 .blank = 266, .black = 316, .burst = 133,
206};
207
208static const struct color_conversion ntsc_j_csc_composite = {
209 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
Zhenyu Wangba010792009-03-04 20:23:02 +0800210 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
211 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800212};
213
214static const struct video_levels ntsc_j_levels_composite = {
215 .blank = 225, .black = 225, .burst = 113,
216};
217
218static const struct color_conversion ntsc_j_csc_svideo = {
219 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
Zhenyu Wangba010792009-03-04 20:23:02 +0800220 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
221 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800222};
223
224static const struct video_levels ntsc_j_levels_svideo = {
225 .blank = 266, .black = 266, .burst = 133,
226};
227
228static const struct color_conversion pal_csc_composite = {
229 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
Zhenyu Wangba010792009-03-04 20:23:02 +0800230 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
231 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800232};
233
234static const struct video_levels pal_levels_composite = {
235 .blank = 237, .black = 237, .burst = 118,
236};
237
238static const struct color_conversion pal_csc_svideo = {
239 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
Zhenyu Wangba010792009-03-04 20:23:02 +0800240 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
241 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800242};
243
244static const struct video_levels pal_levels_svideo = {
245 .blank = 280, .black = 280, .burst = 139,
246};
247
248static const struct color_conversion pal_m_csc_composite = {
249 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800250 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
251 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800252};
253
254static const struct video_levels pal_m_levels_composite = {
255 .blank = 225, .black = 267, .burst = 113,
256};
257
258static const struct color_conversion pal_m_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800259 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
260 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
261 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800262};
263
264static const struct video_levels pal_m_levels_svideo = {
265 .blank = 266, .black = 316, .burst = 133,
266};
267
268static const struct color_conversion pal_n_csc_composite = {
269 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800270 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
271 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800272};
273
274static const struct video_levels pal_n_levels_composite = {
275 .blank = 225, .black = 267, .burst = 118,
276};
277
278static const struct color_conversion pal_n_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800279 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
280 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
281 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800282};
283
284static const struct video_levels pal_n_levels_svideo = {
285 .blank = 266, .black = 316, .burst = 139,
286};
287
288/*
289 * Component connections
290 */
291static const struct color_conversion sdtv_csc_yprpb = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800292 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
293 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
294 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800295};
296
Jesse Barnes79e53942008-11-07 14:24:08 -0800297static const struct color_conversion hdtv_csc_yprpb = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800298 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
299 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
300 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800301};
302
Jesse Barnes79e53942008-11-07 14:24:08 -0800303static const struct video_levels component_levels = {
304 .blank = 279, .black = 279, .burst = 0,
305};
306
307
308struct tv_mode {
Chris Wilson763a4a02010-09-05 00:52:34 +0100309 const char *name;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100310
311 u32 clock;
312 u16 refresh; /* in millihertz (for precision) */
Jesse Barnes79e53942008-11-07 14:24:08 -0800313 u32 oversample;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100314 u8 hsync_end;
315 u16 hblank_start, hblank_end, htotal;
316 bool progressive : 1, trilevel_sync : 1, component_only : 1;
317 u8 vsync_start_f1, vsync_start_f2, vsync_len;
318 bool veq_ena : 1;
319 u8 veq_start_f1, veq_start_f2, veq_len;
320 u8 vi_end_f1, vi_end_f2;
321 u16 nbr_end;
322 bool burst_ena : 1;
323 u8 hburst_start, hburst_len;
324 u8 vburst_start_f1;
325 u16 vburst_end_f1;
326 u8 vburst_start_f2;
327 u16 vburst_end_f2;
328 u8 vburst_start_f3;
329 u16 vburst_end_f3;
330 u8 vburst_start_f4;
331 u16 vburst_end_f4;
Jesse Barnes79e53942008-11-07 14:24:08 -0800332 /*
333 * subcarrier programming
334 */
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100335 u16 dda2_size, dda3_size;
336 u8 dda1_inc;
337 u16 dda2_inc, dda3_inc;
Jesse Barnes79e53942008-11-07 14:24:08 -0800338 u32 sc_reset;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100339 bool pal_burst : 1;
Jesse Barnes79e53942008-11-07 14:24:08 -0800340 /*
341 * blank/black levels
342 */
343 const struct video_levels *composite_levels, *svideo_levels;
344 const struct color_conversion *composite_color, *svideo_color;
345 const u32 *filter_table;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100346 u16 max_srcw;
Jesse Barnes79e53942008-11-07 14:24:08 -0800347};
348
349
350/*
351 * Sub carrier DDA
352 *
353 * I think this works as follows:
354 *
355 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
356 *
357 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
358 *
359 * So,
360 * dda1_ideal = subcarrier/pixel * 4096
361 * dda1_inc = floor (dda1_ideal)
362 * dda2 = dda1_ideal - dda1_inc
363 *
364 * then pick a ratio for dda2 that gives the closest approximation. If
365 * you can't get close enough, you can play with dda3 as well. This
366 * seems likely to happen when dda2 is small as the jumps would be larger
367 *
368 * To invert this,
369 *
370 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
371 *
372 * The constants below were all computed using a 107.520MHz clock
373 */
374
375/**
376 * Register programming values for TV modes.
377 *
378 * These values account for -1s required.
379 */
380
Tobias Klauser005568b2009-02-09 22:02:42 +0100381static const struct tv_mode tv_modes[] = {
Jesse Barnes79e53942008-11-07 14:24:08 -0800382 {
383 .name = "NTSC-M",
Zhenyu Wangba010792009-03-04 20:23:02 +0800384 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200385 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800386 .oversample = TV_OVERSAMPLE_8X,
387 .component_only = 0,
388 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
389
390 .hsync_end = 64, .hblank_end = 124,
391 .hblank_start = 836, .htotal = 857,
392
393 .progressive = false, .trilevel_sync = false,
394
395 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
396 .vsync_len = 6,
397
Akshay Joshi0206e352011-08-16 15:34:10 -0400398 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800399 .veq_start_f2 = 1, .veq_len = 18,
400
401 .vi_end_f1 = 20, .vi_end_f2 = 21,
402 .nbr_end = 240,
403
404 .burst_ena = true,
405 .hburst_start = 72, .hburst_len = 34,
406 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
407 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
408 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
409 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
410
411 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800412 .dda1_inc = 135,
413 .dda2_inc = 20800, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800414 .dda3_inc = 0, .dda3_size = 0,
415 .sc_reset = TV_SC_RESET_EVERY_4,
416 .pal_burst = false,
417
418 .composite_levels = &ntsc_m_levels_composite,
419 .composite_color = &ntsc_m_csc_composite,
420 .svideo_levels = &ntsc_m_levels_svideo,
421 .svideo_color = &ntsc_m_csc_svideo,
422
423 .filter_table = filter_table,
424 },
425 {
426 .name = "NTSC-443",
Zhenyu Wangba010792009-03-04 20:23:02 +0800427 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200428 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800429 .oversample = TV_OVERSAMPLE_8X,
430 .component_only = 0,
431 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
432 .hsync_end = 64, .hblank_end = 124,
433 .hblank_start = 836, .htotal = 857,
434
435 .progressive = false, .trilevel_sync = false,
436
437 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
438 .vsync_len = 6,
439
Akshay Joshi0206e352011-08-16 15:34:10 -0400440 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800441 .veq_start_f2 = 1, .veq_len = 18,
442
443 .vi_end_f1 = 20, .vi_end_f2 = 21,
444 .nbr_end = 240,
445
Chris Wilson3ca87e82010-06-06 15:40:23 +0100446 .burst_ena = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800447 .hburst_start = 72, .hburst_len = 34,
448 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
449 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
450 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
451 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
452
453 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
454 .dda1_inc = 168,
Zhenyu Wangba010792009-03-04 20:23:02 +0800455 .dda2_inc = 4093, .dda2_size = 27456,
456 .dda3_inc = 310, .dda3_size = 525,
457 .sc_reset = TV_SC_RESET_NEVER,
458 .pal_burst = false,
Jesse Barnes79e53942008-11-07 14:24:08 -0800459
460 .composite_levels = &ntsc_m_levels_composite,
461 .composite_color = &ntsc_m_csc_composite,
462 .svideo_levels = &ntsc_m_levels_svideo,
463 .svideo_color = &ntsc_m_csc_svideo,
464
465 .filter_table = filter_table,
466 },
467 {
468 .name = "NTSC-J",
Zhenyu Wangba010792009-03-04 20:23:02 +0800469 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200470 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800471 .oversample = TV_OVERSAMPLE_8X,
472 .component_only = 0,
473
474 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
475 .hsync_end = 64, .hblank_end = 124,
476 .hblank_start = 836, .htotal = 857,
477
478 .progressive = false, .trilevel_sync = false,
479
480 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
481 .vsync_len = 6,
482
Akshay Joshi0206e352011-08-16 15:34:10 -0400483 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800484 .veq_start_f2 = 1, .veq_len = 18,
485
486 .vi_end_f1 = 20, .vi_end_f2 = 21,
487 .nbr_end = 240,
488
489 .burst_ena = true,
490 .hburst_start = 72, .hburst_len = 34,
491 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
492 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
493 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
494 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
495
496 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800497 .dda1_inc = 135,
498 .dda2_inc = 20800, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800499 .dda3_inc = 0, .dda3_size = 0,
500 .sc_reset = TV_SC_RESET_EVERY_4,
501 .pal_burst = false,
502
503 .composite_levels = &ntsc_j_levels_composite,
504 .composite_color = &ntsc_j_csc_composite,
505 .svideo_levels = &ntsc_j_levels_svideo,
506 .svideo_color = &ntsc_j_csc_svideo,
507
508 .filter_table = filter_table,
509 },
510 {
511 .name = "PAL-M",
Zhenyu Wangba010792009-03-04 20:23:02 +0800512 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200513 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800514 .oversample = TV_OVERSAMPLE_8X,
515 .component_only = 0,
516
517 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
518 .hsync_end = 64, .hblank_end = 124,
519 .hblank_start = 836, .htotal = 857,
520
521 .progressive = false, .trilevel_sync = false,
522
523 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
524 .vsync_len = 6,
525
Akshay Joshi0206e352011-08-16 15:34:10 -0400526 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800527 .veq_start_f2 = 1, .veq_len = 18,
528
529 .vi_end_f1 = 20, .vi_end_f2 = 21,
530 .nbr_end = 240,
531
532 .burst_ena = true,
533 .hburst_start = 72, .hburst_len = 34,
534 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
535 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
536 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
537 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
538
539 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800540 .dda1_inc = 135,
541 .dda2_inc = 16704, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800542 .dda3_inc = 0, .dda3_size = 0,
Zhenyu Wangba010792009-03-04 20:23:02 +0800543 .sc_reset = TV_SC_RESET_EVERY_8,
544 .pal_burst = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800545
546 .composite_levels = &pal_m_levels_composite,
547 .composite_color = &pal_m_csc_composite,
548 .svideo_levels = &pal_m_levels_svideo,
549 .svideo_color = &pal_m_csc_svideo,
550
551 .filter_table = filter_table,
552 },
553 {
554 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
555 .name = "PAL-N",
Zhenyu Wangba010792009-03-04 20:23:02 +0800556 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200557 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800558 .oversample = TV_OVERSAMPLE_8X,
559 .component_only = 0,
560
561 .hsync_end = 64, .hblank_end = 128,
562 .hblank_start = 844, .htotal = 863,
563
564 .progressive = false, .trilevel_sync = false,
565
566
567 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
568 .vsync_len = 6,
569
Akshay Joshi0206e352011-08-16 15:34:10 -0400570 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800571 .veq_start_f2 = 1, .veq_len = 18,
572
573 .vi_end_f1 = 24, .vi_end_f2 = 25,
574 .nbr_end = 286,
575
576 .burst_ena = true,
Akshay Joshi0206e352011-08-16 15:34:10 -0400577 .hburst_start = 73, .hburst_len = 34,
Jesse Barnes79e53942008-11-07 14:24:08 -0800578 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
579 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
580 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
581 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
582
583
584 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800585 .dda1_inc = 135,
586 .dda2_inc = 23578, .dda2_size = 27648,
587 .dda3_inc = 134, .dda3_size = 625,
Jesse Barnes79e53942008-11-07 14:24:08 -0800588 .sc_reset = TV_SC_RESET_EVERY_8,
589 .pal_burst = true,
590
591 .composite_levels = &pal_n_levels_composite,
592 .composite_color = &pal_n_csc_composite,
593 .svideo_levels = &pal_n_levels_svideo,
594 .svideo_color = &pal_n_csc_svideo,
595
596 .filter_table = filter_table,
597 },
598 {
599 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
600 .name = "PAL",
Zhenyu Wangba010792009-03-04 20:23:02 +0800601 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200602 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800603 .oversample = TV_OVERSAMPLE_8X,
604 .component_only = 0,
605
Zhenyu Wangba010792009-03-04 20:23:02 +0800606 .hsync_end = 64, .hblank_end = 142,
Jesse Barnes79e53942008-11-07 14:24:08 -0800607 .hblank_start = 844, .htotal = 863,
608
609 .progressive = false, .trilevel_sync = false,
610
611 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
612 .vsync_len = 5,
613
Akshay Joshi0206e352011-08-16 15:34:10 -0400614 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800615 .veq_start_f2 = 1, .veq_len = 15,
616
617 .vi_end_f1 = 24, .vi_end_f2 = 25,
618 .nbr_end = 286,
619
620 .burst_ena = true,
621 .hburst_start = 73, .hburst_len = 32,
622 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
623 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
624 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
625 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
626
627 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
628 .dda1_inc = 168,
Zhenyu Wangba010792009-03-04 20:23:02 +0800629 .dda2_inc = 4122, .dda2_size = 27648,
630 .dda3_inc = 67, .dda3_size = 625,
Jesse Barnes79e53942008-11-07 14:24:08 -0800631 .sc_reset = TV_SC_RESET_EVERY_8,
632 .pal_burst = true,
633
634 .composite_levels = &pal_levels_composite,
635 .composite_color = &pal_csc_composite,
636 .svideo_levels = &pal_levels_svideo,
637 .svideo_color = &pal_csc_svideo,
638
639 .filter_table = filter_table,
640 },
641 {
Rodrigo Vivi95899192012-05-22 15:23:24 -0300642 .name = "480p",
643 .clock = 107520,
644 .refresh = 59940,
645 .oversample = TV_OVERSAMPLE_4X,
646 .component_only = 1,
647
648 .hsync_end = 64, .hblank_end = 122,
649 .hblank_start = 842, .htotal = 857,
650
651 .progressive = true, .trilevel_sync = false,
652
653 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
654 .vsync_len = 12,
655
656 .veq_ena = false,
657
658 .vi_end_f1 = 44, .vi_end_f2 = 44,
659 .nbr_end = 479,
660
661 .burst_ena = false,
662
663 .filter_table = filter_table,
664 },
665 {
666 .name = "576p",
667 .clock = 107520,
668 .refresh = 50000,
669 .oversample = TV_OVERSAMPLE_4X,
670 .component_only = 1,
671
672 .hsync_end = 64, .hblank_end = 139,
673 .hblank_start = 859, .htotal = 863,
674
675 .progressive = true, .trilevel_sync = false,
676
677 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
678 .vsync_len = 10,
679
680 .veq_ena = false,
681
682 .vi_end_f1 = 48, .vi_end_f2 = 48,
683 .nbr_end = 575,
684
685 .burst_ena = false,
686
687 .filter_table = filter_table,
688 },
689 {
Jesse Barnes79e53942008-11-07 14:24:08 -0800690 .name = "720p@60Hz",
691 .clock = 148800,
692 .refresh = 60000,
693 .oversample = TV_OVERSAMPLE_2X,
694 .component_only = 1,
695
696 .hsync_end = 80, .hblank_end = 300,
697 .hblank_start = 1580, .htotal = 1649,
698
Akshay Joshi0206e352011-08-16 15:34:10 -0400699 .progressive = true, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800700
701 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
702 .vsync_len = 10,
703
704 .veq_ena = false,
705
706 .vi_end_f1 = 29, .vi_end_f2 = 29,
707 .nbr_end = 719,
708
709 .burst_ena = false,
710
711 .filter_table = filter_table,
712 },
713 {
Jesse Barnes79e53942008-11-07 14:24:08 -0800714 .name = "720p@50Hz",
715 .clock = 148800,
716 .refresh = 50000,
717 .oversample = TV_OVERSAMPLE_2X,
718 .component_only = 1,
719
720 .hsync_end = 80, .hblank_end = 300,
721 .hblank_start = 1580, .htotal = 1979,
722
Akshay Joshi0206e352011-08-16 15:34:10 -0400723 .progressive = true, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800724
725 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
726 .vsync_len = 10,
727
728 .veq_ena = false,
729
730 .vi_end_f1 = 29, .vi_end_f2 = 29,
731 .nbr_end = 719,
732
733 .burst_ena = false,
734
735 .filter_table = filter_table,
736 .max_srcw = 800
737 },
738 {
739 .name = "1080i@50Hz",
740 .clock = 148800,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200741 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800742 .oversample = TV_OVERSAMPLE_2X,
743 .component_only = 1,
744
745 .hsync_end = 88, .hblank_end = 235,
746 .hblank_start = 2155, .htotal = 2639,
747
Akshay Joshi0206e352011-08-16 15:34:10 -0400748 .progressive = false, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800749
750 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
751 .vsync_len = 10,
752
Akshay Joshi0206e352011-08-16 15:34:10 -0400753 .veq_ena = true, .veq_start_f1 = 4,
Jesse Barnes79e53942008-11-07 14:24:08 -0800754 .veq_start_f2 = 4, .veq_len = 10,
755
756
757 .vi_end_f1 = 21, .vi_end_f2 = 22,
758 .nbr_end = 539,
759
760 .burst_ena = false,
761
762 .filter_table = filter_table,
763 },
764 {
765 .name = "1080i@60Hz",
766 .clock = 148800,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200767 .refresh = 60000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800768 .oversample = TV_OVERSAMPLE_2X,
769 .component_only = 1,
770
771 .hsync_end = 88, .hblank_end = 235,
772 .hblank_start = 2155, .htotal = 2199,
773
Akshay Joshi0206e352011-08-16 15:34:10 -0400774 .progressive = false, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800775
776 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
777 .vsync_len = 10,
778
Akshay Joshi0206e352011-08-16 15:34:10 -0400779 .veq_ena = true, .veq_start_f1 = 4,
Jesse Barnes79e53942008-11-07 14:24:08 -0800780 .veq_start_f2 = 4, .veq_len = 10,
781
782
783 .vi_end_f1 = 21, .vi_end_f2 = 22,
784 .nbr_end = 539,
785
786 .burst_ena = false,
787
788 .filter_table = filter_table,
789 },
Jesse Barnes79e53942008-11-07 14:24:08 -0800790};
791
Daniel Vettercd91ef22013-07-21 21:37:02 +0200792static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
Chris Wilsonea5b2132010-08-04 13:50:23 +0100793{
Daniel Vettercd91ef22013-07-21 21:37:02 +0200794 return container_of(encoder, struct intel_tv, base);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100795}
796
Chris Wilsondf0e9242010-09-09 16:20:55 +0100797static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
798{
Daniel Vettercd91ef22013-07-21 21:37:02 +0200799 return enc_to_tv(intel_attached_encoder(connector));
Chris Wilsondf0e9242010-09-09 16:20:55 +0100800}
801
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200802static bool
803intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
Jesse Barnes79e53942008-11-07 14:24:08 -0800804{
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200805 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100806 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200807 u32 tmp = I915_READ(TV_CTL);
808
809 if (!(tmp & TV_ENC_ENABLE))
810 return false;
811
812 *pipe = PORT_TO_PIPE(tmp);
813
814 return true;
815}
816
Jesse Barnes79e53942008-11-07 14:24:08 -0800817static void
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200818intel_enable_tv(struct intel_encoder *encoder,
819 struct intel_crtc_state *pipe_config,
820 struct drm_connector_state *conn_state)
Jesse Barnes79e53942008-11-07 14:24:08 -0800821{
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200822 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100823 struct drm_i915_private *dev_priv = to_i915(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -0800824
Ville Syrjälä7a989482014-09-08 17:43:01 +0300825 /* Prevents vblank waits from timing out in intel_tv_detect_type() */
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +0200826 intel_wait_for_vblank(dev_priv,
Ville Syrjälä7a989482014-09-08 17:43:01 +0300827 to_intel_crtc(encoder->base.crtc)->pipe);
828
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200829 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
830}
831
832static void
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200833intel_disable_tv(struct intel_encoder *encoder,
834 struct intel_crtc_state *old_crtc_state,
835 struct drm_connector_state *old_conn_state)
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200836{
837 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100838 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200839
840 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
Jesse Barnes79e53942008-11-07 14:24:08 -0800841}
842
Jesse Barnes79e53942008-11-07 14:24:08 -0800843static const struct tv_mode *
Chris Wilson763a4a02010-09-05 00:52:34 +0100844intel_tv_mode_lookup(const char *tv_format)
Jesse Barnes79e53942008-11-07 14:24:08 -0800845{
846 int i;
847
Dave Airlie3801a7f2012-04-20 13:13:54 +0100848 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
Jesse Barnes79e53942008-11-07 14:24:08 -0800849 const struct tv_mode *tv_mode = &tv_modes[i];
850
851 if (!strcmp(tv_format, tv_mode->name))
852 return tv_mode;
853 }
854 return NULL;
855}
856
857static const struct tv_mode *
Chris Wilson763a4a02010-09-05 00:52:34 +0100858intel_tv_mode_find(struct intel_tv *intel_tv)
Jesse Barnes79e53942008-11-07 14:24:08 -0800859{
Chris Wilsonea5b2132010-08-04 13:50:23 +0100860 return intel_tv_mode_lookup(intel_tv->tv_format);
Jesse Barnes79e53942008-11-07 14:24:08 -0800861}
862
863static enum drm_mode_status
Chris Wilson763a4a02010-09-05 00:52:34 +0100864intel_tv_mode_valid(struct drm_connector *connector,
865 struct drm_display_mode *mode)
Jesse Barnes79e53942008-11-07 14:24:08 -0800866{
Chris Wilsondf0e9242010-09-09 16:20:55 +0100867 struct intel_tv *intel_tv = intel_attached_tv(connector);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100868 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
Mika Kahola54c032b2016-02-02 15:16:43 +0200869 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
870
871 if (mode->clock > max_dotclk)
872 return MODE_CLOCK_HIGH;
Jesse Barnes79e53942008-11-07 14:24:08 -0800873
874 /* Ensure TV refresh is close to desired refresh */
Zhao Yakui0d0884c2009-09-29 16:31:49 +0800875 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
876 < 1000)
Jesse Barnes79e53942008-11-07 14:24:08 -0800877 return MODE_OK;
Chris Wilson763a4a02010-09-05 00:52:34 +0100878
Jesse Barnes79e53942008-11-07 14:24:08 -0800879 return MODE_CLOCK_RANGE;
880}
881
882
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100883static void
884intel_tv_get_config(struct intel_encoder *encoder,
Ander Conselvan de Oliveira5cec2582015-01-15 14:55:21 +0200885 struct intel_crtc_state *pipe_config)
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100886{
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200887 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100888}
889
Jesse Barnes79e53942008-11-07 14:24:08 -0800890static bool
Daniel Vetter5d2d38d2013-03-27 00:45:01 +0100891intel_tv_compute_config(struct intel_encoder *encoder,
Maarten Lankhorst0a478c22016-08-09 17:04:05 +0200892 struct intel_crtc_state *pipe_config,
893 struct drm_connector_state *conn_state)
Jesse Barnes79e53942008-11-07 14:24:08 -0800894{
Daniel Vettercd91ef22013-07-21 21:37:02 +0200895 struct intel_tv *intel_tv = enc_to_tv(encoder);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100896 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
Jesse Barnes79e53942008-11-07 14:24:08 -0800897
898 if (!tv_mode)
899 return false;
900
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200901 pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
Daniel Vetter5d2d38d2013-03-27 00:45:01 +0100902 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
903 pipe_config->pipe_bpp = 8*3;
904
Daniel Vetter1062b812013-09-10 11:44:30 +0200905 /* TV has it's own notion of sync and other mode flags, so clear them. */
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200906 pipe_config->base.adjusted_mode.flags = 0;
Daniel Vetter1062b812013-09-10 11:44:30 +0200907
908 /*
909 * FIXME: We don't check whether the input mode is actually what we want
910 * or whether userspace is doing something stupid.
911 */
912
Jesse Barnes79e53942008-11-07 14:24:08 -0800913 return true;
914}
915
Daniel Vetter8cb92202014-04-24 23:54:39 +0200916static void
917set_tv_mode_timings(struct drm_i915_private *dev_priv,
918 const struct tv_mode *tv_mode,
919 bool burst_ena)
Jesse Barnes79e53942008-11-07 14:24:08 -0800920{
Jesse Barnes79e53942008-11-07 14:24:08 -0800921 u32 hctl1, hctl2, hctl3;
922 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
Jesse Barnes79e53942008-11-07 14:24:08 -0800923
Jesse Barnes79e53942008-11-07 14:24:08 -0800924 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
925 (tv_mode->htotal << TV_HTOTAL_SHIFT);
926
927 hctl2 = (tv_mode->hburst_start << 16) |
928 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
929
930 if (burst_ena)
931 hctl2 |= TV_BURST_ENA;
932
933 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
934 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
935
936 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
937 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
938 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
939
940 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
941 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
942 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
943
944 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
945 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
946 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
947
948 if (tv_mode->veq_ena)
949 vctl3 |= TV_EQUAL_ENA;
950
951 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
952 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
953
954 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
955 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
956
957 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
958 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
959
960 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
961 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
962
Daniel Vetter8cb92202014-04-24 23:54:39 +0200963 I915_WRITE(TV_H_CTL_1, hctl1);
964 I915_WRITE(TV_H_CTL_2, hctl2);
965 I915_WRITE(TV_H_CTL_3, hctl3);
966 I915_WRITE(TV_V_CTL_1, vctl1);
967 I915_WRITE(TV_V_CTL_2, vctl2);
968 I915_WRITE(TV_V_CTL_3, vctl3);
969 I915_WRITE(TV_V_CTL_4, vctl4);
970 I915_WRITE(TV_V_CTL_5, vctl5);
971 I915_WRITE(TV_V_CTL_6, vctl6);
972 I915_WRITE(TV_V_CTL_7, vctl7);
973}
974
Daniel Vetterb8866ef2014-04-24 23:54:40 +0200975static void set_color_conversion(struct drm_i915_private *dev_priv,
976 const struct color_conversion *color_conversion)
977{
978 if (!color_conversion)
979 return;
980
981 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
982 color_conversion->gy);
983 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
984 color_conversion->ay);
985 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
986 color_conversion->gu);
987 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
988 color_conversion->au);
989 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
990 color_conversion->gv);
991 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
992 color_conversion->av);
993}
994
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200995static void intel_tv_pre_enable(struct intel_encoder *encoder,
996 struct intel_crtc_state *pipe_config,
997 struct drm_connector_state *conn_state)
Daniel Vetter8cb92202014-04-24 23:54:39 +0200998{
Tvrtko Ursulin66478472016-11-16 08:55:40 +0000999 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
Daniel Vetter8cb92202014-04-24 23:54:39 +02001000 struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
1001 struct intel_tv *intel_tv = enc_to_tv(encoder);
1002 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1003 u32 tv_ctl;
1004 u32 scctl1, scctl2, scctl3;
1005 int i, j;
1006 const struct video_levels *video_levels;
1007 const struct color_conversion *color_conversion;
1008 bool burst_ena;
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001009 int xpos = 0x0, ypos = 0x0;
1010 unsigned int xsize, ysize;
Daniel Vetter8cb92202014-04-24 23:54:39 +02001011
1012 if (!tv_mode)
1013 return; /* can't happen (mode_prepare prevents this) */
1014
1015 tv_ctl = I915_READ(TV_CTL);
1016 tv_ctl &= TV_CTL_SAVE;
1017
1018 switch (intel_tv->type) {
1019 default:
1020 case DRM_MODE_CONNECTOR_Unknown:
1021 case DRM_MODE_CONNECTOR_Composite:
1022 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1023 video_levels = tv_mode->composite_levels;
1024 color_conversion = tv_mode->composite_color;
1025 burst_ena = tv_mode->burst_ena;
1026 break;
1027 case DRM_MODE_CONNECTOR_Component:
1028 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1029 video_levels = &component_levels;
1030 if (tv_mode->burst_ena)
1031 color_conversion = &sdtv_csc_yprpb;
1032 else
1033 color_conversion = &hdtv_csc_yprpb;
1034 burst_ena = false;
1035 break;
1036 case DRM_MODE_CONNECTOR_SVIDEO:
1037 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1038 video_levels = tv_mode->svideo_levels;
1039 color_conversion = tv_mode->svideo_color;
1040 burst_ena = tv_mode->burst_ena;
1041 break;
1042 }
1043
Jesse Barnes79e53942008-11-07 14:24:08 -08001044 if (intel_crtc->pipe == 1)
1045 tv_ctl |= TV_ENC_PIPEB_SELECT;
1046 tv_ctl |= tv_mode->oversample;
1047
1048 if (tv_mode->progressive)
1049 tv_ctl |= TV_PROGRESSIVE;
1050 if (tv_mode->trilevel_sync)
1051 tv_ctl |= TV_TRILEVEL_SYNC;
1052 if (tv_mode->pal_burst)
1053 tv_ctl |= TV_PAL_BURST;
Jesse Barnes79e53942008-11-07 14:24:08 -08001054
Chris Wilsond2718172009-11-27 13:06:56 +00001055 scctl1 = 0;
1056 if (tv_mode->dda1_inc)
1057 scctl1 |= TV_SC_DDA1_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001058 if (tv_mode->dda2_inc)
1059 scctl1 |= TV_SC_DDA2_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001060 if (tv_mode->dda3_inc)
1061 scctl1 |= TV_SC_DDA3_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001062 scctl1 |= tv_mode->sc_reset;
Chris Wilsond2718172009-11-27 13:06:56 +00001063 if (video_levels)
1064 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
Jesse Barnes79e53942008-11-07 14:24:08 -08001065 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1066
1067 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1068 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1069
1070 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1071 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1072
1073 /* Enable two fixes for the chips that need them. */
Tvrtko Ursulin50a0bc92016-10-13 11:02:58 +01001074 if (IS_I915GM(dev_priv))
Jesse Barnes79e53942008-11-07 14:24:08 -08001075 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1076
Daniel Vetter8cb92202014-04-24 23:54:39 +02001077 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1078
Jesse Barnes79e53942008-11-07 14:24:08 -08001079 I915_WRITE(TV_SC_CTL_1, scctl1);
1080 I915_WRITE(TV_SC_CTL_2, scctl2);
1081 I915_WRITE(TV_SC_CTL_3, scctl3);
1082
Daniel Vetterb8866ef2014-04-24 23:54:40 +02001083 set_color_conversion(dev_priv, color_conversion);
Jesse Barnes79e53942008-11-07 14:24:08 -08001084
Tvrtko Ursulin66478472016-11-16 08:55:40 +00001085 if (INTEL_GEN(dev_priv) >= 4)
Zhenyu Wangd2d9f232009-03-04 19:36:02 +08001086 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1087 else
1088 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1089
Jesse Barnes79e53942008-11-07 14:24:08 -08001090 if (video_levels)
1091 I915_WRITE(TV_CLR_LEVEL,
1092 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1093 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
Jesse Barnes79e53942008-11-07 14:24:08 -08001094
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001095 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
Jesse Barnes79e53942008-11-07 14:24:08 -08001096
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001097 /* Filter ctl must be set before TV_WIN_SIZE */
1098 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1099 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1100 if (tv_mode->progressive)
1101 ysize = tv_mode->nbr_end + 1;
1102 else
1103 ysize = 2*tv_mode->nbr_end + 1;
Jesse Barnes79e53942008-11-07 14:24:08 -08001104
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001105 xpos += intel_tv->margin[TV_MARGIN_LEFT];
1106 ypos += intel_tv->margin[TV_MARGIN_TOP];
1107 xsize -= (intel_tv->margin[TV_MARGIN_LEFT] +
1108 intel_tv->margin[TV_MARGIN_RIGHT]);
1109 ysize -= (intel_tv->margin[TV_MARGIN_TOP] +
1110 intel_tv->margin[TV_MARGIN_BOTTOM]);
1111 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1112 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
Jesse Barnes79e53942008-11-07 14:24:08 -08001113
1114 j = 0;
1115 for (i = 0; i < 60; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001116 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001117 for (i = 0; i < 60; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001118 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001119 for (i = 0; i < 43; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001120 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001121 for (i = 0; i < 43; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001122 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
Chris Wilsonb8ed2a42010-09-05 00:43:42 +01001123 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
Jesse Barnes79e53942008-11-07 14:24:08 -08001124 I915_WRITE(TV_CTL, tv_ctl);
1125}
1126
1127static const struct drm_display_mode reported_modes[] = {
1128 {
1129 .name = "NTSC 480i",
1130 .clock = 107520,
1131 .hdisplay = 1280,
1132 .hsync_start = 1368,
1133 .hsync_end = 1496,
1134 .htotal = 1712,
1135
1136 .vdisplay = 1024,
1137 .vsync_start = 1027,
1138 .vsync_end = 1034,
1139 .vtotal = 1104,
1140 .type = DRM_MODE_TYPE_DRIVER,
1141 },
1142};
1143
1144/**
1145 * Detects TV presence by checking for load.
1146 *
1147 * Requires that the current pipe's DPLL is active.
1148
1149 * \return true if TV is connected.
1150 * \return false if TV is disconnected.
1151 */
1152static int
Akshay Joshi0206e352011-08-16 15:34:10 -04001153intel_tv_detect_type(struct intel_tv *intel_tv,
Chris Wilson8102e122011-02-10 10:05:35 +00001154 struct drm_connector *connector)
Jesse Barnes79e53942008-11-07 14:24:08 -08001155{
Maarten Lankhorst0eadc622016-02-17 09:18:37 +01001156 struct drm_crtc *crtc = connector->state->crtc;
Keith Packard835bff72011-05-12 17:10:57 -07001157 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
Maarten Lankhorst0eadc622016-02-17 09:18:37 +01001158 struct drm_device *dev = connector->dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +01001159 struct drm_i915_private *dev_priv = to_i915(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -08001160 u32 tv_ctl, save_tv_ctl;
1161 u32 tv_dac, save_tv_dac;
Chris Wilson974b9332010-09-05 00:44:20 +01001162 int type;
Jesse Barnes79e53942008-11-07 14:24:08 -08001163
1164 /* Disable TV interrupts around load detect or we'll recurse */
Chris Wilson8102e122011-02-10 10:05:35 +00001165 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
Daniel Vetter2795aa482014-09-15 14:55:25 +02001166 spin_lock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001167 i915_disable_pipestat(dev_priv, 0,
Imre Deak755e9012014-02-10 18:42:47 +02001168 PIPE_HOTPLUG_INTERRUPT_STATUS |
1169 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
Daniel Vetter2795aa482014-09-15 14:55:25 +02001170 spin_unlock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001171 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001172
Chris Wilson974b9332010-09-05 00:44:20 +01001173 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1174 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1175
1176 /* Poll for TV detection */
1177 tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001178 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
Keith Packard835bff72011-05-12 17:10:57 -07001179 if (intel_crtc->pipe == 1)
1180 tv_ctl |= TV_ENC_PIPEB_SELECT;
1181 else
1182 tv_ctl &= ~TV_ENC_PIPEB_SELECT;
Chris Wilson974b9332010-09-05 00:44:20 +01001183
1184 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001185 tv_dac |= (TVDAC_STATE_CHG_EN |
1186 TVDAC_A_SENSE_CTL |
1187 TVDAC_B_SENSE_CTL |
1188 TVDAC_C_SENSE_CTL |
1189 DAC_CTL_OVERRIDE |
1190 DAC_A_0_7_V |
1191 DAC_B_0_7_V |
1192 DAC_C_0_7_V);
Chris Wilson974b9332010-09-05 00:44:20 +01001193
Daniel Vetterd42c9e22012-03-25 22:56:14 +02001194
1195 /*
1196 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1197 * the TV is misdetected. This is hardware requirement.
1198 */
Tvrtko Ursulin50a0bc92016-10-13 11:02:58 +01001199 if (IS_GM45(dev_priv))
Daniel Vetterd42c9e22012-03-25 22:56:14 +02001200 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1201 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1202
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001203 I915_WRITE(TV_CTL, tv_ctl);
1204 I915_WRITE(TV_DAC, tv_dac);
Pekka Enberg4f233ef2010-09-04 19:24:04 +03001205 POSTING_READ(TV_DAC);
Pekka Enberg4f233ef2010-09-04 19:24:04 +03001206
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +02001207 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
Chris Wilson29e13162010-09-22 19:10:09 +01001208
Chris Wilson974b9332010-09-05 00:44:20 +01001209 type = -1;
Keith Packard2bf71162011-05-12 17:10:58 -07001210 tv_dac = I915_READ(TV_DAC);
1211 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1212 /*
1213 * A B C
1214 * 0 1 1 Composite
1215 * 1 0 X svideo
1216 * 0 0 0 Component
1217 */
1218 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1219 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1220 type = DRM_MODE_CONNECTOR_Composite;
1221 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1222 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1223 type = DRM_MODE_CONNECTOR_SVIDEO;
1224 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1225 DRM_DEBUG_KMS("Detected Component TV connection\n");
1226 type = DRM_MODE_CONNECTOR_Component;
1227 } else {
1228 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1229 type = -1;
Jesse Barnes79e53942008-11-07 14:24:08 -08001230 }
1231
Chris Wilson974b9332010-09-05 00:44:20 +01001232 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1233 I915_WRITE(TV_CTL, save_tv_ctl);
Daniel Vetterbf2125e2012-05-22 21:41:25 +02001234 POSTING_READ(TV_CTL);
1235
1236 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +02001237 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
Chris Wilson974b9332010-09-05 00:44:20 +01001238
Jesse Barnes79e53942008-11-07 14:24:08 -08001239 /* Restore interrupt config */
Chris Wilson8102e122011-02-10 10:05:35 +00001240 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
Daniel Vetter2795aa482014-09-15 14:55:25 +02001241 spin_lock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001242 i915_enable_pipestat(dev_priv, 0,
Imre Deak755e9012014-02-10 18:42:47 +02001243 PIPE_HOTPLUG_INTERRUPT_STATUS |
1244 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
Daniel Vetter2795aa482014-09-15 14:55:25 +02001245 spin_unlock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001246 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001247
1248 return type;
1249}
1250
Ma Ling213c2e62009-08-24 13:50:25 +08001251/*
1252 * Here we set accurate tv format according to connector type
1253 * i.e Component TV should not be assigned by NTSC or PAL
1254 */
1255static void intel_tv_find_better_format(struct drm_connector *connector)
1256{
Chris Wilsondf0e9242010-09-09 16:20:55 +01001257 struct intel_tv *intel_tv = intel_attached_tv(connector);
Chris Wilsonea5b2132010-08-04 13:50:23 +01001258 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
Ma Ling213c2e62009-08-24 13:50:25 +08001259 int i;
1260
Chris Wilsonea5b2132010-08-04 13:50:23 +01001261 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
Ma Ling213c2e62009-08-24 13:50:25 +08001262 tv_mode->component_only)
1263 return;
1264
1265
Ville Syrjälä53abb672015-08-21 20:45:28 +03001266 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
Ma Ling213c2e62009-08-24 13:50:25 +08001267 tv_mode = tv_modes + i;
1268
Chris Wilsonea5b2132010-08-04 13:50:23 +01001269 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
Ma Ling213c2e62009-08-24 13:50:25 +08001270 tv_mode->component_only)
1271 break;
1272 }
1273
Chris Wilsonea5b2132010-08-04 13:50:23 +01001274 intel_tv->tv_format = tv_mode->name;
Rob Clark662595d2012-10-11 20:36:04 -05001275 drm_object_property_set_value(&connector->base,
Ma Ling213c2e62009-08-24 13:50:25 +08001276 connector->dev->mode_config.tv_mode_property, i);
1277}
1278
Jesse Barnes79e53942008-11-07 14:24:08 -08001279/**
1280 * Detect the TV connection.
1281 *
1282 * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
1283 * we have a pipe programmed in order to probe the TV.
1284 */
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001285static int
1286intel_tv_detect(struct drm_connector *connector,
1287 struct drm_modeset_acquire_ctx *ctx,
1288 bool force)
Jesse Barnes79e53942008-11-07 14:24:08 -08001289{
Jesse Barnes79e53942008-11-07 14:24:08 -08001290 struct drm_display_mode mode;
Chris Wilsondf0e9242010-09-09 16:20:55 +01001291 struct intel_tv *intel_tv = intel_attached_tv(connector);
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001292 enum drm_connector_status status;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001293 int type;
Jesse Barnes79e53942008-11-07 14:24:08 -08001294
Chris Wilson164c8592013-07-20 20:27:08 +01001295 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
Jani Nikulac23cc412014-06-03 14:56:17 +03001296 connector->base.id, connector->name,
Chris Wilson164c8592013-07-20 20:27:08 +01001297 force);
1298
Jesse Barnes79e53942008-11-07 14:24:08 -08001299 mode = reported_modes[0];
Jesse Barnes79e53942008-11-07 14:24:08 -08001300
Daniel Vetter38de45c2012-04-20 21:25:04 +02001301 if (force) {
Chris Wilson8261b192011-04-19 23:18:09 +01001302 struct intel_load_detect_pipe tmp;
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001303 int ret;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001304
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001305 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1306 if (ret < 0)
1307 return ret;
Ville Syrjälä208bf9f2014-08-11 13:15:35 +03001308
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001309 if (ret > 0) {
Chris Wilson8102e122011-02-10 10:05:35 +00001310 type = intel_tv_detect_type(intel_tv, connector);
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001311 intel_release_load_detect_pipe(connector, &tmp, ctx);
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001312 status = type < 0 ?
1313 connector_status_disconnected :
1314 connector_status_connected;
Jesse Barnes79e53942008-11-07 14:24:08 -08001315 } else
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001316 status = connector_status_unknown;
Chris Wilson7b334fc2010-09-09 23:51:02 +01001317 } else
1318 return connector->status;
Zhenyu Wangbf5a2692009-03-04 19:36:03 +08001319
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001320 if (status != connector_status_connected)
1321 return status;
Jesse Barnes79e53942008-11-07 14:24:08 -08001322
Mathew McKernand5627662011-04-12 06:51:37 +01001323 intel_tv->type = type;
Ma Ling213c2e62009-08-24 13:50:25 +08001324 intel_tv_find_better_format(connector);
Mathew McKernand5627662011-04-12 06:51:37 +01001325
Jesse Barnes79e53942008-11-07 14:24:08 -08001326 return connector_status_connected;
1327}
1328
Chris Wilson763a4a02010-09-05 00:52:34 +01001329static const struct input_res {
1330 const char *name;
Jesse Barnes79e53942008-11-07 14:24:08 -08001331 int w, h;
Chris Wilson763a4a02010-09-05 00:52:34 +01001332} input_res_table[] = {
Jesse Barnes79e53942008-11-07 14:24:08 -08001333 {"640x480", 640, 480},
1334 {"800x600", 800, 600},
1335 {"1024x768", 1024, 768},
1336 {"1280x1024", 1280, 1024},
1337 {"848x480", 848, 480},
1338 {"1280x720", 1280, 720},
1339 {"1920x1080", 1920, 1080},
1340};
1341
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001342/*
1343 * Chose preferred mode according to line number of TV format
1344 */
1345static void
1346intel_tv_chose_preferred_modes(struct drm_connector *connector,
1347 struct drm_display_mode *mode_ptr)
1348{
Chris Wilsondf0e9242010-09-09 16:20:55 +01001349 struct intel_tv *intel_tv = intel_attached_tv(connector);
Chris Wilsonea5b2132010-08-04 13:50:23 +01001350 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001351
1352 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1353 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1354 else if (tv_mode->nbr_end > 480) {
1355 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1356 if (mode_ptr->vdisplay == 720)
1357 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1358 } else if (mode_ptr->vdisplay == 1080)
1359 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1360 }
1361}
1362
Jesse Barnes79e53942008-11-07 14:24:08 -08001363/**
1364 * Stub get_modes function.
1365 *
1366 * This should probably return a set of fixed modes, unless we can figure out
1367 * how to probe modes off of TV connections.
1368 */
1369
1370static int
1371intel_tv_get_modes(struct drm_connector *connector)
1372{
1373 struct drm_display_mode *mode_ptr;
Chris Wilsondf0e9242010-09-09 16:20:55 +01001374 struct intel_tv *intel_tv = intel_attached_tv(connector);
Chris Wilsonea5b2132010-08-04 13:50:23 +01001375 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001376 int j, count = 0;
1377 u64 tmp;
Jesse Barnes79e53942008-11-07 14:24:08 -08001378
Kulikov Vasiliy04ad3272010-06-28 15:54:56 +04001379 for (j = 0; j < ARRAY_SIZE(input_res_table);
Jesse Barnes79e53942008-11-07 14:24:08 -08001380 j++) {
Chris Wilson763a4a02010-09-05 00:52:34 +01001381 const struct input_res *input = &input_res_table[j];
Jesse Barnes79e53942008-11-07 14:24:08 -08001382 unsigned int hactive_s = input->w;
1383 unsigned int vactive_s = input->h;
1384
1385 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1386 continue;
1387
1388 if (input->w > 1024 && (!tv_mode->progressive
1389 && !tv_mode->component_only))
1390 continue;
1391
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001392 mode_ptr = drm_mode_create(connector->dev);
1393 if (!mode_ptr)
1394 continue;
Jesse Barnes79e53942008-11-07 14:24:08 -08001395 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
Imre Deak05d25212016-01-29 14:52:29 +02001396 mode_ptr->name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
Jesse Barnes79e53942008-11-07 14:24:08 -08001397
1398 mode_ptr->hdisplay = hactive_s;
1399 mode_ptr->hsync_start = hactive_s + 1;
1400 mode_ptr->hsync_end = hactive_s + 64;
1401 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1402 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1403 mode_ptr->htotal = hactive_s + 96;
1404
1405 mode_ptr->vdisplay = vactive_s;
1406 mode_ptr->vsync_start = vactive_s + 1;
1407 mode_ptr->vsync_end = vactive_s + 32;
1408 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1409 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1410 mode_ptr->vtotal = vactive_s + 33;
1411
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001412 tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
1413 tmp *= mode_ptr->htotal;
1414 tmp = div_u64(tmp, 1000000);
1415 mode_ptr->clock = (int) tmp;
Jesse Barnes79e53942008-11-07 14:24:08 -08001416
1417 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001418 intel_tv_chose_preferred_modes(connector, mode_ptr);
Jesse Barnes79e53942008-11-07 14:24:08 -08001419 drm_mode_probed_add(connector, mode_ptr);
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001420 count++;
Jesse Barnes79e53942008-11-07 14:24:08 -08001421 }
1422
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001423 return count;
Jesse Barnes79e53942008-11-07 14:24:08 -08001424}
1425
1426static void
Akshay Joshi0206e352011-08-16 15:34:10 -04001427intel_tv_destroy(struct drm_connector *connector)
Jesse Barnes79e53942008-11-07 14:24:08 -08001428{
Jesse Barnes79e53942008-11-07 14:24:08 -08001429 drm_connector_cleanup(connector);
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001430 kfree(connector);
Jesse Barnes79e53942008-11-07 14:24:08 -08001431}
1432
1433
1434static int
1435intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
1436 uint64_t val)
1437{
1438 struct drm_device *dev = connector->dev;
Chris Wilsondf0e9242010-09-09 16:20:55 +01001439 struct intel_tv *intel_tv = intel_attached_tv(connector);
1440 struct drm_crtc *crtc = intel_tv->base.base.crtc;
Jesse Barnes79e53942008-11-07 14:24:08 -08001441 int ret = 0;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001442 bool changed = false;
Jesse Barnes79e53942008-11-07 14:24:08 -08001443
Rob Clark662595d2012-10-11 20:36:04 -05001444 ret = drm_object_property_set_value(&connector->base, property, val);
Jesse Barnes79e53942008-11-07 14:24:08 -08001445 if (ret < 0)
1446 goto out;
1447
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001448 if (property == dev->mode_config.tv_left_margin_property &&
Chris Wilsonea5b2132010-08-04 13:50:23 +01001449 intel_tv->margin[TV_MARGIN_LEFT] != val) {
1450 intel_tv->margin[TV_MARGIN_LEFT] = val;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001451 changed = true;
1452 } else if (property == dev->mode_config.tv_right_margin_property &&
Chris Wilsonea5b2132010-08-04 13:50:23 +01001453 intel_tv->margin[TV_MARGIN_RIGHT] != val) {
1454 intel_tv->margin[TV_MARGIN_RIGHT] = val;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001455 changed = true;
1456 } else if (property == dev->mode_config.tv_top_margin_property &&
Chris Wilsonea5b2132010-08-04 13:50:23 +01001457 intel_tv->margin[TV_MARGIN_TOP] != val) {
1458 intel_tv->margin[TV_MARGIN_TOP] = val;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001459 changed = true;
1460 } else if (property == dev->mode_config.tv_bottom_margin_property &&
Chris Wilsonea5b2132010-08-04 13:50:23 +01001461 intel_tv->margin[TV_MARGIN_BOTTOM] != val) {
1462 intel_tv->margin[TV_MARGIN_BOTTOM] = val;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001463 changed = true;
1464 } else if (property == dev->mode_config.tv_mode_property) {
Dan Carpenter29911962010-06-23 19:29:54 +02001465 if (val >= ARRAY_SIZE(tv_modes)) {
Jesse Barnes79e53942008-11-07 14:24:08 -08001466 ret = -EINVAL;
1467 goto out;
1468 }
Chris Wilsonea5b2132010-08-04 13:50:23 +01001469 if (!strcmp(intel_tv->tv_format, tv_modes[val].name))
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001470 goto out;
1471
Chris Wilsonea5b2132010-08-04 13:50:23 +01001472 intel_tv->tv_format = tv_modes[val].name;
Zhenyu Wangebcc8f22009-03-23 19:40:57 +08001473 changed = true;
Jesse Barnes79e53942008-11-07 14:24:08 -08001474 } else {
1475 ret = -EINVAL;
1476 goto out;
1477 }
1478
Zhenyu Wang7d6ff782009-03-24 00:45:13 +08001479 if (changed && crtc)
Chris Wilsonc0c36b942012-12-19 16:08:43 +00001480 intel_crtc_restore_mode(crtc);
Jesse Barnes79e53942008-11-07 14:24:08 -08001481out:
1482 return ret;
1483}
1484
Jesse Barnes79e53942008-11-07 14:24:08 -08001485static const struct drm_connector_funcs intel_tv_connector_funcs = {
Maarten Lankhorst4d688a22015-08-05 12:37:06 +02001486 .dpms = drm_atomic_helper_connector_dpms,
Chris Wilson1ebaa0b2016-06-24 14:00:15 +01001487 .late_register = intel_connector_register,
Chris Wilsonc191eca2016-06-17 11:40:33 +01001488 .early_unregister = intel_connector_unregister,
Jesse Barnes79e53942008-11-07 14:24:08 -08001489 .destroy = intel_tv_destroy,
1490 .set_property = intel_tv_set_property,
Matt Roper2545e4a2015-01-22 16:51:27 -08001491 .atomic_get_property = intel_connector_atomic_get_property,
Jesse Barnes79e53942008-11-07 14:24:08 -08001492 .fill_modes = drm_helper_probe_single_connector_modes,
Matt Roperc6f95f22015-01-22 16:50:32 -08001493 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Ander Conselvan de Oliveira98969722015-03-20 16:18:06 +02001494 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
Jesse Barnes79e53942008-11-07 14:24:08 -08001495};
1496
1497static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001498 .detect_ctx = intel_tv_detect,
Jesse Barnes79e53942008-11-07 14:24:08 -08001499 .mode_valid = intel_tv_mode_valid,
1500 .get_modes = intel_tv_get_modes,
Jesse Barnes79e53942008-11-07 14:24:08 -08001501};
1502
Jesse Barnes79e53942008-11-07 14:24:08 -08001503static const struct drm_encoder_funcs intel_tv_enc_funcs = {
Chris Wilsonea5b2132010-08-04 13:50:23 +01001504 .destroy = intel_encoder_destroy,
Jesse Barnes79e53942008-11-07 14:24:08 -08001505};
1506
Jesse Barnes79e53942008-11-07 14:24:08 -08001507void
Ander Conselvan de Oliveirac39055b2016-11-23 16:21:44 +02001508intel_tv_init(struct drm_i915_private *dev_priv)
Jesse Barnes79e53942008-11-07 14:24:08 -08001509{
Ander Conselvan de Oliveirac39055b2016-11-23 16:21:44 +02001510 struct drm_device *dev = &dev_priv->drm;
Jesse Barnes79e53942008-11-07 14:24:08 -08001511 struct drm_connector *connector;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001512 struct intel_tv *intel_tv;
Eric Anholt21d40d32010-03-25 11:11:14 -07001513 struct intel_encoder *intel_encoder;
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001514 struct intel_connector *intel_connector;
Jesse Barnes79e53942008-11-07 14:24:08 -08001515 u32 tv_dac_on, tv_dac_off, save_tv_dac;
Ville Syrjäläb7c914b2015-08-31 15:09:26 +03001516 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
Jesse Barnes79e53942008-11-07 14:24:08 -08001517 int i, initial_mode = 0;
1518
1519 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1520 return;
1521
Jani Nikula3bdd14d2016-03-16 12:43:29 +02001522 if (!intel_bios_is_tv_present(dev_priv)) {
Zhao Yakuic3561432009-11-24 09:48:48 +08001523 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1524 return;
1525 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001526
1527 /*
1528 * Sanity check the TV output by checking to see if the
1529 * DAC register holds a value
1530 */
1531 save_tv_dac = I915_READ(TV_DAC);
1532
1533 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1534 tv_dac_on = I915_READ(TV_DAC);
1535
1536 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1537 tv_dac_off = I915_READ(TV_DAC);
1538
1539 I915_WRITE(TV_DAC, save_tv_dac);
1540
1541 /*
1542 * If the register does not hold the state change enable
1543 * bit, (either as a 0 or a 1), assume it doesn't really
1544 * exist
1545 */
1546 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1547 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1548 return;
1549
Daniel Vetterb14c5672013-09-19 12:18:32 +02001550 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
Chris Wilsonea5b2132010-08-04 13:50:23 +01001551 if (!intel_tv) {
Jesse Barnes79e53942008-11-07 14:24:08 -08001552 return;
1553 }
Ma Lingf8aed702009-08-24 13:50:24 +08001554
Ander Conselvan de Oliveira08d9bc92015-04-10 10:59:10 +03001555 intel_connector = intel_connector_alloc();
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001556 if (!intel_connector) {
Chris Wilsonea5b2132010-08-04 13:50:23 +01001557 kfree(intel_tv);
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001558 return;
1559 }
1560
Chris Wilsonea5b2132010-08-04 13:50:23 +01001561 intel_encoder = &intel_tv->base;
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001562 connector = &intel_connector->base;
Jesse Barnes79e53942008-11-07 14:24:08 -08001563
Chris Wilson8102e122011-02-10 10:05:35 +00001564 /* The documentation, for the older chipsets at least, recommend
1565 * using a polling method rather than hotplug detection for TVs.
1566 * This is because in order to perform the hotplug detection, the PLLs
1567 * for the TV must be kept alive increasing power drain and starving
1568 * bandwidth from other encoders. Notably for instance, it causes
1569 * pipe underruns on Crestline when this encoder is supposedly idle.
1570 *
1571 * More recent chipsets favour HDMI rather than integrated S-Video.
1572 */
Egbert Eich821450c2013-04-16 13:36:55 +02001573 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
Chris Wilson8102e122011-02-10 10:05:35 +00001574
Jesse Barnes79e53942008-11-07 14:24:08 -08001575 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1576 DRM_MODE_CONNECTOR_SVIDEO);
1577
Chris Wilson4ef69c72010-09-09 15:14:28 +01001578 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
Ville Syrjälä580d8ed2016-05-27 20:59:24 +03001579 DRM_MODE_ENCODER_TVDAC, "TV");
Jesse Barnes79e53942008-11-07 14:24:08 -08001580
Daniel Vetter5d2d38d2013-03-27 00:45:01 +01001581 intel_encoder->compute_config = intel_tv_compute_config;
Daniel Vetter7a495cf2013-11-18 09:00:58 +01001582 intel_encoder->get_config = intel_tv_get_config;
Daniel Vetter809a2a82014-04-24 23:54:43 +02001583 intel_encoder->pre_enable = intel_tv_pre_enable;
Daniel Vetter6b5756a2012-06-30 10:33:44 +02001584 intel_encoder->enable = intel_enable_tv;
1585 intel_encoder->disable = intel_disable_tv;
Daniel Vetter9a8ee982012-07-02 13:34:59 +02001586 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1587 intel_connector->get_hw_state = intel_connector_get_hw_state;
Daniel Vetter6b5756a2012-06-30 10:33:44 +02001588
Chris Wilsondf0e9242010-09-09 16:20:55 +01001589 intel_connector_attach_encoder(intel_connector, intel_encoder);
Pandiyan, Dhinakaran03cdc1d2016-09-19 18:24:38 -07001590
Eric Anholt21d40d32010-03-25 11:11:14 -07001591 intel_encoder->type = INTEL_OUTPUT_TVOUT;
Ander Conselvan de Oliveira79f255a2017-02-22 08:34:27 +02001592 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
Pandiyan, Dhinakaran03cdc1d2016-09-19 18:24:38 -07001593 intel_encoder->port = PORT_NONE;
Eric Anholt21d40d32010-03-25 11:11:14 -07001594 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
Ville Syrjäläbc079e82014-03-03 16:15:28 +02001595 intel_encoder->cloneable = 0;
Chris Wilson4ef69c72010-09-09 15:14:28 +01001596 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
Chris Wilsonea5b2132010-08-04 13:50:23 +01001597 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
Jesse Barnes79e53942008-11-07 14:24:08 -08001598
1599 /* BIOS margin values */
Chris Wilsonea5b2132010-08-04 13:50:23 +01001600 intel_tv->margin[TV_MARGIN_LEFT] = 54;
1601 intel_tv->margin[TV_MARGIN_TOP] = 36;
1602 intel_tv->margin[TV_MARGIN_RIGHT] = 46;
1603 intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
Jesse Barnes79e53942008-11-07 14:24:08 -08001604
Chris Wilson763a4a02010-09-05 00:52:34 +01001605 intel_tv->tv_format = tv_modes[initial_mode].name;
Jesse Barnes79e53942008-11-07 14:24:08 -08001606
Jesse Barnes79e53942008-11-07 14:24:08 -08001607 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1608 connector->interlace_allowed = false;
1609 connector->doublescan_allowed = false;
1610
1611 /* Create TV properties then attach current values */
Dan Carpenter29911962010-06-23 19:29:54 +02001612 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
Ville Syrjäläb7c914b2015-08-31 15:09:26 +03001613 tv_format_names[i] = tv_modes[i].name;
Chris Wilson763a4a02010-09-05 00:52:34 +01001614 drm_mode_create_tv_properties(dev,
1615 ARRAY_SIZE(tv_modes),
1616 tv_format_names);
Jesse Barnes79e53942008-11-07 14:24:08 -08001617
Rob Clark662595d2012-10-11 20:36:04 -05001618 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
Jesse Barnes79e53942008-11-07 14:24:08 -08001619 initial_mode);
Rob Clark662595d2012-10-11 20:36:04 -05001620 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001621 dev->mode_config.tv_left_margin_property,
Chris Wilsonea5b2132010-08-04 13:50:23 +01001622 intel_tv->margin[TV_MARGIN_LEFT]);
Rob Clark662595d2012-10-11 20:36:04 -05001623 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001624 dev->mode_config.tv_top_margin_property,
Chris Wilsonea5b2132010-08-04 13:50:23 +01001625 intel_tv->margin[TV_MARGIN_TOP]);
Rob Clark662595d2012-10-11 20:36:04 -05001626 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001627 dev->mode_config.tv_right_margin_property,
Chris Wilsonea5b2132010-08-04 13:50:23 +01001628 intel_tv->margin[TV_MARGIN_RIGHT]);
Rob Clark662595d2012-10-11 20:36:04 -05001629 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001630 dev->mode_config.tv_bottom_margin_property,
Chris Wilsonea5b2132010-08-04 13:50:23 +01001631 intel_tv->margin[TV_MARGIN_BOTTOM]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001632}