blob: 885fc3809f7f904e8bc82e0eeee9cddd3dcef3f4 [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
Chris Wilsonea5b2132010-08-04 13:50:23 +010046struct intel_tv {
47 struct intel_encoder base;
48
Jesse Barnes79e53942008-11-07 14:24:08 -080049 int type;
Jesse Barnes79e53942008-11-07 14:24:08 -080050};
51
52struct video_levels {
Tvrtko Ursulindb492962016-10-13 11:09:26 +010053 u16 blank, black;
54 u8 burst;
Jesse Barnes79e53942008-11-07 14:24:08 -080055};
56
57struct color_conversion {
58 u16 ry, gy, by, ay;
59 u16 ru, gu, bu, au;
60 u16 rv, gv, bv, av;
61};
62
63static const u32 filter_table[] = {
64 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
65 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
66 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
67 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
68 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
69 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
70 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
71 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
72 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
73 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
74 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
75 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
76 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
77 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
78 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
79 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
80 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
81 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
82 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
83 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
84 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
85 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
86 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
87 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
88 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
89 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
90 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
91 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
92 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
93 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
94 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
95 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
96 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
97 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
98 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
99 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
100 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
101 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
102 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
103 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
104 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
105 0x2D002CC0, 0x30003640, 0x2D0036C0,
106 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
107 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
108 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
109 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
110 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
111 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
112 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
113 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
114 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
115 0x28003100, 0x28002F00, 0x00003100,
116};
117
118/*
119 * Color conversion values have 3 separate fixed point formats:
120 *
121 * 10 bit fields (ay, au)
122 * 1.9 fixed point (b.bbbbbbbbb)
123 * 11 bit fields (ry, by, ru, gu, gv)
124 * exp.mantissa (ee.mmmmmmmmm)
125 * ee = 00 = 10^-1 (0.mmmmmmmmm)
126 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
127 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
128 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
129 * 12 bit fields (gy, rv, bu)
130 * exp.mantissa (eee.mmmmmmmmm)
131 * eee = 000 = 10^-1 (0.mmmmmmmmm)
132 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
133 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
134 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
135 * eee = 100 = reserved
136 * eee = 101 = reserved
137 * eee = 110 = reserved
138 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
139 *
140 * Saturation and contrast are 8 bits, with their own representation:
141 * 8 bit field (saturation, contrast)
142 * exp.mantissa (ee.mmmmmm)
143 * ee = 00 = 10^-1 (0.mmmmmm)
144 * ee = 01 = 10^0 (m.mmmmm)
145 * ee = 10 = 10^1 (mm.mmmm)
146 * ee = 11 = 10^2 (mmm.mmm)
147 *
148 * Simple conversion function:
149 *
150 * static u32
151 * float_to_csc_11(float f)
152 * {
153 * u32 exp;
154 * u32 mant;
155 * u32 ret;
156 *
157 * if (f < 0)
158 * f = -f;
159 *
160 * if (f >= 1) {
161 * exp = 0x7;
Akshay Joshi0206e352011-08-16 15:34:10 -0400162 * mant = 1 << 8;
Jesse Barnes79e53942008-11-07 14:24:08 -0800163 * } else {
164 * for (exp = 0; exp < 3 && f < 0.5; exp++)
Akshay Joshi0206e352011-08-16 15:34:10 -0400165 * f *= 2.0;
Jesse Barnes79e53942008-11-07 14:24:08 -0800166 * mant = (f * (1 << 9) + 0.5);
167 * if (mant >= (1 << 9))
168 * mant = (1 << 9) - 1;
169 * }
170 * ret = (exp << 9) | mant;
171 * return ret;
172 * }
173 */
174
175/*
176 * Behold, magic numbers! If we plant them they might grow a big
177 * s-video cable to the sky... or something.
178 *
179 * Pre-converted to appropriate hex value.
180 */
181
182/*
183 * PAL & NTSC values for composite & s-video connections
184 */
185static const struct color_conversion ntsc_m_csc_composite = {
186 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800187 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
188 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800189};
190
191static const struct video_levels ntsc_m_levels_composite = {
192 .blank = 225, .black = 267, .burst = 113,
193};
194
195static const struct color_conversion ntsc_m_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800196 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
197 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
198 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800199};
200
201static const struct video_levels ntsc_m_levels_svideo = {
202 .blank = 266, .black = 316, .burst = 133,
203};
204
205static const struct color_conversion ntsc_j_csc_composite = {
206 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
Zhenyu Wangba010792009-03-04 20:23:02 +0800207 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
208 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800209};
210
211static const struct video_levels ntsc_j_levels_composite = {
212 .blank = 225, .black = 225, .burst = 113,
213};
214
215static const struct color_conversion ntsc_j_csc_svideo = {
216 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
Zhenyu Wangba010792009-03-04 20:23:02 +0800217 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
218 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800219};
220
221static const struct video_levels ntsc_j_levels_svideo = {
222 .blank = 266, .black = 266, .burst = 133,
223};
224
225static const struct color_conversion pal_csc_composite = {
226 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
Zhenyu Wangba010792009-03-04 20:23:02 +0800227 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
228 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800229};
230
231static const struct video_levels pal_levels_composite = {
232 .blank = 237, .black = 237, .burst = 118,
233};
234
235static const struct color_conversion pal_csc_svideo = {
236 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
Zhenyu Wangba010792009-03-04 20:23:02 +0800237 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
238 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800239};
240
241static const struct video_levels pal_levels_svideo = {
242 .blank = 280, .black = 280, .burst = 139,
243};
244
245static const struct color_conversion pal_m_csc_composite = {
246 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800247 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
248 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800249};
250
251static const struct video_levels pal_m_levels_composite = {
252 .blank = 225, .black = 267, .burst = 113,
253};
254
255static const struct color_conversion pal_m_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800256 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
257 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
258 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800259};
260
261static const struct video_levels pal_m_levels_svideo = {
262 .blank = 266, .black = 316, .burst = 133,
263};
264
265static const struct color_conversion pal_n_csc_composite = {
266 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
Zhenyu Wangba010792009-03-04 20:23:02 +0800267 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
268 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800269};
270
271static const struct video_levels pal_n_levels_composite = {
272 .blank = 225, .black = 267, .burst = 118,
273};
274
275static const struct color_conversion pal_n_csc_svideo = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800276 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
277 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
278 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800279};
280
281static const struct video_levels pal_n_levels_svideo = {
282 .blank = 266, .black = 316, .burst = 139,
283};
284
285/*
286 * Component connections
287 */
288static const struct color_conversion sdtv_csc_yprpb = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800289 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
290 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
291 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800292};
293
Jesse Barnes79e53942008-11-07 14:24:08 -0800294static const struct color_conversion hdtv_csc_yprpb = {
Zhenyu Wangba010792009-03-04 20:23:02 +0800295 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
296 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
297 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
Jesse Barnes79e53942008-11-07 14:24:08 -0800298};
299
Jesse Barnes79e53942008-11-07 14:24:08 -0800300static const struct video_levels component_levels = {
301 .blank = 279, .black = 279, .burst = 0,
302};
303
304
305struct tv_mode {
Chris Wilson763a4a02010-09-05 00:52:34 +0100306 const char *name;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100307
308 u32 clock;
309 u16 refresh; /* in millihertz (for precision) */
Jesse Barnes79e53942008-11-07 14:24:08 -0800310 u32 oversample;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100311 u8 hsync_end;
312 u16 hblank_start, hblank_end, htotal;
313 bool progressive : 1, trilevel_sync : 1, component_only : 1;
314 u8 vsync_start_f1, vsync_start_f2, vsync_len;
315 bool veq_ena : 1;
316 u8 veq_start_f1, veq_start_f2, veq_len;
317 u8 vi_end_f1, vi_end_f2;
318 u16 nbr_end;
319 bool burst_ena : 1;
320 u8 hburst_start, hburst_len;
321 u8 vburst_start_f1;
322 u16 vburst_end_f1;
323 u8 vburst_start_f2;
324 u16 vburst_end_f2;
325 u8 vburst_start_f3;
326 u16 vburst_end_f3;
327 u8 vburst_start_f4;
328 u16 vburst_end_f4;
Jesse Barnes79e53942008-11-07 14:24:08 -0800329 /*
330 * subcarrier programming
331 */
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100332 u16 dda2_size, dda3_size;
333 u8 dda1_inc;
334 u16 dda2_inc, dda3_inc;
Jesse Barnes79e53942008-11-07 14:24:08 -0800335 u32 sc_reset;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100336 bool pal_burst : 1;
Jesse Barnes79e53942008-11-07 14:24:08 -0800337 /*
338 * blank/black levels
339 */
340 const struct video_levels *composite_levels, *svideo_levels;
341 const struct color_conversion *composite_color, *svideo_color;
342 const u32 *filter_table;
Tvrtko Ursulindb492962016-10-13 11:09:26 +0100343 u16 max_srcw;
Jesse Barnes79e53942008-11-07 14:24:08 -0800344};
345
346
347/*
348 * Sub carrier DDA
349 *
350 * I think this works as follows:
351 *
352 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
353 *
354 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
355 *
356 * So,
357 * dda1_ideal = subcarrier/pixel * 4096
358 * dda1_inc = floor (dda1_ideal)
359 * dda2 = dda1_ideal - dda1_inc
360 *
361 * then pick a ratio for dda2 that gives the closest approximation. If
362 * you can't get close enough, you can play with dda3 as well. This
363 * seems likely to happen when dda2 is small as the jumps would be larger
364 *
365 * To invert this,
366 *
367 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
368 *
369 * The constants below were all computed using a 107.520MHz clock
370 */
371
Chris Wilson3930f182018-02-14 08:58:14 +0000372/*
Jesse Barnes79e53942008-11-07 14:24:08 -0800373 * Register programming values for TV modes.
374 *
375 * These values account for -1s required.
376 */
Tobias Klauser005568b2009-02-09 22:02:42 +0100377static const struct tv_mode tv_modes[] = {
Jesse Barnes79e53942008-11-07 14:24:08 -0800378 {
379 .name = "NTSC-M",
Zhenyu Wangba010792009-03-04 20:23:02 +0800380 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200381 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800382 .oversample = TV_OVERSAMPLE_8X,
383 .component_only = 0,
384 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
385
386 .hsync_end = 64, .hblank_end = 124,
387 .hblank_start = 836, .htotal = 857,
388
389 .progressive = false, .trilevel_sync = false,
390
391 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
392 .vsync_len = 6,
393
Akshay Joshi0206e352011-08-16 15:34:10 -0400394 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800395 .veq_start_f2 = 1, .veq_len = 18,
396
397 .vi_end_f1 = 20, .vi_end_f2 = 21,
398 .nbr_end = 240,
399
400 .burst_ena = true,
401 .hburst_start = 72, .hburst_len = 34,
402 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
403 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
404 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
405 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
406
407 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800408 .dda1_inc = 135,
409 .dda2_inc = 20800, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800410 .dda3_inc = 0, .dda3_size = 0,
411 .sc_reset = TV_SC_RESET_EVERY_4,
412 .pal_burst = false,
413
414 .composite_levels = &ntsc_m_levels_composite,
415 .composite_color = &ntsc_m_csc_composite,
416 .svideo_levels = &ntsc_m_levels_svideo,
417 .svideo_color = &ntsc_m_csc_svideo,
418
419 .filter_table = filter_table,
420 },
421 {
422 .name = "NTSC-443",
Zhenyu Wangba010792009-03-04 20:23:02 +0800423 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200424 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800425 .oversample = TV_OVERSAMPLE_8X,
426 .component_only = 0,
427 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
428 .hsync_end = 64, .hblank_end = 124,
429 .hblank_start = 836, .htotal = 857,
430
431 .progressive = false, .trilevel_sync = false,
432
433 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
434 .vsync_len = 6,
435
Akshay Joshi0206e352011-08-16 15:34:10 -0400436 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800437 .veq_start_f2 = 1, .veq_len = 18,
438
439 .vi_end_f1 = 20, .vi_end_f2 = 21,
440 .nbr_end = 240,
441
Chris Wilson3ca87e82010-06-06 15:40:23 +0100442 .burst_ena = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800443 .hburst_start = 72, .hburst_len = 34,
444 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
445 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
446 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
447 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
448
449 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
450 .dda1_inc = 168,
Zhenyu Wangba010792009-03-04 20:23:02 +0800451 .dda2_inc = 4093, .dda2_size = 27456,
452 .dda3_inc = 310, .dda3_size = 525,
453 .sc_reset = TV_SC_RESET_NEVER,
454 .pal_burst = false,
Jesse Barnes79e53942008-11-07 14:24:08 -0800455
456 .composite_levels = &ntsc_m_levels_composite,
457 .composite_color = &ntsc_m_csc_composite,
458 .svideo_levels = &ntsc_m_levels_svideo,
459 .svideo_color = &ntsc_m_csc_svideo,
460
461 .filter_table = filter_table,
462 },
463 {
464 .name = "NTSC-J",
Zhenyu Wangba010792009-03-04 20:23:02 +0800465 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200466 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800467 .oversample = TV_OVERSAMPLE_8X,
468 .component_only = 0,
469
470 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
471 .hsync_end = 64, .hblank_end = 124,
472 .hblank_start = 836, .htotal = 857,
473
474 .progressive = false, .trilevel_sync = false,
475
476 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
477 .vsync_len = 6,
478
Akshay Joshi0206e352011-08-16 15:34:10 -0400479 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800480 .veq_start_f2 = 1, .veq_len = 18,
481
482 .vi_end_f1 = 20, .vi_end_f2 = 21,
483 .nbr_end = 240,
484
485 .burst_ena = true,
486 .hburst_start = 72, .hburst_len = 34,
487 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
488 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
489 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
490 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
491
492 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800493 .dda1_inc = 135,
494 .dda2_inc = 20800, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800495 .dda3_inc = 0, .dda3_size = 0,
496 .sc_reset = TV_SC_RESET_EVERY_4,
497 .pal_burst = false,
498
499 .composite_levels = &ntsc_j_levels_composite,
500 .composite_color = &ntsc_j_csc_composite,
501 .svideo_levels = &ntsc_j_levels_svideo,
502 .svideo_color = &ntsc_j_csc_svideo,
503
504 .filter_table = filter_table,
505 },
506 {
507 .name = "PAL-M",
Zhenyu Wangba010792009-03-04 20:23:02 +0800508 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200509 .refresh = 59940,
Jesse Barnes79e53942008-11-07 14:24:08 -0800510 .oversample = TV_OVERSAMPLE_8X,
511 .component_only = 0,
512
513 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
514 .hsync_end = 64, .hblank_end = 124,
515 .hblank_start = 836, .htotal = 857,
516
517 .progressive = false, .trilevel_sync = false,
518
519 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
520 .vsync_len = 6,
521
Akshay Joshi0206e352011-08-16 15:34:10 -0400522 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800523 .veq_start_f2 = 1, .veq_len = 18,
524
525 .vi_end_f1 = 20, .vi_end_f2 = 21,
526 .nbr_end = 240,
527
528 .burst_ena = true,
529 .hburst_start = 72, .hburst_len = 34,
530 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
531 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
532 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
533 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
534
535 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800536 .dda1_inc = 135,
537 .dda2_inc = 16704, .dda2_size = 27456,
Jesse Barnes79e53942008-11-07 14:24:08 -0800538 .dda3_inc = 0, .dda3_size = 0,
Zhenyu Wangba010792009-03-04 20:23:02 +0800539 .sc_reset = TV_SC_RESET_EVERY_8,
540 .pal_burst = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800541
542 .composite_levels = &pal_m_levels_composite,
543 .composite_color = &pal_m_csc_composite,
544 .svideo_levels = &pal_m_levels_svideo,
545 .svideo_color = &pal_m_csc_svideo,
546
547 .filter_table = filter_table,
548 },
549 {
550 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
551 .name = "PAL-N",
Zhenyu Wangba010792009-03-04 20:23:02 +0800552 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200553 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800554 .oversample = TV_OVERSAMPLE_8X,
555 .component_only = 0,
556
557 .hsync_end = 64, .hblank_end = 128,
558 .hblank_start = 844, .htotal = 863,
559
560 .progressive = false, .trilevel_sync = false,
561
562
563 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
564 .vsync_len = 6,
565
Akshay Joshi0206e352011-08-16 15:34:10 -0400566 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800567 .veq_start_f2 = 1, .veq_len = 18,
568
569 .vi_end_f1 = 24, .vi_end_f2 = 25,
570 .nbr_end = 286,
571
572 .burst_ena = true,
Akshay Joshi0206e352011-08-16 15:34:10 -0400573 .hburst_start = 73, .hburst_len = 34,
Jesse Barnes79e53942008-11-07 14:24:08 -0800574 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
575 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
576 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
577 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
578
579
580 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
Zhenyu Wangba010792009-03-04 20:23:02 +0800581 .dda1_inc = 135,
582 .dda2_inc = 23578, .dda2_size = 27648,
583 .dda3_inc = 134, .dda3_size = 625,
Jesse Barnes79e53942008-11-07 14:24:08 -0800584 .sc_reset = TV_SC_RESET_EVERY_8,
585 .pal_burst = true,
586
587 .composite_levels = &pal_n_levels_composite,
588 .composite_color = &pal_n_csc_composite,
589 .svideo_levels = &pal_n_levels_svideo,
590 .svideo_color = &pal_n_csc_svideo,
591
592 .filter_table = filter_table,
593 },
594 {
595 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
596 .name = "PAL",
Zhenyu Wangba010792009-03-04 20:23:02 +0800597 .clock = 108000,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200598 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800599 .oversample = TV_OVERSAMPLE_8X,
600 .component_only = 0,
601
Zhenyu Wangba010792009-03-04 20:23:02 +0800602 .hsync_end = 64, .hblank_end = 142,
Jesse Barnes79e53942008-11-07 14:24:08 -0800603 .hblank_start = 844, .htotal = 863,
604
605 .progressive = false, .trilevel_sync = false,
606
607 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
608 .vsync_len = 5,
609
Akshay Joshi0206e352011-08-16 15:34:10 -0400610 .veq_ena = true, .veq_start_f1 = 0,
Jesse Barnes79e53942008-11-07 14:24:08 -0800611 .veq_start_f2 = 1, .veq_len = 15,
612
613 .vi_end_f1 = 24, .vi_end_f2 = 25,
614 .nbr_end = 286,
615
616 .burst_ena = true,
617 .hburst_start = 73, .hburst_len = 32,
618 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
619 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
620 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
621 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
622
623 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
624 .dda1_inc = 168,
Zhenyu Wangba010792009-03-04 20:23:02 +0800625 .dda2_inc = 4122, .dda2_size = 27648,
626 .dda3_inc = 67, .dda3_size = 625,
Jesse Barnes79e53942008-11-07 14:24:08 -0800627 .sc_reset = TV_SC_RESET_EVERY_8,
628 .pal_burst = true,
629
630 .composite_levels = &pal_levels_composite,
631 .composite_color = &pal_csc_composite,
632 .svideo_levels = &pal_levels_svideo,
633 .svideo_color = &pal_csc_svideo,
634
635 .filter_table = filter_table,
636 },
637 {
Rodrigo Vivi95899192012-05-22 15:23:24 -0300638 .name = "480p",
639 .clock = 107520,
640 .refresh = 59940,
641 .oversample = TV_OVERSAMPLE_4X,
642 .component_only = 1,
643
644 .hsync_end = 64, .hblank_end = 122,
645 .hblank_start = 842, .htotal = 857,
646
647 .progressive = true, .trilevel_sync = false,
648
649 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
650 .vsync_len = 12,
651
652 .veq_ena = false,
653
654 .vi_end_f1 = 44, .vi_end_f2 = 44,
655 .nbr_end = 479,
656
657 .burst_ena = false,
658
659 .filter_table = filter_table,
660 },
661 {
662 .name = "576p",
663 .clock = 107520,
664 .refresh = 50000,
665 .oversample = TV_OVERSAMPLE_4X,
666 .component_only = 1,
667
668 .hsync_end = 64, .hblank_end = 139,
669 .hblank_start = 859, .htotal = 863,
670
671 .progressive = true, .trilevel_sync = false,
672
673 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
674 .vsync_len = 10,
675
676 .veq_ena = false,
677
678 .vi_end_f1 = 48, .vi_end_f2 = 48,
679 .nbr_end = 575,
680
681 .burst_ena = false,
682
683 .filter_table = filter_table,
684 },
685 {
Jesse Barnes79e53942008-11-07 14:24:08 -0800686 .name = "720p@60Hz",
687 .clock = 148800,
688 .refresh = 60000,
689 .oversample = TV_OVERSAMPLE_2X,
690 .component_only = 1,
691
692 .hsync_end = 80, .hblank_end = 300,
693 .hblank_start = 1580, .htotal = 1649,
694
Akshay Joshi0206e352011-08-16 15:34:10 -0400695 .progressive = true, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800696
697 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
698 .vsync_len = 10,
699
700 .veq_ena = false,
701
702 .vi_end_f1 = 29, .vi_end_f2 = 29,
703 .nbr_end = 719,
704
705 .burst_ena = false,
706
707 .filter_table = filter_table,
708 },
709 {
Jesse Barnes79e53942008-11-07 14:24:08 -0800710 .name = "720p@50Hz",
711 .clock = 148800,
712 .refresh = 50000,
713 .oversample = TV_OVERSAMPLE_2X,
714 .component_only = 1,
715
716 .hsync_end = 80, .hblank_end = 300,
717 .hblank_start = 1580, .htotal = 1979,
718
Akshay Joshi0206e352011-08-16 15:34:10 -0400719 .progressive = true, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800720
721 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
722 .vsync_len = 10,
723
724 .veq_ena = false,
725
726 .vi_end_f1 = 29, .vi_end_f2 = 29,
727 .nbr_end = 719,
728
729 .burst_ena = false,
730
731 .filter_table = filter_table,
732 .max_srcw = 800
733 },
734 {
735 .name = "1080i@50Hz",
736 .clock = 148800,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200737 .refresh = 50000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800738 .oversample = TV_OVERSAMPLE_2X,
739 .component_only = 1,
740
741 .hsync_end = 88, .hblank_end = 235,
742 .hblank_start = 2155, .htotal = 2639,
743
Akshay Joshi0206e352011-08-16 15:34:10 -0400744 .progressive = false, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800745
746 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
747 .vsync_len = 10,
748
Akshay Joshi0206e352011-08-16 15:34:10 -0400749 .veq_ena = true, .veq_start_f1 = 4,
Jesse Barnes79e53942008-11-07 14:24:08 -0800750 .veq_start_f2 = 4, .veq_len = 10,
751
752
753 .vi_end_f1 = 21, .vi_end_f2 = 22,
754 .nbr_end = 539,
755
756 .burst_ena = false,
757
758 .filter_table = filter_table,
759 },
760 {
761 .name = "1080i@60Hz",
762 .clock = 148800,
Rodrigo Vivi23bd15e2011-12-14 21:10:06 -0200763 .refresh = 60000,
Jesse Barnes79e53942008-11-07 14:24:08 -0800764 .oversample = TV_OVERSAMPLE_2X,
765 .component_only = 1,
766
767 .hsync_end = 88, .hblank_end = 235,
768 .hblank_start = 2155, .htotal = 2199,
769
Akshay Joshi0206e352011-08-16 15:34:10 -0400770 .progressive = false, .trilevel_sync = true,
Jesse Barnes79e53942008-11-07 14:24:08 -0800771
772 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
773 .vsync_len = 10,
774
Akshay Joshi0206e352011-08-16 15:34:10 -0400775 .veq_ena = true, .veq_start_f1 = 4,
Jesse Barnes79e53942008-11-07 14:24:08 -0800776 .veq_start_f2 = 4, .veq_len = 10,
777
778
779 .vi_end_f1 = 21, .vi_end_f2 = 22,
780 .nbr_end = 539,
781
782 .burst_ena = false,
783
784 .filter_table = filter_table,
785 },
Jesse Barnes79e53942008-11-07 14:24:08 -0800786};
787
Daniel Vettercd91ef22013-07-21 21:37:02 +0200788static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
Chris Wilsonea5b2132010-08-04 13:50:23 +0100789{
Daniel Vettercd91ef22013-07-21 21:37:02 +0200790 return container_of(encoder, struct intel_tv, base);
Chris Wilsonea5b2132010-08-04 13:50:23 +0100791}
792
Chris Wilsondf0e9242010-09-09 16:20:55 +0100793static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
794{
Daniel Vettercd91ef22013-07-21 21:37:02 +0200795 return enc_to_tv(intel_attached_encoder(connector));
Chris Wilsondf0e9242010-09-09 16:20:55 +0100796}
797
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200798static bool
799intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
Jesse Barnes79e53942008-11-07 14:24:08 -0800800{
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200801 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100802 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter9a8ee982012-07-02 13:34:59 +0200803 u32 tmp = I915_READ(TV_CTL);
804
805 if (!(tmp & TV_ENC_ENABLE))
806 return false;
807
808 *pipe = PORT_TO_PIPE(tmp);
809
810 return true;
811}
812
Jesse Barnes79e53942008-11-07 14:24:08 -0800813static void
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200814intel_enable_tv(struct intel_encoder *encoder,
Ville Syrjälä5f88a9c2017-08-18 16:49:58 +0300815 const struct intel_crtc_state *pipe_config,
816 const struct drm_connector_state *conn_state)
Jesse Barnes79e53942008-11-07 14:24:08 -0800817{
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200818 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100819 struct drm_i915_private *dev_priv = to_i915(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -0800820
Ville Syrjälä7a989482014-09-08 17:43:01 +0300821 /* Prevents vblank waits from timing out in intel_tv_detect_type() */
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +0200822 intel_wait_for_vblank(dev_priv,
Ville Syrjäläa7f519b2017-10-31 22:51:17 +0200823 to_intel_crtc(pipe_config->base.crtc)->pipe);
Ville Syrjälä7a989482014-09-08 17:43:01 +0300824
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200825 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
826}
827
828static void
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200829intel_disable_tv(struct intel_encoder *encoder,
Ville Syrjälä5f88a9c2017-08-18 16:49:58 +0300830 const struct intel_crtc_state *old_crtc_state,
831 const struct drm_connector_state *old_conn_state)
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200832{
833 struct drm_device *dev = encoder->base.dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +0100834 struct drm_i915_private *dev_priv = to_i915(dev);
Daniel Vetter6b5756a2012-06-30 10:33:44 +0200835
836 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
Jesse Barnes79e53942008-11-07 14:24:08 -0800837}
838
Ville Syrjälä5f88a9c2017-08-18 16:49:58 +0300839static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
Jesse Barnes79e53942008-11-07 14:24:08 -0800840{
Maarten Lankhorst0e891b32017-04-10 11:07:08 +0200841 int format = conn_state->tv.mode;
Jesse Barnes79e53942008-11-07 14:24:08 -0800842
Maarten Lankhorst0e891b32017-04-10 11:07:08 +0200843 return &tv_modes[format];
Jesse Barnes79e53942008-11-07 14:24:08 -0800844}
845
846static enum drm_mode_status
Chris Wilson763a4a02010-09-05 00:52:34 +0100847intel_tv_mode_valid(struct drm_connector *connector,
848 struct drm_display_mode *mode)
Jesse Barnes79e53942008-11-07 14:24:08 -0800849{
Maarten Lankhorst0e891b32017-04-10 11:07:08 +0200850 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
Mika Kahola54c032b2016-02-02 15:16:43 +0200851 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
852
853 if (mode->clock > max_dotclk)
854 return MODE_CLOCK_HIGH;
Jesse Barnes79e53942008-11-07 14:24:08 -0800855
856 /* Ensure TV refresh is close to desired refresh */
Zhao Yakui0d0884c2009-09-29 16:31:49 +0800857 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
858 < 1000)
Jesse Barnes79e53942008-11-07 14:24:08 -0800859 return MODE_OK;
Chris Wilson763a4a02010-09-05 00:52:34 +0100860
Jesse Barnes79e53942008-11-07 14:24:08 -0800861 return MODE_CLOCK_RANGE;
862}
863
864
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100865static void
866intel_tv_get_config(struct intel_encoder *encoder,
Ander Conselvan de Oliveira5cec2582015-01-15 14:55:21 +0200867 struct intel_crtc_state *pipe_config)
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100868{
Ville Syrjäläe1214b92017-10-27 22:31:23 +0300869 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
870
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200871 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
Daniel Vetter7a495cf2013-11-18 09:00:58 +0100872}
873
Jesse Barnes79e53942008-11-07 14:24:08 -0800874static bool
Daniel Vetter5d2d38d2013-03-27 00:45:01 +0100875intel_tv_compute_config(struct intel_encoder *encoder,
Maarten Lankhorst0a478c22016-08-09 17:04:05 +0200876 struct intel_crtc_state *pipe_config,
877 struct drm_connector_state *conn_state)
Jesse Barnes79e53942008-11-07 14:24:08 -0800878{
Maarten Lankhorst0e891b32017-04-10 11:07:08 +0200879 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
Jesse Barnes79e53942008-11-07 14:24:08 -0800880
881 if (!tv_mode)
882 return false;
883
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200884 pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
Daniel Vetter5d2d38d2013-03-27 00:45:01 +0100885 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
886 pipe_config->pipe_bpp = 8*3;
887
Daniel Vetter1062b812013-09-10 11:44:30 +0200888 /* TV has it's own notion of sync and other mode flags, so clear them. */
Ander Conselvan de Oliveira2d112de2015-01-15 14:55:22 +0200889 pipe_config->base.adjusted_mode.flags = 0;
Daniel Vetter1062b812013-09-10 11:44:30 +0200890
891 /*
892 * FIXME: We don't check whether the input mode is actually what we want
893 * or whether userspace is doing something stupid.
894 */
895
Jesse Barnes79e53942008-11-07 14:24:08 -0800896 return true;
897}
898
Daniel Vetter8cb92202014-04-24 23:54:39 +0200899static void
900set_tv_mode_timings(struct drm_i915_private *dev_priv,
901 const struct tv_mode *tv_mode,
902 bool burst_ena)
Jesse Barnes79e53942008-11-07 14:24:08 -0800903{
Jesse Barnes79e53942008-11-07 14:24:08 -0800904 u32 hctl1, hctl2, hctl3;
905 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
Jesse Barnes79e53942008-11-07 14:24:08 -0800906
Jesse Barnes79e53942008-11-07 14:24:08 -0800907 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
908 (tv_mode->htotal << TV_HTOTAL_SHIFT);
909
910 hctl2 = (tv_mode->hburst_start << 16) |
911 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
912
913 if (burst_ena)
914 hctl2 |= TV_BURST_ENA;
915
916 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
917 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
918
919 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
920 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
921 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
922
923 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
924 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
925 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
926
927 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
928 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
929 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
930
931 if (tv_mode->veq_ena)
932 vctl3 |= TV_EQUAL_ENA;
933
934 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
935 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
936
937 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
938 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
939
940 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
941 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
942
943 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
944 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
945
Daniel Vetter8cb92202014-04-24 23:54:39 +0200946 I915_WRITE(TV_H_CTL_1, hctl1);
947 I915_WRITE(TV_H_CTL_2, hctl2);
948 I915_WRITE(TV_H_CTL_3, hctl3);
949 I915_WRITE(TV_V_CTL_1, vctl1);
950 I915_WRITE(TV_V_CTL_2, vctl2);
951 I915_WRITE(TV_V_CTL_3, vctl3);
952 I915_WRITE(TV_V_CTL_4, vctl4);
953 I915_WRITE(TV_V_CTL_5, vctl5);
954 I915_WRITE(TV_V_CTL_6, vctl6);
955 I915_WRITE(TV_V_CTL_7, vctl7);
956}
957
Daniel Vetterb8866ef2014-04-24 23:54:40 +0200958static void set_color_conversion(struct drm_i915_private *dev_priv,
959 const struct color_conversion *color_conversion)
960{
961 if (!color_conversion)
962 return;
963
964 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
965 color_conversion->gy);
966 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
967 color_conversion->ay);
968 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
969 color_conversion->gu);
970 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
971 color_conversion->au);
972 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
973 color_conversion->gv);
974 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
975 color_conversion->av);
976}
977
Maarten Lankhorstfd6bbda2016-08-09 17:04:04 +0200978static void intel_tv_pre_enable(struct intel_encoder *encoder,
Ville Syrjälä5f88a9c2017-08-18 16:49:58 +0300979 const struct intel_crtc_state *pipe_config,
980 const struct drm_connector_state *conn_state)
Daniel Vetter8cb92202014-04-24 23:54:39 +0200981{
Tvrtko Ursulin66478472016-11-16 08:55:40 +0000982 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
Ville Syrjäläa7f519b2017-10-31 22:51:17 +0200983 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
Daniel Vetter8cb92202014-04-24 23:54:39 +0200984 struct intel_tv *intel_tv = enc_to_tv(encoder);
Maarten Lankhorst0e891b32017-04-10 11:07:08 +0200985 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
Daniel Vetter8cb92202014-04-24 23:54:39 +0200986 u32 tv_ctl;
987 u32 scctl1, scctl2, scctl3;
988 int i, j;
989 const struct video_levels *video_levels;
990 const struct color_conversion *color_conversion;
991 bool burst_ena;
Daniel Vetter3fa2dd12014-04-24 23:54:42 +0200992 int xpos = 0x0, ypos = 0x0;
993 unsigned int xsize, ysize;
Daniel Vetter8cb92202014-04-24 23:54:39 +0200994
995 if (!tv_mode)
996 return; /* can't happen (mode_prepare prevents this) */
997
998 tv_ctl = I915_READ(TV_CTL);
999 tv_ctl &= TV_CTL_SAVE;
1000
1001 switch (intel_tv->type) {
1002 default:
1003 case DRM_MODE_CONNECTOR_Unknown:
1004 case DRM_MODE_CONNECTOR_Composite:
1005 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1006 video_levels = tv_mode->composite_levels;
1007 color_conversion = tv_mode->composite_color;
1008 burst_ena = tv_mode->burst_ena;
1009 break;
1010 case DRM_MODE_CONNECTOR_Component:
1011 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1012 video_levels = &component_levels;
1013 if (tv_mode->burst_ena)
1014 color_conversion = &sdtv_csc_yprpb;
1015 else
1016 color_conversion = &hdtv_csc_yprpb;
1017 burst_ena = false;
1018 break;
1019 case DRM_MODE_CONNECTOR_SVIDEO:
1020 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1021 video_levels = tv_mode->svideo_levels;
1022 color_conversion = tv_mode->svideo_color;
1023 burst_ena = tv_mode->burst_ena;
1024 break;
1025 }
1026
Jesse Barnes79e53942008-11-07 14:24:08 -08001027 if (intel_crtc->pipe == 1)
1028 tv_ctl |= TV_ENC_PIPEB_SELECT;
1029 tv_ctl |= tv_mode->oversample;
1030
1031 if (tv_mode->progressive)
1032 tv_ctl |= TV_PROGRESSIVE;
1033 if (tv_mode->trilevel_sync)
1034 tv_ctl |= TV_TRILEVEL_SYNC;
1035 if (tv_mode->pal_burst)
1036 tv_ctl |= TV_PAL_BURST;
Jesse Barnes79e53942008-11-07 14:24:08 -08001037
Chris Wilsond2718172009-11-27 13:06:56 +00001038 scctl1 = 0;
1039 if (tv_mode->dda1_inc)
1040 scctl1 |= TV_SC_DDA1_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001041 if (tv_mode->dda2_inc)
1042 scctl1 |= TV_SC_DDA2_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001043 if (tv_mode->dda3_inc)
1044 scctl1 |= TV_SC_DDA3_EN;
Jesse Barnes79e53942008-11-07 14:24:08 -08001045 scctl1 |= tv_mode->sc_reset;
Chris Wilsond2718172009-11-27 13:06:56 +00001046 if (video_levels)
1047 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
Jesse Barnes79e53942008-11-07 14:24:08 -08001048 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1049
1050 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1051 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1052
1053 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1054 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1055
1056 /* Enable two fixes for the chips that need them. */
Tvrtko Ursulin50a0bc92016-10-13 11:02:58 +01001057 if (IS_I915GM(dev_priv))
Jesse Barnes79e53942008-11-07 14:24:08 -08001058 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1059
Daniel Vetter8cb92202014-04-24 23:54:39 +02001060 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1061
Jesse Barnes79e53942008-11-07 14:24:08 -08001062 I915_WRITE(TV_SC_CTL_1, scctl1);
1063 I915_WRITE(TV_SC_CTL_2, scctl2);
1064 I915_WRITE(TV_SC_CTL_3, scctl3);
1065
Daniel Vetterb8866ef2014-04-24 23:54:40 +02001066 set_color_conversion(dev_priv, color_conversion);
Jesse Barnes79e53942008-11-07 14:24:08 -08001067
Tvrtko Ursulin66478472016-11-16 08:55:40 +00001068 if (INTEL_GEN(dev_priv) >= 4)
Zhenyu Wangd2d9f232009-03-04 19:36:02 +08001069 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1070 else
1071 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1072
Jesse Barnes79e53942008-11-07 14:24:08 -08001073 if (video_levels)
1074 I915_WRITE(TV_CLR_LEVEL,
1075 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1076 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
Jesse Barnes79e53942008-11-07 14:24:08 -08001077
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001078 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
Jesse Barnes79e53942008-11-07 14:24:08 -08001079
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001080 /* Filter ctl must be set before TV_WIN_SIZE */
1081 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1082 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1083 if (tv_mode->progressive)
1084 ysize = tv_mode->nbr_end + 1;
1085 else
1086 ysize = 2*tv_mode->nbr_end + 1;
Jesse Barnes79e53942008-11-07 14:24:08 -08001087
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001088 xpos += conn_state->tv.margins.left;
1089 ypos += conn_state->tv.margins.top;
1090 xsize -= (conn_state->tv.margins.left +
1091 conn_state->tv.margins.right);
1092 ysize -= (conn_state->tv.margins.top +
1093 conn_state->tv.margins.bottom);
Daniel Vetter3fa2dd12014-04-24 23:54:42 +02001094 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1095 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
Jesse Barnes79e53942008-11-07 14:24:08 -08001096
1097 j = 0;
1098 for (i = 0; i < 60; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001099 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001100 for (i = 0; i < 60; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001101 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001102 for (i = 0; i < 43; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001103 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
Jesse Barnes79e53942008-11-07 14:24:08 -08001104 for (i = 0; i < 43; i++)
Ville Syrjälä184d7c02015-09-18 20:03:21 +03001105 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
Chris Wilsonb8ed2a42010-09-05 00:43:42 +01001106 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
Jesse Barnes79e53942008-11-07 14:24:08 -08001107 I915_WRITE(TV_CTL, tv_ctl);
1108}
1109
1110static const struct drm_display_mode reported_modes[] = {
1111 {
1112 .name = "NTSC 480i",
1113 .clock = 107520,
1114 .hdisplay = 1280,
1115 .hsync_start = 1368,
1116 .hsync_end = 1496,
1117 .htotal = 1712,
1118
1119 .vdisplay = 1024,
1120 .vsync_start = 1027,
1121 .vsync_end = 1034,
1122 .vtotal = 1104,
1123 .type = DRM_MODE_TYPE_DRIVER,
1124 },
1125};
1126
Jesse Barnes79e53942008-11-07 14:24:08 -08001127static int
Akshay Joshi0206e352011-08-16 15:34:10 -04001128intel_tv_detect_type(struct intel_tv *intel_tv,
Chris Wilson8102e122011-02-10 10:05:35 +00001129 struct drm_connector *connector)
Jesse Barnes79e53942008-11-07 14:24:08 -08001130{
Maarten Lankhorst0eadc622016-02-17 09:18:37 +01001131 struct drm_crtc *crtc = connector->state->crtc;
Keith Packard835bff72011-05-12 17:10:57 -07001132 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
Maarten Lankhorst0eadc622016-02-17 09:18:37 +01001133 struct drm_device *dev = connector->dev;
Chris Wilsonfac5e232016-07-04 11:34:36 +01001134 struct drm_i915_private *dev_priv = to_i915(dev);
Jesse Barnes79e53942008-11-07 14:24:08 -08001135 u32 tv_ctl, save_tv_ctl;
1136 u32 tv_dac, save_tv_dac;
Chris Wilson974b9332010-09-05 00:44:20 +01001137 int type;
Jesse Barnes79e53942008-11-07 14:24:08 -08001138
1139 /* Disable TV interrupts around load detect or we'll recurse */
Chris Wilson8102e122011-02-10 10:05:35 +00001140 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
Daniel Vetter2795aa482014-09-15 14:55:25 +02001141 spin_lock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001142 i915_disable_pipestat(dev_priv, 0,
Imre Deak755e9012014-02-10 18:42:47 +02001143 PIPE_HOTPLUG_INTERRUPT_STATUS |
1144 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
Daniel Vetter2795aa482014-09-15 14:55:25 +02001145 spin_unlock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001146 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001147
Chris Wilson974b9332010-09-05 00:44:20 +01001148 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1149 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1150
1151 /* Poll for TV detection */
1152 tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001153 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
Keith Packard835bff72011-05-12 17:10:57 -07001154 if (intel_crtc->pipe == 1)
1155 tv_ctl |= TV_ENC_PIPEB_SELECT;
1156 else
1157 tv_ctl &= ~TV_ENC_PIPEB_SELECT;
Chris Wilson974b9332010-09-05 00:44:20 +01001158
1159 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001160 tv_dac |= (TVDAC_STATE_CHG_EN |
1161 TVDAC_A_SENSE_CTL |
1162 TVDAC_B_SENSE_CTL |
1163 TVDAC_C_SENSE_CTL |
1164 DAC_CTL_OVERRIDE |
1165 DAC_A_0_7_V |
1166 DAC_B_0_7_V |
1167 DAC_C_0_7_V);
Chris Wilson974b9332010-09-05 00:44:20 +01001168
Daniel Vetterd42c9e22012-03-25 22:56:14 +02001169
1170 /*
1171 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1172 * the TV is misdetected. This is hardware requirement.
1173 */
Tvrtko Ursulin50a0bc92016-10-13 11:02:58 +01001174 if (IS_GM45(dev_priv))
Daniel Vetterd42c9e22012-03-25 22:56:14 +02001175 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1176 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1177
ling.ma@intel.com8ed9a5b2009-06-22 22:08:35 +08001178 I915_WRITE(TV_CTL, tv_ctl);
1179 I915_WRITE(TV_DAC, tv_dac);
Pekka Enberg4f233ef2010-09-04 19:24:04 +03001180 POSTING_READ(TV_DAC);
Pekka Enberg4f233ef2010-09-04 19:24:04 +03001181
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +02001182 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
Chris Wilson29e13162010-09-22 19:10:09 +01001183
Chris Wilson974b9332010-09-05 00:44:20 +01001184 type = -1;
Keith Packard2bf71162011-05-12 17:10:58 -07001185 tv_dac = I915_READ(TV_DAC);
1186 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1187 /*
1188 * A B C
1189 * 0 1 1 Composite
1190 * 1 0 X svideo
1191 * 0 0 0 Component
1192 */
1193 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1194 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1195 type = DRM_MODE_CONNECTOR_Composite;
1196 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1197 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1198 type = DRM_MODE_CONNECTOR_SVIDEO;
1199 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1200 DRM_DEBUG_KMS("Detected Component TV connection\n");
1201 type = DRM_MODE_CONNECTOR_Component;
1202 } else {
1203 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1204 type = -1;
Jesse Barnes79e53942008-11-07 14:24:08 -08001205 }
1206
Chris Wilson974b9332010-09-05 00:44:20 +01001207 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1208 I915_WRITE(TV_CTL, save_tv_ctl);
Daniel Vetterbf2125e2012-05-22 21:41:25 +02001209 POSTING_READ(TV_CTL);
1210
1211 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
Ville Syrjälä0f0f74b2016-10-31 22:37:06 +02001212 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
Chris Wilson974b9332010-09-05 00:44:20 +01001213
Jesse Barnes79e53942008-11-07 14:24:08 -08001214 /* Restore interrupt config */
Chris Wilson8102e122011-02-10 10:05:35 +00001215 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
Daniel Vetter2795aa482014-09-15 14:55:25 +02001216 spin_lock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001217 i915_enable_pipestat(dev_priv, 0,
Imre Deak755e9012014-02-10 18:42:47 +02001218 PIPE_HOTPLUG_INTERRUPT_STATUS |
1219 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
Daniel Vetter2795aa482014-09-15 14:55:25 +02001220 spin_unlock_irq(&dev_priv->irq_lock);
Chris Wilson8102e122011-02-10 10:05:35 +00001221 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001222
1223 return type;
1224}
1225
Ma Ling213c2e62009-08-24 13:50:25 +08001226/*
1227 * Here we set accurate tv format according to connector type
1228 * i.e Component TV should not be assigned by NTSC or PAL
1229 */
1230static void intel_tv_find_better_format(struct drm_connector *connector)
1231{
Chris Wilsondf0e9242010-09-09 16:20:55 +01001232 struct intel_tv *intel_tv = intel_attached_tv(connector);
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001233 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
Ma Ling213c2e62009-08-24 13:50:25 +08001234 int i;
1235
Chris Wilsonea5b2132010-08-04 13:50:23 +01001236 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
Ma Ling213c2e62009-08-24 13:50:25 +08001237 tv_mode->component_only)
1238 return;
1239
1240
Ville Syrjälä53abb672015-08-21 20:45:28 +03001241 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
Ma Ling213c2e62009-08-24 13:50:25 +08001242 tv_mode = tv_modes + i;
1243
Chris Wilsonea5b2132010-08-04 13:50:23 +01001244 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
Ma Ling213c2e62009-08-24 13:50:25 +08001245 tv_mode->component_only)
1246 break;
1247 }
1248
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001249 connector->state->tv.mode = i;
Ma Ling213c2e62009-08-24 13:50:25 +08001250}
1251
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001252static int
1253intel_tv_detect(struct drm_connector *connector,
1254 struct drm_modeset_acquire_ctx *ctx,
1255 bool force)
Jesse Barnes79e53942008-11-07 14:24:08 -08001256{
Jesse Barnes79e53942008-11-07 14:24:08 -08001257 struct drm_display_mode mode;
Chris Wilsondf0e9242010-09-09 16:20:55 +01001258 struct intel_tv *intel_tv = intel_attached_tv(connector);
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001259 enum drm_connector_status status;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001260 int type;
Jesse Barnes79e53942008-11-07 14:24:08 -08001261
Chris Wilson164c8592013-07-20 20:27:08 +01001262 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
Jani Nikulac23cc412014-06-03 14:56:17 +03001263 connector->base.id, connector->name,
Chris Wilson164c8592013-07-20 20:27:08 +01001264 force);
1265
Jesse Barnes79e53942008-11-07 14:24:08 -08001266 mode = reported_modes[0];
Jesse Barnes79e53942008-11-07 14:24:08 -08001267
Daniel Vetter38de45c2012-04-20 21:25:04 +02001268 if (force) {
Chris Wilson8261b192011-04-19 23:18:09 +01001269 struct intel_load_detect_pipe tmp;
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001270 int ret;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001271
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001272 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1273 if (ret < 0)
1274 return ret;
Ville Syrjälä208bf9f2014-08-11 13:15:35 +03001275
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001276 if (ret > 0) {
Chris Wilson8102e122011-02-10 10:05:35 +00001277 type = intel_tv_detect_type(intel_tv, connector);
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001278 intel_release_load_detect_pipe(connector, &tmp, ctx);
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001279 status = type < 0 ?
1280 connector_status_disconnected :
1281 connector_status_connected;
Jesse Barnes79e53942008-11-07 14:24:08 -08001282 } else
Ville Syrjäläbbfb44e2014-09-02 12:57:22 +03001283 status = connector_status_unknown;
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001284
1285 if (status == connector_status_connected) {
1286 intel_tv->type = type;
1287 intel_tv_find_better_format(connector);
1288 }
1289
1290 return status;
Chris Wilson7b334fc2010-09-09 23:51:02 +01001291 } else
1292 return connector->status;
Jesse Barnes79e53942008-11-07 14:24:08 -08001293}
1294
Chris Wilson763a4a02010-09-05 00:52:34 +01001295static const struct input_res {
1296 const char *name;
Jesse Barnes79e53942008-11-07 14:24:08 -08001297 int w, h;
Chris Wilson763a4a02010-09-05 00:52:34 +01001298} input_res_table[] = {
Jesse Barnes79e53942008-11-07 14:24:08 -08001299 {"640x480", 640, 480},
1300 {"800x600", 800, 600},
1301 {"1024x768", 1024, 768},
1302 {"1280x1024", 1280, 1024},
1303 {"848x480", 848, 480},
1304 {"1280x720", 1280, 720},
1305 {"1920x1080", 1920, 1080},
1306};
1307
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001308/*
1309 * Chose preferred mode according to line number of TV format
1310 */
1311static void
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001312intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001313 struct drm_display_mode *mode_ptr)
1314{
ling.ma@intel.combcae2ca2009-07-20 13:20:23 +08001315 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1316 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1317 else if (tv_mode->nbr_end > 480) {
1318 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1319 if (mode_ptr->vdisplay == 720)
1320 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1321 } else if (mode_ptr->vdisplay == 1080)
1322 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1323 }
1324}
1325
Jesse Barnes79e53942008-11-07 14:24:08 -08001326static int
1327intel_tv_get_modes(struct drm_connector *connector)
1328{
1329 struct drm_display_mode *mode_ptr;
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001330 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001331 int j, count = 0;
1332 u64 tmp;
Jesse Barnes79e53942008-11-07 14:24:08 -08001333
Kulikov Vasiliy04ad3272010-06-28 15:54:56 +04001334 for (j = 0; j < ARRAY_SIZE(input_res_table);
Jesse Barnes79e53942008-11-07 14:24:08 -08001335 j++) {
Chris Wilson763a4a02010-09-05 00:52:34 +01001336 const struct input_res *input = &input_res_table[j];
Jesse Barnes79e53942008-11-07 14:24:08 -08001337 unsigned int hactive_s = input->w;
1338 unsigned int vactive_s = input->h;
1339
1340 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1341 continue;
1342
1343 if (input->w > 1024 && (!tv_mode->progressive
1344 && !tv_mode->component_only))
1345 continue;
1346
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001347 mode_ptr = drm_mode_create(connector->dev);
1348 if (!mode_ptr)
1349 continue;
Jesse Barnes79e53942008-11-07 14:24:08 -08001350 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
Imre Deak05d25212016-01-29 14:52:29 +02001351 mode_ptr->name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
Jesse Barnes79e53942008-11-07 14:24:08 -08001352
1353 mode_ptr->hdisplay = hactive_s;
1354 mode_ptr->hsync_start = hactive_s + 1;
1355 mode_ptr->hsync_end = hactive_s + 64;
1356 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1357 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1358 mode_ptr->htotal = hactive_s + 96;
1359
1360 mode_ptr->vdisplay = vactive_s;
1361 mode_ptr->vsync_start = vactive_s + 1;
1362 mode_ptr->vsync_end = vactive_s + 32;
1363 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1364 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1365 mode_ptr->vtotal = vactive_s + 33;
1366
Chris Wilson31236982017-09-13 11:51:53 +01001367 tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001368 tmp *= mode_ptr->htotal;
1369 tmp = div_u64(tmp, 1000000);
1370 mode_ptr->clock = (int) tmp;
Jesse Barnes79e53942008-11-07 14:24:08 -08001371
1372 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001373 intel_tv_choose_preferred_modes(tv_mode, mode_ptr);
Jesse Barnes79e53942008-11-07 14:24:08 -08001374 drm_mode_probed_add(connector, mode_ptr);
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001375 count++;
Jesse Barnes79e53942008-11-07 14:24:08 -08001376 }
1377
Zhenyu Wang02c5dd92009-03-04 19:36:01 +08001378 return count;
Jesse Barnes79e53942008-11-07 14:24:08 -08001379}
1380
1381static void
Akshay Joshi0206e352011-08-16 15:34:10 -04001382intel_tv_destroy(struct drm_connector *connector)
Jesse Barnes79e53942008-11-07 14:24:08 -08001383{
Jesse Barnes79e53942008-11-07 14:24:08 -08001384 drm_connector_cleanup(connector);
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001385 kfree(connector);
Jesse Barnes79e53942008-11-07 14:24:08 -08001386}
1387
Jesse Barnes79e53942008-11-07 14:24:08 -08001388static const struct drm_connector_funcs intel_tv_connector_funcs = {
Chris Wilson1ebaa0b2016-06-24 14:00:15 +01001389 .late_register = intel_connector_register,
Chris Wilsonc191eca2016-06-17 11:40:33 +01001390 .early_unregister = intel_connector_unregister,
Jesse Barnes79e53942008-11-07 14:24:08 -08001391 .destroy = intel_tv_destroy,
Jesse Barnes79e53942008-11-07 14:24:08 -08001392 .fill_modes = drm_helper_probe_single_connector_modes,
Matt Roperc6f95f22015-01-22 16:50:32 -08001393 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
Ander Conselvan de Oliveira98969722015-03-20 16:18:06 +02001394 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
Jesse Barnes79e53942008-11-07 14:24:08 -08001395};
1396
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001397static int intel_tv_atomic_check(struct drm_connector *connector,
1398 struct drm_connector_state *new_state)
1399{
1400 struct drm_crtc_state *new_crtc_state;
1401 struct drm_connector_state *old_state;
1402
1403 if (!new_state->crtc)
1404 return 0;
1405
1406 old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
1407 new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
1408
1409 if (old_state->tv.mode != new_state->tv.mode ||
1410 old_state->tv.margins.left != new_state->tv.margins.left ||
1411 old_state->tv.margins.right != new_state->tv.margins.right ||
1412 old_state->tv.margins.top != new_state->tv.margins.top ||
1413 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1414 /* Force a modeset. */
1415
1416 new_crtc_state->connectors_changed = true;
1417 }
1418
1419 return 0;
1420}
1421
Jesse Barnes79e53942008-11-07 14:24:08 -08001422static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
Maarten Lankhorst6c5ed5a2017-04-06 20:55:20 +02001423 .detect_ctx = intel_tv_detect,
Jesse Barnes79e53942008-11-07 14:24:08 -08001424 .mode_valid = intel_tv_mode_valid,
1425 .get_modes = intel_tv_get_modes,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001426 .atomic_check = intel_tv_atomic_check,
Jesse Barnes79e53942008-11-07 14:24:08 -08001427};
1428
Jesse Barnes79e53942008-11-07 14:24:08 -08001429static const struct drm_encoder_funcs intel_tv_enc_funcs = {
Chris Wilsonea5b2132010-08-04 13:50:23 +01001430 .destroy = intel_encoder_destroy,
Jesse Barnes79e53942008-11-07 14:24:08 -08001431};
1432
Jesse Barnes79e53942008-11-07 14:24:08 -08001433void
Ander Conselvan de Oliveirac39055b2016-11-23 16:21:44 +02001434intel_tv_init(struct drm_i915_private *dev_priv)
Jesse Barnes79e53942008-11-07 14:24:08 -08001435{
Ander Conselvan de Oliveirac39055b2016-11-23 16:21:44 +02001436 struct drm_device *dev = &dev_priv->drm;
Jesse Barnes79e53942008-11-07 14:24:08 -08001437 struct drm_connector *connector;
Chris Wilsonea5b2132010-08-04 13:50:23 +01001438 struct intel_tv *intel_tv;
Eric Anholt21d40d32010-03-25 11:11:14 -07001439 struct intel_encoder *intel_encoder;
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001440 struct intel_connector *intel_connector;
Jesse Barnes79e53942008-11-07 14:24:08 -08001441 u32 tv_dac_on, tv_dac_off, save_tv_dac;
Ville Syrjäläb7c914b2015-08-31 15:09:26 +03001442 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
Jesse Barnes79e53942008-11-07 14:24:08 -08001443 int i, initial_mode = 0;
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001444 struct drm_connector_state *state;
Jesse Barnes79e53942008-11-07 14:24:08 -08001445
1446 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1447 return;
1448
Jani Nikula3bdd14d2016-03-16 12:43:29 +02001449 if (!intel_bios_is_tv_present(dev_priv)) {
Zhao Yakuic3561432009-11-24 09:48:48 +08001450 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1451 return;
1452 }
Jesse Barnes79e53942008-11-07 14:24:08 -08001453
1454 /*
1455 * Sanity check the TV output by checking to see if the
1456 * DAC register holds a value
1457 */
1458 save_tv_dac = I915_READ(TV_DAC);
1459
1460 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1461 tv_dac_on = I915_READ(TV_DAC);
1462
1463 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1464 tv_dac_off = I915_READ(TV_DAC);
1465
1466 I915_WRITE(TV_DAC, save_tv_dac);
1467
1468 /*
1469 * If the register does not hold the state change enable
1470 * bit, (either as a 0 or a 1), assume it doesn't really
1471 * exist
1472 */
1473 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1474 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1475 return;
1476
Daniel Vetterb14c5672013-09-19 12:18:32 +02001477 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
Chris Wilsonea5b2132010-08-04 13:50:23 +01001478 if (!intel_tv) {
Jesse Barnes79e53942008-11-07 14:24:08 -08001479 return;
1480 }
Ma Lingf8aed702009-08-24 13:50:24 +08001481
Ander Conselvan de Oliveira08d9bc92015-04-10 10:59:10 +03001482 intel_connector = intel_connector_alloc();
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001483 if (!intel_connector) {
Chris Wilsonea5b2132010-08-04 13:50:23 +01001484 kfree(intel_tv);
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001485 return;
1486 }
1487
Chris Wilsonea5b2132010-08-04 13:50:23 +01001488 intel_encoder = &intel_tv->base;
Zhenyu Wang0c41ee22010-03-29 16:38:44 +08001489 connector = &intel_connector->base;
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001490 state = connector->state;
Jesse Barnes79e53942008-11-07 14:24:08 -08001491
Chris Wilson3930f182018-02-14 08:58:14 +00001492 /*
1493 * The documentation, for the older chipsets at least, recommend
Chris Wilson8102e122011-02-10 10:05:35 +00001494 * using a polling method rather than hotplug detection for TVs.
1495 * This is because in order to perform the hotplug detection, the PLLs
1496 * for the TV must be kept alive increasing power drain and starving
1497 * bandwidth from other encoders. Notably for instance, it causes
1498 * pipe underruns on Crestline when this encoder is supposedly idle.
1499 *
1500 * More recent chipsets favour HDMI rather than integrated S-Video.
1501 */
Egbert Eich821450c2013-04-16 13:36:55 +02001502 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
Chris Wilson8102e122011-02-10 10:05:35 +00001503
Jesse Barnes79e53942008-11-07 14:24:08 -08001504 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1505 DRM_MODE_CONNECTOR_SVIDEO);
1506
Chris Wilson4ef69c72010-09-09 15:14:28 +01001507 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
Ville Syrjälä580d8ed2016-05-27 20:59:24 +03001508 DRM_MODE_ENCODER_TVDAC, "TV");
Jesse Barnes79e53942008-11-07 14:24:08 -08001509
Daniel Vetter5d2d38d2013-03-27 00:45:01 +01001510 intel_encoder->compute_config = intel_tv_compute_config;
Daniel Vetter7a495cf2013-11-18 09:00:58 +01001511 intel_encoder->get_config = intel_tv_get_config;
Daniel Vetter809a2a82014-04-24 23:54:43 +02001512 intel_encoder->pre_enable = intel_tv_pre_enable;
Daniel Vetter6b5756a2012-06-30 10:33:44 +02001513 intel_encoder->enable = intel_enable_tv;
1514 intel_encoder->disable = intel_disable_tv;
Daniel Vetter9a8ee982012-07-02 13:34:59 +02001515 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1516 intel_connector->get_hw_state = intel_connector_get_hw_state;
Daniel Vetter6b5756a2012-06-30 10:33:44 +02001517
Chris Wilsondf0e9242010-09-09 16:20:55 +01001518 intel_connector_attach_encoder(intel_connector, intel_encoder);
Pandiyan, Dhinakaran03cdc1d2016-09-19 18:24:38 -07001519
Eric Anholt21d40d32010-03-25 11:11:14 -07001520 intel_encoder->type = INTEL_OUTPUT_TVOUT;
Ander Conselvan de Oliveira79f255a2017-02-22 08:34:27 +02001521 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
Pandiyan, Dhinakaran03cdc1d2016-09-19 18:24:38 -07001522 intel_encoder->port = PORT_NONE;
Eric Anholt21d40d32010-03-25 11:11:14 -07001523 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
Ville Syrjäläbc079e82014-03-03 16:15:28 +02001524 intel_encoder->cloneable = 0;
Chris Wilson4ef69c72010-09-09 15:14:28 +01001525 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
Chris Wilsonea5b2132010-08-04 13:50:23 +01001526 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
Jesse Barnes79e53942008-11-07 14:24:08 -08001527
1528 /* BIOS margin values */
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001529 state->tv.margins.left = 54;
1530 state->tv.margins.top = 36;
1531 state->tv.margins.right = 46;
1532 state->tv.margins.bottom = 37;
Jesse Barnes79e53942008-11-07 14:24:08 -08001533
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001534 state->tv.mode = initial_mode;
Jesse Barnes79e53942008-11-07 14:24:08 -08001535
Jesse Barnes79e53942008-11-07 14:24:08 -08001536 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1537 connector->interlace_allowed = false;
1538 connector->doublescan_allowed = false;
1539
1540 /* Create TV properties then attach current values */
Dan Carpenter29911962010-06-23 19:29:54 +02001541 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
Ville Syrjäläb7c914b2015-08-31 15:09:26 +03001542 tv_format_names[i] = tv_modes[i].name;
Chris Wilson763a4a02010-09-05 00:52:34 +01001543 drm_mode_create_tv_properties(dev,
1544 ARRAY_SIZE(tv_modes),
1545 tv_format_names);
Jesse Barnes79e53942008-11-07 14:24:08 -08001546
Rob Clark662595d2012-10-11 20:36:04 -05001547 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001548 state->tv.mode);
Rob Clark662595d2012-10-11 20:36:04 -05001549 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001550 dev->mode_config.tv_left_margin_property,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001551 state->tv.margins.left);
Rob Clark662595d2012-10-11 20:36:04 -05001552 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001553 dev->mode_config.tv_top_margin_property,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001554 state->tv.margins.top);
Rob Clark662595d2012-10-11 20:36:04 -05001555 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001556 dev->mode_config.tv_right_margin_property,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001557 state->tv.margins.right);
Rob Clark662595d2012-10-11 20:36:04 -05001558 drm_object_attach_property(&connector->base,
Jesse Barnes79e53942008-11-07 14:24:08 -08001559 dev->mode_config.tv_bottom_margin_property,
Maarten Lankhorst0e891b32017-04-10 11:07:08 +02001560 state->tv.margins.bottom);
Jesse Barnes79e53942008-11-07 14:24:08 -08001561}