Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2006-2008 Intel Corporation
3 : : * Jesse Barnes <jesse.barnes@intel.com>
4 : : *
5 : : * Permission is hereby granted, free of charge, to any person obtaining a
6 : : * copy of this software and associated documentation files (the "Software"),
7 : : * to deal in the Software without restriction, including without limitation
8 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 : : * and/or sell copies of the Software, and to permit persons to whom the
10 : : * Software is furnished to do so, subject to the following conditions:
11 : : *
12 : : * The above copyright notice and this permission notice (including the next
13 : : * paragraph) shall be included in all copies or substantial portions of the
14 : : * Software.
15 : : *
16 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 : : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 : : * DEALINGS IN THE SOFTWARE.
23 : : *
24 : : * Authors:
25 : : * Eric Anholt <eric@anholt.net>
26 : : *
27 : : */
28 : :
29 : : /** @file
30 : : * Integrated TV-out support for the 915GM and 945GM.
31 : : */
32 : :
33 : : #include <drm/drm_atomic_helper.h>
34 : : #include <drm/drm_crtc.h>
35 : : #include <drm/drm_edid.h>
36 : : #include <drm/i915_drm.h>
37 : :
38 : : #include "i915_drv.h"
39 : : #include "intel_connector.h"
40 : : #include "intel_display_types.h"
41 : : #include "intel_hotplug.h"
42 : : #include "intel_tv.h"
43 : :
44 : : enum tv_margin {
45 : : TV_MARGIN_LEFT, TV_MARGIN_TOP,
46 : : TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
47 : : };
48 : :
49 : : struct intel_tv {
50 : : struct intel_encoder base;
51 : :
52 : : int type;
53 : : };
54 : :
55 : : struct video_levels {
56 : : u16 blank, black;
57 : : u8 burst;
58 : : };
59 : :
60 : : struct color_conversion {
61 : : u16 ry, gy, by, ay;
62 : : u16 ru, gu, bu, au;
63 : : u16 rv, gv, bv, av;
64 : : };
65 : :
66 : : static 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;
165 : : * mant = 1 << 8;
166 : : * } else {
167 : : * for (exp = 0; exp < 3 && f < 0.5; exp++)
168 : : * f *= 2.0;
169 : : * 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 : : */
188 : : static const struct color_conversion ntsc_m_csc_composite = {
189 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
190 : : .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
191 : : .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
192 : : };
193 : :
194 : : static const struct video_levels ntsc_m_levels_composite = {
195 : : .blank = 225, .black = 267, .burst = 113,
196 : : };
197 : :
198 : : static const struct color_conversion ntsc_m_csc_svideo = {
199 : : .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,
202 : : };
203 : :
204 : : static const struct video_levels ntsc_m_levels_svideo = {
205 : : .blank = 266, .black = 316, .burst = 133,
206 : : };
207 : :
208 : : static const struct color_conversion ntsc_j_csc_composite = {
209 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
210 : : .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
211 : : .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
212 : : };
213 : :
214 : : static const struct video_levels ntsc_j_levels_composite = {
215 : : .blank = 225, .black = 225, .burst = 113,
216 : : };
217 : :
218 : : static const struct color_conversion ntsc_j_csc_svideo = {
219 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
220 : : .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
221 : : .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
222 : : };
223 : :
224 : : static const struct video_levels ntsc_j_levels_svideo = {
225 : : .blank = 266, .black = 266, .burst = 133,
226 : : };
227 : :
228 : : static const struct color_conversion pal_csc_composite = {
229 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
230 : : .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
231 : : .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
232 : : };
233 : :
234 : : static const struct video_levels pal_levels_composite = {
235 : : .blank = 237, .black = 237, .burst = 118,
236 : : };
237 : :
238 : : static const struct color_conversion pal_csc_svideo = {
239 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
240 : : .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
241 : : .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
242 : : };
243 : :
244 : : static const struct video_levels pal_levels_svideo = {
245 : : .blank = 280, .black = 280, .burst = 139,
246 : : };
247 : :
248 : : static const struct color_conversion pal_m_csc_composite = {
249 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
250 : : .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
251 : : .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
252 : : };
253 : :
254 : : static const struct video_levels pal_m_levels_composite = {
255 : : .blank = 225, .black = 267, .burst = 113,
256 : : };
257 : :
258 : : static const struct color_conversion pal_m_csc_svideo = {
259 : : .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,
262 : : };
263 : :
264 : : static const struct video_levels pal_m_levels_svideo = {
265 : : .blank = 266, .black = 316, .burst = 133,
266 : : };
267 : :
268 : : static const struct color_conversion pal_n_csc_composite = {
269 : : .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
270 : : .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
271 : : .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
272 : : };
273 : :
274 : : static const struct video_levels pal_n_levels_composite = {
275 : : .blank = 225, .black = 267, .burst = 118,
276 : : };
277 : :
278 : : static const struct color_conversion pal_n_csc_svideo = {
279 : : .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,
282 : : };
283 : :
284 : : static const struct video_levels pal_n_levels_svideo = {
285 : : .blank = 266, .black = 316, .burst = 139,
286 : : };
287 : :
288 : : /*
289 : : * Component connections
290 : : */
291 : : static const struct color_conversion sdtv_csc_yprpb = {
292 : : .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,
295 : : };
296 : :
297 : : static const struct color_conversion hdtv_csc_yprpb = {
298 : : .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,
301 : : };
302 : :
303 : : static const struct video_levels component_levels = {
304 : : .blank = 279, .black = 279, .burst = 0,
305 : : };
306 : :
307 : :
308 : : struct tv_mode {
309 : : const char *name;
310 : :
311 : : u32 clock;
312 : : u16 refresh; /* in millihertz (for precision) */
313 : : u8 oversample;
314 : : 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;
332 : : /*
333 : : * subcarrier programming
334 : : */
335 : : u16 dda2_size, dda3_size;
336 : : u8 dda1_inc;
337 : : u16 dda2_inc, dda3_inc;
338 : : u32 sc_reset;
339 : : bool pal_burst : 1;
340 : : /*
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;
346 : : };
347 : :
348 : :
349 : : /*
350 : : * Sub carrier DDA
351 : : *
352 : : * I think this works as follows:
353 : : *
354 : : * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
355 : : *
356 : : * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
357 : : *
358 : : * So,
359 : : * dda1_ideal = subcarrier/pixel * 4096
360 : : * dda1_inc = floor (dda1_ideal)
361 : : * dda2 = dda1_ideal - dda1_inc
362 : : *
363 : : * then pick a ratio for dda2 that gives the closest approximation. If
364 : : * you can't get close enough, you can play with dda3 as well. This
365 : : * seems likely to happen when dda2 is small as the jumps would be larger
366 : : *
367 : : * To invert this,
368 : : *
369 : : * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
370 : : *
371 : : * The constants below were all computed using a 107.520MHz clock
372 : : */
373 : :
374 : : /*
375 : : * Register programming values for TV modes.
376 : : *
377 : : * These values account for -1s required.
378 : : */
379 : : static const struct tv_mode tv_modes[] = {
380 : : {
381 : : .name = "NTSC-M",
382 : : .clock = 108000,
383 : : .refresh = 59940,
384 : : .oversample = 8,
385 : : .component_only = false,
386 : : /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
387 : :
388 : : .hsync_end = 64, .hblank_end = 124,
389 : : .hblank_start = 836, .htotal = 857,
390 : :
391 : : .progressive = false, .trilevel_sync = false,
392 : :
393 : : .vsync_start_f1 = 6, .vsync_start_f2 = 7,
394 : : .vsync_len = 6,
395 : :
396 : : .veq_ena = true, .veq_start_f1 = 0,
397 : : .veq_start_f2 = 1, .veq_len = 18,
398 : :
399 : : .vi_end_f1 = 20, .vi_end_f2 = 21,
400 : : .nbr_end = 240,
401 : :
402 : : .burst_ena = true,
403 : : .hburst_start = 72, .hburst_len = 34,
404 : : .vburst_start_f1 = 9, .vburst_end_f1 = 240,
405 : : .vburst_start_f2 = 10, .vburst_end_f2 = 240,
406 : : .vburst_start_f3 = 9, .vburst_end_f3 = 240,
407 : : .vburst_start_f4 = 10, .vburst_end_f4 = 240,
408 : :
409 : : /* desired 3.5800000 actual 3.5800000 clock 107.52 */
410 : : .dda1_inc = 135,
411 : : .dda2_inc = 20800, .dda2_size = 27456,
412 : : .dda3_inc = 0, .dda3_size = 0,
413 : : .sc_reset = TV_SC_RESET_EVERY_4,
414 : : .pal_burst = false,
415 : :
416 : : .composite_levels = &ntsc_m_levels_composite,
417 : : .composite_color = &ntsc_m_csc_composite,
418 : : .svideo_levels = &ntsc_m_levels_svideo,
419 : : .svideo_color = &ntsc_m_csc_svideo,
420 : :
421 : : .filter_table = filter_table,
422 : : },
423 : : {
424 : : .name = "NTSC-443",
425 : : .clock = 108000,
426 : : .refresh = 59940,
427 : : .oversample = 8,
428 : : .component_only = false,
429 : : /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
430 : : .hsync_end = 64, .hblank_end = 124,
431 : : .hblank_start = 836, .htotal = 857,
432 : :
433 : : .progressive = false, .trilevel_sync = false,
434 : :
435 : : .vsync_start_f1 = 6, .vsync_start_f2 = 7,
436 : : .vsync_len = 6,
437 : :
438 : : .veq_ena = true, .veq_start_f1 = 0,
439 : : .veq_start_f2 = 1, .veq_len = 18,
440 : :
441 : : .vi_end_f1 = 20, .vi_end_f2 = 21,
442 : : .nbr_end = 240,
443 : :
444 : : .burst_ena = true,
445 : : .hburst_start = 72, .hburst_len = 34,
446 : : .vburst_start_f1 = 9, .vburst_end_f1 = 240,
447 : : .vburst_start_f2 = 10, .vburst_end_f2 = 240,
448 : : .vburst_start_f3 = 9, .vburst_end_f3 = 240,
449 : : .vburst_start_f4 = 10, .vburst_end_f4 = 240,
450 : :
451 : : /* desired 4.4336180 actual 4.4336180 clock 107.52 */
452 : : .dda1_inc = 168,
453 : : .dda2_inc = 4093, .dda2_size = 27456,
454 : : .dda3_inc = 310, .dda3_size = 525,
455 : : .sc_reset = TV_SC_RESET_NEVER,
456 : : .pal_burst = false,
457 : :
458 : : .composite_levels = &ntsc_m_levels_composite,
459 : : .composite_color = &ntsc_m_csc_composite,
460 : : .svideo_levels = &ntsc_m_levels_svideo,
461 : : .svideo_color = &ntsc_m_csc_svideo,
462 : :
463 : : .filter_table = filter_table,
464 : : },
465 : : {
466 : : .name = "NTSC-J",
467 : : .clock = 108000,
468 : : .refresh = 59940,
469 : : .oversample = 8,
470 : : .component_only = false,
471 : :
472 : : /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
473 : : .hsync_end = 64, .hblank_end = 124,
474 : : .hblank_start = 836, .htotal = 857,
475 : :
476 : : .progressive = false, .trilevel_sync = false,
477 : :
478 : : .vsync_start_f1 = 6, .vsync_start_f2 = 7,
479 : : .vsync_len = 6,
480 : :
481 : : .veq_ena = true, .veq_start_f1 = 0,
482 : : .veq_start_f2 = 1, .veq_len = 18,
483 : :
484 : : .vi_end_f1 = 20, .vi_end_f2 = 21,
485 : : .nbr_end = 240,
486 : :
487 : : .burst_ena = true,
488 : : .hburst_start = 72, .hburst_len = 34,
489 : : .vburst_start_f1 = 9, .vburst_end_f1 = 240,
490 : : .vburst_start_f2 = 10, .vburst_end_f2 = 240,
491 : : .vburst_start_f3 = 9, .vburst_end_f3 = 240,
492 : : .vburst_start_f4 = 10, .vburst_end_f4 = 240,
493 : :
494 : : /* desired 3.5800000 actual 3.5800000 clock 107.52 */
495 : : .dda1_inc = 135,
496 : : .dda2_inc = 20800, .dda2_size = 27456,
497 : : .dda3_inc = 0, .dda3_size = 0,
498 : : .sc_reset = TV_SC_RESET_EVERY_4,
499 : : .pal_burst = false,
500 : :
501 : : .composite_levels = &ntsc_j_levels_composite,
502 : : .composite_color = &ntsc_j_csc_composite,
503 : : .svideo_levels = &ntsc_j_levels_svideo,
504 : : .svideo_color = &ntsc_j_csc_svideo,
505 : :
506 : : .filter_table = filter_table,
507 : : },
508 : : {
509 : : .name = "PAL-M",
510 : : .clock = 108000,
511 : : .refresh = 59940,
512 : : .oversample = 8,
513 : : .component_only = false,
514 : :
515 : : /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
516 : : .hsync_end = 64, .hblank_end = 124,
517 : : .hblank_start = 836, .htotal = 857,
518 : :
519 : : .progressive = false, .trilevel_sync = false,
520 : :
521 : : .vsync_start_f1 = 6, .vsync_start_f2 = 7,
522 : : .vsync_len = 6,
523 : :
524 : : .veq_ena = true, .veq_start_f1 = 0,
525 : : .veq_start_f2 = 1, .veq_len = 18,
526 : :
527 : : .vi_end_f1 = 20, .vi_end_f2 = 21,
528 : : .nbr_end = 240,
529 : :
530 : : .burst_ena = true,
531 : : .hburst_start = 72, .hburst_len = 34,
532 : : .vburst_start_f1 = 9, .vburst_end_f1 = 240,
533 : : .vburst_start_f2 = 10, .vburst_end_f2 = 240,
534 : : .vburst_start_f3 = 9, .vburst_end_f3 = 240,
535 : : .vburst_start_f4 = 10, .vburst_end_f4 = 240,
536 : :
537 : : /* desired 3.5800000 actual 3.5800000 clock 107.52 */
538 : : .dda1_inc = 135,
539 : : .dda2_inc = 16704, .dda2_size = 27456,
540 : : .dda3_inc = 0, .dda3_size = 0,
541 : : .sc_reset = TV_SC_RESET_EVERY_8,
542 : : .pal_burst = true,
543 : :
544 : : .composite_levels = &pal_m_levels_composite,
545 : : .composite_color = &pal_m_csc_composite,
546 : : .svideo_levels = &pal_m_levels_svideo,
547 : : .svideo_color = &pal_m_csc_svideo,
548 : :
549 : : .filter_table = filter_table,
550 : : },
551 : : {
552 : : /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
553 : : .name = "PAL-N",
554 : : .clock = 108000,
555 : : .refresh = 50000,
556 : : .oversample = 8,
557 : : .component_only = false,
558 : :
559 : : .hsync_end = 64, .hblank_end = 128,
560 : : .hblank_start = 844, .htotal = 863,
561 : :
562 : : .progressive = false, .trilevel_sync = false,
563 : :
564 : :
565 : : .vsync_start_f1 = 6, .vsync_start_f2 = 7,
566 : : .vsync_len = 6,
567 : :
568 : : .veq_ena = true, .veq_start_f1 = 0,
569 : : .veq_start_f2 = 1, .veq_len = 18,
570 : :
571 : : .vi_end_f1 = 24, .vi_end_f2 = 25,
572 : : .nbr_end = 286,
573 : :
574 : : .burst_ena = true,
575 : : .hburst_start = 73, .hburst_len = 34,
576 : : .vburst_start_f1 = 8, .vburst_end_f1 = 285,
577 : : .vburst_start_f2 = 8, .vburst_end_f2 = 286,
578 : : .vburst_start_f3 = 9, .vburst_end_f3 = 286,
579 : : .vburst_start_f4 = 9, .vburst_end_f4 = 285,
580 : :
581 : :
582 : : /* desired 4.4336180 actual 4.4336180 clock 107.52 */
583 : : .dda1_inc = 135,
584 : : .dda2_inc = 23578, .dda2_size = 27648,
585 : : .dda3_inc = 134, .dda3_size = 625,
586 : : .sc_reset = TV_SC_RESET_EVERY_8,
587 : : .pal_burst = true,
588 : :
589 : : .composite_levels = &pal_n_levels_composite,
590 : : .composite_color = &pal_n_csc_composite,
591 : : .svideo_levels = &pal_n_levels_svideo,
592 : : .svideo_color = &pal_n_csc_svideo,
593 : :
594 : : .filter_table = filter_table,
595 : : },
596 : : {
597 : : /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
598 : : .name = "PAL",
599 : : .clock = 108000,
600 : : .refresh = 50000,
601 : : .oversample = 8,
602 : : .component_only = false,
603 : :
604 : : .hsync_end = 64, .hblank_end = 142,
605 : : .hblank_start = 844, .htotal = 863,
606 : :
607 : : .progressive = false, .trilevel_sync = false,
608 : :
609 : : .vsync_start_f1 = 5, .vsync_start_f2 = 6,
610 : : .vsync_len = 5,
611 : :
612 : : .veq_ena = true, .veq_start_f1 = 0,
613 : : .veq_start_f2 = 1, .veq_len = 15,
614 : :
615 : : .vi_end_f1 = 24, .vi_end_f2 = 25,
616 : : .nbr_end = 286,
617 : :
618 : : .burst_ena = true,
619 : : .hburst_start = 73, .hburst_len = 32,
620 : : .vburst_start_f1 = 8, .vburst_end_f1 = 285,
621 : : .vburst_start_f2 = 8, .vburst_end_f2 = 286,
622 : : .vburst_start_f3 = 9, .vburst_end_f3 = 286,
623 : : .vburst_start_f4 = 9, .vburst_end_f4 = 285,
624 : :
625 : : /* desired 4.4336180 actual 4.4336180 clock 107.52 */
626 : : .dda1_inc = 168,
627 : : .dda2_inc = 4122, .dda2_size = 27648,
628 : : .dda3_inc = 67, .dda3_size = 625,
629 : : .sc_reset = TV_SC_RESET_EVERY_8,
630 : : .pal_burst = true,
631 : :
632 : : .composite_levels = &pal_levels_composite,
633 : : .composite_color = &pal_csc_composite,
634 : : .svideo_levels = &pal_levels_svideo,
635 : : .svideo_color = &pal_csc_svideo,
636 : :
637 : : .filter_table = filter_table,
638 : : },
639 : : {
640 : : .name = "480p",
641 : : .clock = 108000,
642 : : .refresh = 59940,
643 : : .oversample = 4,
644 : : .component_only = true,
645 : :
646 : : .hsync_end = 64, .hblank_end = 122,
647 : : .hblank_start = 842, .htotal = 857,
648 : :
649 : : .progressive = true, .trilevel_sync = false,
650 : :
651 : : .vsync_start_f1 = 12, .vsync_start_f2 = 12,
652 : : .vsync_len = 12,
653 : :
654 : : .veq_ena = false,
655 : :
656 : : .vi_end_f1 = 44, .vi_end_f2 = 44,
657 : : .nbr_end = 479,
658 : :
659 : : .burst_ena = false,
660 : :
661 : : .filter_table = filter_table,
662 : : },
663 : : {
664 : : .name = "576p",
665 : : .clock = 108000,
666 : : .refresh = 50000,
667 : : .oversample = 4,
668 : : .component_only = true,
669 : :
670 : : .hsync_end = 64, .hblank_end = 139,
671 : : .hblank_start = 859, .htotal = 863,
672 : :
673 : : .progressive = true, .trilevel_sync = false,
674 : :
675 : : .vsync_start_f1 = 10, .vsync_start_f2 = 10,
676 : : .vsync_len = 10,
677 : :
678 : : .veq_ena = false,
679 : :
680 : : .vi_end_f1 = 48, .vi_end_f2 = 48,
681 : : .nbr_end = 575,
682 : :
683 : : .burst_ena = false,
684 : :
685 : : .filter_table = filter_table,
686 : : },
687 : : {
688 : : .name = "720p@60Hz",
689 : : .clock = 148500,
690 : : .refresh = 60000,
691 : : .oversample = 2,
692 : : .component_only = true,
693 : :
694 : : .hsync_end = 80, .hblank_end = 300,
695 : : .hblank_start = 1580, .htotal = 1649,
696 : :
697 : : .progressive = true, .trilevel_sync = true,
698 : :
699 : : .vsync_start_f1 = 10, .vsync_start_f2 = 10,
700 : : .vsync_len = 10,
701 : :
702 : : .veq_ena = false,
703 : :
704 : : .vi_end_f1 = 29, .vi_end_f2 = 29,
705 : : .nbr_end = 719,
706 : :
707 : : .burst_ena = false,
708 : :
709 : : .filter_table = filter_table,
710 : : },
711 : : {
712 : : .name = "720p@50Hz",
713 : : .clock = 148500,
714 : : .refresh = 50000,
715 : : .oversample = 2,
716 : : .component_only = true,
717 : :
718 : : .hsync_end = 80, .hblank_end = 300,
719 : : .hblank_start = 1580, .htotal = 1979,
720 : :
721 : : .progressive = true, .trilevel_sync = true,
722 : :
723 : : .vsync_start_f1 = 10, .vsync_start_f2 = 10,
724 : : .vsync_len = 10,
725 : :
726 : : .veq_ena = false,
727 : :
728 : : .vi_end_f1 = 29, .vi_end_f2 = 29,
729 : : .nbr_end = 719,
730 : :
731 : : .burst_ena = false,
732 : :
733 : : .filter_table = filter_table,
734 : : },
735 : : {
736 : : .name = "1080i@50Hz",
737 : : .clock = 148500,
738 : : .refresh = 50000,
739 : : .oversample = 2,
740 : : .component_only = true,
741 : :
742 : : .hsync_end = 88, .hblank_end = 235,
743 : : .hblank_start = 2155, .htotal = 2639,
744 : :
745 : : .progressive = false, .trilevel_sync = true,
746 : :
747 : : .vsync_start_f1 = 4, .vsync_start_f2 = 5,
748 : : .vsync_len = 10,
749 : :
750 : : .veq_ena = true, .veq_start_f1 = 4,
751 : : .veq_start_f2 = 4, .veq_len = 10,
752 : :
753 : :
754 : : .vi_end_f1 = 21, .vi_end_f2 = 22,
755 : : .nbr_end = 539,
756 : :
757 : : .burst_ena = false,
758 : :
759 : : .filter_table = filter_table,
760 : : },
761 : : {
762 : : .name = "1080i@60Hz",
763 : : .clock = 148500,
764 : : .refresh = 60000,
765 : : .oversample = 2,
766 : : .component_only = true,
767 : :
768 : : .hsync_end = 88, .hblank_end = 235,
769 : : .hblank_start = 2155, .htotal = 2199,
770 : :
771 : : .progressive = false, .trilevel_sync = true,
772 : :
773 : : .vsync_start_f1 = 4, .vsync_start_f2 = 5,
774 : : .vsync_len = 10,
775 : :
776 : : .veq_ena = true, .veq_start_f1 = 4,
777 : : .veq_start_f2 = 4, .veq_len = 10,
778 : :
779 : :
780 : : .vi_end_f1 = 21, .vi_end_f2 = 22,
781 : : .nbr_end = 539,
782 : :
783 : : .burst_ena = false,
784 : :
785 : : .filter_table = filter_table,
786 : : },
787 : :
788 : : {
789 : : .name = "1080p@30Hz",
790 : : .clock = 148500,
791 : : .refresh = 30000,
792 : : .oversample = 2,
793 : : .component_only = true,
794 : :
795 : : .hsync_end = 88, .hblank_end = 235,
796 : : .hblank_start = 2155, .htotal = 2199,
797 : :
798 : : .progressive = true, .trilevel_sync = true,
799 : :
800 : : .vsync_start_f1 = 8, .vsync_start_f2 = 8,
801 : : .vsync_len = 10,
802 : :
803 : : .veq_ena = false, .veq_start_f1 = 0,
804 : : .veq_start_f2 = 0, .veq_len = 0,
805 : :
806 : : .vi_end_f1 = 44, .vi_end_f2 = 44,
807 : : .nbr_end = 1079,
808 : :
809 : : .burst_ena = false,
810 : :
811 : : .filter_table = filter_table,
812 : : },
813 : :
814 : : {
815 : : .name = "1080p@50Hz",
816 : : .clock = 148500,
817 : : .refresh = 50000,
818 : : .oversample = 1,
819 : : .component_only = true,
820 : :
821 : : .hsync_end = 88, .hblank_end = 235,
822 : : .hblank_start = 2155, .htotal = 2639,
823 : :
824 : : .progressive = true, .trilevel_sync = true,
825 : :
826 : : .vsync_start_f1 = 8, .vsync_start_f2 = 8,
827 : : .vsync_len = 10,
828 : :
829 : : .veq_ena = false, .veq_start_f1 = 0,
830 : : .veq_start_f2 = 0, .veq_len = 0,
831 : :
832 : : .vi_end_f1 = 44, .vi_end_f2 = 44,
833 : : .nbr_end = 1079,
834 : :
835 : : .burst_ena = false,
836 : :
837 : : .filter_table = filter_table,
838 : : },
839 : :
840 : : {
841 : : .name = "1080p@60Hz",
842 : : .clock = 148500,
843 : : .refresh = 60000,
844 : : .oversample = 1,
845 : : .component_only = true,
846 : :
847 : : .hsync_end = 88, .hblank_end = 235,
848 : : .hblank_start = 2155, .htotal = 2199,
849 : :
850 : : .progressive = true, .trilevel_sync = true,
851 : :
852 : : .vsync_start_f1 = 8, .vsync_start_f2 = 8,
853 : : .vsync_len = 10,
854 : :
855 : : .veq_ena = false, .veq_start_f1 = 0,
856 : : .veq_start_f2 = 0, .veq_len = 0,
857 : :
858 : : .vi_end_f1 = 44, .vi_end_f2 = 44,
859 : : .nbr_end = 1079,
860 : :
861 : : .burst_ena = false,
862 : :
863 : : .filter_table = filter_table,
864 : : },
865 : : };
866 : :
867 : : struct intel_tv_connector_state {
868 : : struct drm_connector_state base;
869 : :
870 : : /*
871 : : * May need to override the user margins for
872 : : * gen3 >1024 wide source vertical centering.
873 : : */
874 : : struct {
875 : : u16 top, bottom;
876 : : } margins;
877 : :
878 : : bool bypass_vfilter;
879 : : };
880 : :
881 : : #define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
882 : :
883 : : static struct drm_connector_state *
884 : 0 : intel_tv_connector_duplicate_state(struct drm_connector *connector)
885 : : {
886 : 0 : struct intel_tv_connector_state *state;
887 : :
888 : 0 : state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
889 [ # # ]: 0 : if (!state)
890 : : return NULL;
891 : :
892 : 0 : __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
893 : 0 : return &state->base;
894 : : }
895 : :
896 : 0 : static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
897 : : {
898 : 0 : return container_of(encoder, struct intel_tv, base);
899 : : }
900 : :
901 : 0 : static struct intel_tv *intel_attached_tv(struct intel_connector *connector)
902 : : {
903 : 0 : return enc_to_tv(intel_attached_encoder(connector));
904 : : }
905 : :
906 : : static bool
907 : 0 : intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
908 : : {
909 : 0 : struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
910 : 0 : u32 tmp = I915_READ(TV_CTL);
911 : :
912 : 0 : *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
913 : :
914 : 0 : return tmp & TV_ENC_ENABLE;
915 : : }
916 : :
917 : : static void
918 : 0 : intel_enable_tv(struct intel_encoder *encoder,
919 : : const struct intel_crtc_state *pipe_config,
920 : : const struct drm_connector_state *conn_state)
921 : : {
922 : 0 : struct drm_device *dev = encoder->base.dev;
923 : 0 : struct drm_i915_private *dev_priv = to_i915(dev);
924 : :
925 : : /* Prevents vblank waits from timing out in intel_tv_detect_type() */
926 : 0 : intel_wait_for_vblank(dev_priv,
927 : 0 : to_intel_crtc(pipe_config->uapi.crtc)->pipe);
928 : :
929 : 0 : I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
930 : 0 : }
931 : :
932 : : static void
933 : 0 : intel_disable_tv(struct intel_encoder *encoder,
934 : : const struct intel_crtc_state *old_crtc_state,
935 : : const struct drm_connector_state *old_conn_state)
936 : : {
937 : 0 : struct drm_device *dev = encoder->base.dev;
938 : 0 : struct drm_i915_private *dev_priv = to_i915(dev);
939 : :
940 : 0 : I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
941 : 0 : }
942 : :
943 : 0 : static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
944 : : {
945 : 0 : int format = conn_state->tv.mode;
946 : :
947 : 0 : return &tv_modes[format];
948 : : }
949 : :
950 : : static enum drm_mode_status
951 : 0 : intel_tv_mode_valid(struct drm_connector *connector,
952 : : struct drm_display_mode *mode)
953 : : {
954 : 0 : const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
955 [ # # ]: 0 : int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
956 : :
957 [ # # ]: 0 : if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
958 : : return MODE_NO_DBLESCAN;
959 : :
960 [ # # ]: 0 : if (mode->clock > max_dotclk)
961 : : return MODE_CLOCK_HIGH;
962 : :
963 : : /* Ensure TV refresh is close to desired refresh */
964 [ # # ]: 0 : if (abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) >= 1000)
965 : 0 : return MODE_CLOCK_RANGE;
966 : :
967 : : return MODE_OK;
968 : : }
969 : :
970 : : static int
971 : 0 : intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
972 : : {
973 : 0 : if (tv_mode->progressive)
974 : 0 : return tv_mode->nbr_end + 1;
975 : : else
976 : 0 : return 2 * (tv_mode->nbr_end + 1);
977 : : }
978 : :
979 : : static void
980 : 0 : intel_tv_mode_to_mode(struct drm_display_mode *mode,
981 : : const struct tv_mode *tv_mode)
982 : : {
983 : 0 : mode->clock = tv_mode->clock /
984 : 0 : (tv_mode->oversample >> !tv_mode->progressive);
985 : :
986 : : /*
987 : : * tv_mode horizontal timings:
988 : : *
989 : : * hsync_end
990 : : * | hblank_end
991 : : * | | hblank_start
992 : : * | | | htotal
993 : : * | _______ |
994 : : * ____/ \___
995 : : * \__/ \
996 : : */
997 : 0 : mode->hdisplay =
998 : 0 : tv_mode->hblank_start - tv_mode->hblank_end;
999 : 0 : mode->hsync_start = mode->hdisplay +
1000 : 0 : tv_mode->htotal - tv_mode->hblank_start;
1001 : 0 : mode->hsync_end = mode->hsync_start +
1002 : 0 : tv_mode->hsync_end;
1003 : 0 : mode->htotal = tv_mode->htotal + 1;
1004 : :
1005 : : /*
1006 : : * tv_mode vertical timings:
1007 : : *
1008 : : * vsync_start
1009 : : * | vsync_end
1010 : : * | | vi_end nbr_end
1011 : : * | | | |
1012 : : * | | _______
1013 : : * \__ ____/ \
1014 : : * \__/
1015 : : */
1016 [ # # ]: 0 : mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
1017 [ # # ]: 0 : if (tv_mode->progressive) {
1018 : 0 : mode->vsync_start = mode->vdisplay +
1019 : 0 : tv_mode->vsync_start_f1 + 1;
1020 : 0 : mode->vsync_end = mode->vsync_start +
1021 : 0 : tv_mode->vsync_len;
1022 : 0 : mode->vtotal = mode->vdisplay +
1023 : 0 : tv_mode->vi_end_f1 + 1;
1024 : : } else {
1025 : 0 : mode->vsync_start = mode->vdisplay +
1026 : 0 : tv_mode->vsync_start_f1 + 1 +
1027 : 0 : tv_mode->vsync_start_f2 + 1;
1028 : 0 : mode->vsync_end = mode->vsync_start +
1029 : 0 : 2 * tv_mode->vsync_len;
1030 : 0 : mode->vtotal = mode->vdisplay +
1031 : 0 : tv_mode->vi_end_f1 + 1 +
1032 : 0 : tv_mode->vi_end_f2 + 1;
1033 : : }
1034 : :
1035 : : /* TV has it's own notion of sync and other mode flags, so clear them. */
1036 : 0 : mode->flags = 0;
1037 : :
1038 : 0 : mode->vrefresh = 0;
1039 : 0 : mode->vrefresh = drm_mode_vrefresh(mode);
1040 : :
1041 : 0 : snprintf(mode->name, sizeof(mode->name),
1042 : : "%dx%d%c (%s)",
1043 : : mode->hdisplay, mode->vdisplay,
1044 [ # # ]: 0 : tv_mode->progressive ? 'p' : 'i',
1045 : : tv_mode->name);
1046 : 0 : }
1047 : :
1048 : 0 : static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
1049 : : int hdisplay, int left_margin,
1050 : : int right_margin)
1051 : : {
1052 : 0 : int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
1053 : 0 : int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
1054 : 0 : int new_htotal = mode->htotal * hdisplay /
1055 : 0 : (mode->hdisplay - left_margin - right_margin);
1056 : :
1057 : 0 : mode->clock = mode->clock * new_htotal / mode->htotal;
1058 : :
1059 : 0 : mode->hdisplay = hdisplay;
1060 : 0 : mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
1061 : 0 : mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
1062 : 0 : mode->htotal = new_htotal;
1063 : 0 : }
1064 : :
1065 : 0 : static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
1066 : : int vdisplay, int top_margin,
1067 : : int bottom_margin)
1068 : : {
1069 : 0 : int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
1070 : 0 : int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
1071 : 0 : int new_vtotal = mode->vtotal * vdisplay /
1072 : 0 : (mode->vdisplay - top_margin - bottom_margin);
1073 : :
1074 : 0 : mode->clock = mode->clock * new_vtotal / mode->vtotal;
1075 : :
1076 : 0 : mode->vdisplay = vdisplay;
1077 : 0 : mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
1078 : 0 : mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
1079 : 0 : mode->vtotal = new_vtotal;
1080 : 0 : }
1081 : :
1082 : : static void
1083 : 0 : intel_tv_get_config(struct intel_encoder *encoder,
1084 : : struct intel_crtc_state *pipe_config)
1085 : : {
1086 : 0 : struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1087 : 0 : struct drm_display_mode *adjusted_mode =
1088 : : &pipe_config->hw.adjusted_mode;
1089 : 0 : struct drm_display_mode mode = {};
1090 : 0 : u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
1091 : 0 : struct tv_mode tv_mode = {};
1092 : 0 : int hdisplay = adjusted_mode->crtc_hdisplay;
1093 : 0 : int vdisplay = adjusted_mode->crtc_vdisplay;
1094 : 0 : int xsize, ysize, xpos, ypos;
1095 : :
1096 : 0 : pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
1097 : :
1098 : 0 : tv_ctl = I915_READ(TV_CTL);
1099 : 0 : hctl1 = I915_READ(TV_H_CTL_1);
1100 : 0 : hctl3 = I915_READ(TV_H_CTL_3);
1101 : 0 : vctl1 = I915_READ(TV_V_CTL_1);
1102 : 0 : vctl2 = I915_READ(TV_V_CTL_2);
1103 : :
1104 : 0 : tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
1105 : 0 : tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
1106 : :
1107 : 0 : tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
1108 : 0 : tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
1109 : :
1110 : 0 : tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
1111 : 0 : tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
1112 : 0 : tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
1113 : :
1114 : 0 : tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
1115 : 0 : tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
1116 : 0 : tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
1117 : :
1118 : 0 : tv_mode.clock = pipe_config->port_clock;
1119 : :
1120 : 0 : tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
1121 : :
1122 [ # # # # ]: 0 : switch (tv_ctl & TV_OVERSAMPLE_MASK) {
1123 : 0 : case TV_OVERSAMPLE_8X:
1124 : 0 : tv_mode.oversample = 8;
1125 : 0 : break;
1126 : 0 : case TV_OVERSAMPLE_4X:
1127 : 0 : tv_mode.oversample = 4;
1128 : 0 : break;
1129 : 0 : case TV_OVERSAMPLE_2X:
1130 : 0 : tv_mode.oversample = 2;
1131 : 0 : break;
1132 : 0 : default:
1133 : 0 : tv_mode.oversample = 1;
1134 : 0 : break;
1135 : : }
1136 : :
1137 : 0 : tmp = I915_READ(TV_WIN_POS);
1138 : 0 : xpos = tmp >> 16;
1139 : 0 : ypos = tmp & 0xffff;
1140 : :
1141 : 0 : tmp = I915_READ(TV_WIN_SIZE);
1142 : 0 : xsize = tmp >> 16;
1143 : 0 : ysize = tmp & 0xffff;
1144 : :
1145 : 0 : intel_tv_mode_to_mode(&mode, &tv_mode);
1146 : :
1147 : 0 : DRM_DEBUG_KMS("TV mode:\n");
1148 : 0 : drm_mode_debug_printmodeline(&mode);
1149 : :
1150 : 0 : intel_tv_scale_mode_horiz(&mode, hdisplay,
1151 : 0 : xpos, mode.hdisplay - xsize - xpos);
1152 : 0 : intel_tv_scale_mode_vert(&mode, vdisplay,
1153 : 0 : ypos, mode.vdisplay - ysize - ypos);
1154 : :
1155 : 0 : adjusted_mode->crtc_clock = mode.clock;
1156 [ # # ]: 0 : if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
1157 : 0 : adjusted_mode->crtc_clock /= 2;
1158 : :
1159 : : /* pixel counter doesn't work on i965gm TV output */
1160 [ # # ]: 0 : if (IS_I965GM(dev_priv))
1161 : 0 : adjusted_mode->private_flags |=
1162 : : I915_MODE_FLAG_USE_SCANLINE_COUNTER;
1163 : 0 : }
1164 : :
1165 : 0 : static bool intel_tv_source_too_wide(struct drm_i915_private *dev_priv,
1166 : : int hdisplay)
1167 : : {
1168 [ # # ]: 0 : return IS_GEN(dev_priv, 3) && hdisplay > 1024;
1169 : : }
1170 : :
1171 : 0 : static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode,
1172 : : const struct drm_connector_state *conn_state,
1173 : : int vdisplay)
1174 : : {
1175 : 0 : return tv_mode->crtc_vdisplay -
1176 : 0 : conn_state->tv.margins.top -
1177 : 0 : conn_state->tv.margins.bottom !=
1178 : : vdisplay;
1179 : : }
1180 : :
1181 : : static int
1182 : 0 : intel_tv_compute_config(struct intel_encoder *encoder,
1183 : : struct intel_crtc_state *pipe_config,
1184 : : struct drm_connector_state *conn_state)
1185 : : {
1186 [ # # ]: 0 : struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1187 : 0 : struct intel_tv_connector_state *tv_conn_state =
1188 : 0 : to_intel_tv_connector_state(conn_state);
1189 : 0 : const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
1190 : 0 : struct drm_display_mode *adjusted_mode =
1191 : : &pipe_config->hw.adjusted_mode;
1192 : 0 : int hdisplay = adjusted_mode->crtc_hdisplay;
1193 : 0 : int vdisplay = adjusted_mode->crtc_vdisplay;
1194 : :
1195 : 0 : if (!tv_mode)
1196 : : return -EINVAL;
1197 : :
1198 [ # # ]: 0 : if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
1199 : : return -EINVAL;
1200 : :
1201 : 0 : pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
1202 : :
1203 : 0 : DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
1204 : 0 : pipe_config->pipe_bpp = 8*3;
1205 : :
1206 : 0 : pipe_config->port_clock = tv_mode->clock;
1207 : :
1208 : 0 : intel_tv_mode_to_mode(adjusted_mode, tv_mode);
1209 : 0 : drm_mode_set_crtcinfo(adjusted_mode, 0);
1210 : :
1211 [ # # # # ]: 0 : if (intel_tv_source_too_wide(dev_priv, hdisplay) ||
1212 [ # # ]: 0 : !intel_tv_vert_scaling(adjusted_mode, conn_state, vdisplay)) {
1213 : 0 : int extra, top, bottom;
1214 : :
1215 : 0 : extra = adjusted_mode->crtc_vdisplay - vdisplay;
1216 : :
1217 [ # # ]: 0 : if (extra < 0) {
1218 : 0 : DRM_DEBUG_KMS("No vertical scaling for >1024 pixel wide modes\n");
1219 : 0 : return -EINVAL;
1220 : : }
1221 : :
1222 : : /* Need to turn off the vertical filter and center the image */
1223 : :
1224 : : /* Attempt to maintain the relative sizes of the margins */
1225 : 0 : top = conn_state->tv.margins.top;
1226 : 0 : bottom = conn_state->tv.margins.bottom;
1227 : :
1228 [ # # ]: 0 : if (top + bottom)
1229 : 0 : top = extra * top / (top + bottom);
1230 : : else
1231 : 0 : top = extra / 2;
1232 : 0 : bottom = extra - top;
1233 : :
1234 : 0 : tv_conn_state->margins.top = top;
1235 : 0 : tv_conn_state->margins.bottom = bottom;
1236 : :
1237 : 0 : tv_conn_state->bypass_vfilter = true;
1238 : :
1239 [ # # ]: 0 : if (!tv_mode->progressive) {
1240 : 0 : adjusted_mode->clock /= 2;
1241 : 0 : adjusted_mode->crtc_clock /= 2;
1242 : 0 : adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
1243 : : }
1244 : : } else {
1245 : 0 : tv_conn_state->margins.top = conn_state->tv.margins.top;
1246 : 0 : tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
1247 : :
1248 : 0 : tv_conn_state->bypass_vfilter = false;
1249 : : }
1250 : :
1251 : 0 : DRM_DEBUG_KMS("TV mode:\n");
1252 : 0 : drm_mode_debug_printmodeline(adjusted_mode);
1253 : :
1254 : : /*
1255 : : * The pipe scanline counter behaviour looks as follows when
1256 : : * using the TV encoder:
1257 : : *
1258 : : * time ->
1259 : : *
1260 : : * dsl=vtotal-1 | |
1261 : : * || ||
1262 : : * ___| | ___| |
1263 : : * / | / |
1264 : : * / | / |
1265 : : * dsl=0 ___/ |_____/ |
1266 : : * | | | | | |
1267 : : * ^ ^ ^ ^ ^
1268 : : * | | | | pipe vblank/first part of tv vblank
1269 : : * | | | bottom margin
1270 : : * | | active
1271 : : * | top margin
1272 : : * remainder of tv vblank
1273 : : *
1274 : : * When the TV encoder is used the pipe wants to run faster
1275 : : * than expected rate. During the active portion the TV
1276 : : * encoder stalls the pipe every few lines to keep it in
1277 : : * check. When the TV encoder reaches the bottom margin the
1278 : : * pipe simply stops. Once we reach the TV vblank the pipe is
1279 : : * no longer stalled and it runs at the max rate (apparently
1280 : : * oversample clock on gen3, cdclk on gen4). Once the pipe
1281 : : * reaches the pipe vtotal the pipe stops for the remainder
1282 : : * of the TV vblank/top margin. The pipe starts up again when
1283 : : * the TV encoder exits the top margin.
1284 : : *
1285 : : * To avoid huge hassles for vblank timestamping we scale
1286 : : * the pipe timings as if the pipe always runs at the average
1287 : : * rate it maintains during the active period. This also
1288 : : * gives us a reasonable guesstimate as to the pixel rate.
1289 : : * Due to the variation in the actual pipe speed the scanline
1290 : : * counter will give us slightly erroneous results during the
1291 : : * TV vblank/margins. But since vtotal was selected such that
1292 : : * it matches the average rate of the pipe during the active
1293 : : * portion the error shouldn't cause any serious grief to
1294 : : * vblank timestamps.
1295 : : *
1296 : : * For posterity here is the empirically derived formula
1297 : : * that gives us the maximum length of the pipe vblank
1298 : : * we can use without causing display corruption. Following
1299 : : * this would allow us to have a ticking scanline counter
1300 : : * everywhere except during the bottom margin (there the
1301 : : * pipe always stops). Ie. this would eliminate the second
1302 : : * flat portion of the above graph. However this would also
1303 : : * complicate vblank timestamping as the pipe vtotal would
1304 : : * no longer match the average rate the pipe runs at during
1305 : : * the active portion. Hence following this formula seems
1306 : : * more trouble that it's worth.
1307 : : *
1308 : : * if (IS_GEN(dev_priv, 4)) {
1309 : : * num = cdclk * (tv_mode->oversample >> !tv_mode->progressive);
1310 : : * den = tv_mode->clock;
1311 : : * } else {
1312 : : * num = tv_mode->oversample >> !tv_mode->progressive;
1313 : : * den = 1;
1314 : : * }
1315 : : * max_pipe_vblank_len ~=
1316 : : * (num * tv_htotal * (tv_vblank_len + top_margin)) /
1317 : : * (den * pipe_htotal);
1318 : : */
1319 : 0 : intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
1320 : 0 : conn_state->tv.margins.left,
1321 : 0 : conn_state->tv.margins.right);
1322 : 0 : intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
1323 : 0 : tv_conn_state->margins.top,
1324 : 0 : tv_conn_state->margins.bottom);
1325 : 0 : drm_mode_set_crtcinfo(adjusted_mode, 0);
1326 : 0 : adjusted_mode->name[0] = '\0';
1327 : :
1328 : : /* pixel counter doesn't work on i965gm TV output */
1329 [ # # ]: 0 : if (IS_I965GM(dev_priv))
1330 : 0 : adjusted_mode->private_flags |=
1331 : : I915_MODE_FLAG_USE_SCANLINE_COUNTER;
1332 : :
1333 : : return 0;
1334 : : }
1335 : :
1336 : : static void
1337 : 0 : set_tv_mode_timings(struct drm_i915_private *dev_priv,
1338 : : const struct tv_mode *tv_mode,
1339 : : bool burst_ena)
1340 : : {
1341 : 0 : u32 hctl1, hctl2, hctl3;
1342 : 0 : u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1343 : :
1344 : 0 : hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1345 : 0 : (tv_mode->htotal << TV_HTOTAL_SHIFT);
1346 : :
1347 : 0 : hctl2 = (tv_mode->hburst_start << 16) |
1348 : 0 : (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1349 : :
1350 [ # # ]: 0 : if (burst_ena)
1351 : 0 : hctl2 |= TV_BURST_ENA;
1352 : :
1353 : 0 : hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1354 : 0 : (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1355 : :
1356 : 0 : vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1357 : 0 : (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1358 : 0 : (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1359 : :
1360 : 0 : vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1361 : 0 : (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1362 : 0 : (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1363 : :
1364 : 0 : vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1365 : 0 : (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1366 : 0 : (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1367 : :
1368 [ # # ]: 0 : if (tv_mode->veq_ena)
1369 : 0 : vctl3 |= TV_EQUAL_ENA;
1370 : :
1371 : 0 : vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1372 : 0 : (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1373 : :
1374 : 0 : vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1375 : 0 : (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1376 : :
1377 : 0 : vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1378 : 0 : (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1379 : :
1380 : 0 : vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1381 : 0 : (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1382 : :
1383 : 0 : I915_WRITE(TV_H_CTL_1, hctl1);
1384 : 0 : I915_WRITE(TV_H_CTL_2, hctl2);
1385 : 0 : I915_WRITE(TV_H_CTL_3, hctl3);
1386 : 0 : I915_WRITE(TV_V_CTL_1, vctl1);
1387 : 0 : I915_WRITE(TV_V_CTL_2, vctl2);
1388 : 0 : I915_WRITE(TV_V_CTL_3, vctl3);
1389 : 0 : I915_WRITE(TV_V_CTL_4, vctl4);
1390 : 0 : I915_WRITE(TV_V_CTL_5, vctl5);
1391 : 0 : I915_WRITE(TV_V_CTL_6, vctl6);
1392 : 0 : I915_WRITE(TV_V_CTL_7, vctl7);
1393 : 0 : }
1394 : :
1395 : 0 : static void set_color_conversion(struct drm_i915_private *dev_priv,
1396 : : const struct color_conversion *color_conversion)
1397 : : {
1398 [ # # ]: 0 : if (!color_conversion)
1399 : : return;
1400 : :
1401 : 0 : I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1402 : : color_conversion->gy);
1403 : 0 : I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
1404 : : color_conversion->ay);
1405 : 0 : I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1406 : : color_conversion->gu);
1407 : 0 : I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1408 : : color_conversion->au);
1409 : 0 : I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1410 : : color_conversion->gv);
1411 : 0 : I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1412 : : color_conversion->av);
1413 : : }
1414 : :
1415 : 0 : static void intel_tv_pre_enable(struct intel_encoder *encoder,
1416 : : const struct intel_crtc_state *pipe_config,
1417 : : const struct drm_connector_state *conn_state)
1418 : : {
1419 : 0 : struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1420 : 0 : struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc);
1421 : 0 : struct intel_tv *intel_tv = enc_to_tv(encoder);
1422 : 0 : const struct intel_tv_connector_state *tv_conn_state =
1423 : 0 : to_intel_tv_connector_state(conn_state);
1424 : 0 : const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
1425 : 0 : u32 tv_ctl, tv_filter_ctl;
1426 : 0 : u32 scctl1, scctl2, scctl3;
1427 : 0 : int i, j;
1428 : 0 : const struct video_levels *video_levels;
1429 : 0 : const struct color_conversion *color_conversion;
1430 : 0 : bool burst_ena;
1431 : 0 : int xpos, ypos;
1432 : 0 : unsigned int xsize, ysize;
1433 : :
1434 : 0 : if (!tv_mode)
1435 : : return; /* can't happen (mode_prepare prevents this) */
1436 : :
1437 : 0 : tv_ctl = I915_READ(TV_CTL);
1438 : 0 : tv_ctl &= TV_CTL_SAVE;
1439 : :
1440 [ # # # ]: 0 : switch (intel_tv->type) {
1441 : 0 : default:
1442 : : case DRM_MODE_CONNECTOR_Unknown:
1443 : : case DRM_MODE_CONNECTOR_Composite:
1444 : 0 : tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1445 : 0 : video_levels = tv_mode->composite_levels;
1446 : 0 : color_conversion = tv_mode->composite_color;
1447 : 0 : burst_ena = tv_mode->burst_ena;
1448 : 0 : break;
1449 : 0 : case DRM_MODE_CONNECTOR_Component:
1450 : 0 : tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1451 : 0 : video_levels = &component_levels;
1452 [ # # ]: 0 : if (tv_mode->burst_ena)
1453 : : color_conversion = &sdtv_csc_yprpb;
1454 : : else
1455 : 0 : color_conversion = &hdtv_csc_yprpb;
1456 : : burst_ena = false;
1457 : : break;
1458 : 0 : case DRM_MODE_CONNECTOR_SVIDEO:
1459 : 0 : tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1460 : 0 : video_levels = tv_mode->svideo_levels;
1461 : 0 : color_conversion = tv_mode->svideo_color;
1462 : 0 : burst_ena = tv_mode->burst_ena;
1463 : 0 : break;
1464 : : }
1465 : :
1466 : 0 : tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1467 : :
1468 [ # # # # ]: 0 : switch (tv_mode->oversample) {
1469 : 0 : case 8:
1470 : 0 : tv_ctl |= TV_OVERSAMPLE_8X;
1471 : 0 : break;
1472 : : case 4:
1473 : : tv_ctl |= TV_OVERSAMPLE_4X;
1474 : : break;
1475 : 0 : case 2:
1476 : 0 : tv_ctl |= TV_OVERSAMPLE_2X;
1477 : 0 : break;
1478 : 0 : default:
1479 : 0 : tv_ctl |= TV_OVERSAMPLE_NONE;
1480 : 0 : break;
1481 : : }
1482 : :
1483 [ # # ]: 0 : if (tv_mode->progressive)
1484 : 0 : tv_ctl |= TV_PROGRESSIVE;
1485 [ # # ]: 0 : if (tv_mode->trilevel_sync)
1486 : 0 : tv_ctl |= TV_TRILEVEL_SYNC;
1487 [ # # ]: 0 : if (tv_mode->pal_burst)
1488 : 0 : tv_ctl |= TV_PAL_BURST;
1489 : :
1490 : 0 : scctl1 = 0;
1491 [ # # ]: 0 : if (tv_mode->dda1_inc)
1492 : 0 : scctl1 |= TV_SC_DDA1_EN;
1493 [ # # ]: 0 : if (tv_mode->dda2_inc)
1494 : 0 : scctl1 |= TV_SC_DDA2_EN;
1495 [ # # ]: 0 : if (tv_mode->dda3_inc)
1496 : 0 : scctl1 |= TV_SC_DDA3_EN;
1497 : 0 : scctl1 |= tv_mode->sc_reset;
1498 [ # # ]: 0 : if (video_levels)
1499 : 0 : scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1500 : 0 : scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1501 : :
1502 : 0 : scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1503 : 0 : tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1504 : :
1505 : 0 : scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1506 : 0 : tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1507 : :
1508 : : /* Enable two fixes for the chips that need them. */
1509 [ # # ]: 0 : if (IS_I915GM(dev_priv))
1510 : 0 : tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1511 : :
1512 : 0 : set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1513 : :
1514 : 0 : I915_WRITE(TV_SC_CTL_1, scctl1);
1515 : 0 : I915_WRITE(TV_SC_CTL_2, scctl2);
1516 : 0 : I915_WRITE(TV_SC_CTL_3, scctl3);
1517 : :
1518 : 0 : set_color_conversion(dev_priv, color_conversion);
1519 : :
1520 [ # # ]: 0 : if (INTEL_GEN(dev_priv) >= 4)
1521 : 0 : I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1522 : : else
1523 : 0 : I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1524 : :
1525 [ # # ]: 0 : if (video_levels)
1526 : 0 : I915_WRITE(TV_CLR_LEVEL,
1527 : : ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1528 : : (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1529 : :
1530 : 0 : assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder);
1531 : :
1532 : : /* Filter ctl must be set before TV_WIN_SIZE */
1533 : 0 : tv_filter_ctl = TV_AUTO_SCALE;
1534 [ # # ]: 0 : if (tv_conn_state->bypass_vfilter)
1535 : 0 : tv_filter_ctl |= TV_V_FILTER_BYPASS;
1536 : 0 : I915_WRITE(TV_FILTER_CTL_1, tv_filter_ctl);
1537 : :
1538 : 0 : xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1539 [ # # ]: 0 : ysize = intel_tv_mode_vdisplay(tv_mode);
1540 : :
1541 : 0 : xpos = conn_state->tv.margins.left;
1542 : 0 : ypos = tv_conn_state->margins.top;
1543 : 0 : xsize -= (conn_state->tv.margins.left +
1544 : 0 : conn_state->tv.margins.right);
1545 : 0 : ysize -= (tv_conn_state->margins.top +
1546 : 0 : tv_conn_state->margins.bottom);
1547 : 0 : I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1548 : 0 : I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1549 : :
1550 : 0 : j = 0;
1551 [ # # ]: 0 : for (i = 0; i < 60; i++)
1552 : 0 : I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
1553 [ # # ]: 0 : for (i = 0; i < 60; i++)
1554 : 0 : I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
1555 [ # # ]: 0 : for (i = 0; i < 43; i++)
1556 : 0 : I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
1557 [ # # ]: 0 : for (i = 0; i < 43; i++)
1558 : 0 : I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
1559 : 0 : I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1560 : 0 : I915_WRITE(TV_CTL, tv_ctl);
1561 : : }
1562 : :
1563 : : static int
1564 : : intel_tv_detect_type(struct intel_tv *intel_tv,
1565 : : struct drm_connector *connector)
1566 : : {
1567 : : struct drm_crtc *crtc = connector->state->crtc;
1568 : : struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1569 : : struct drm_device *dev = connector->dev;
1570 : : struct drm_i915_private *dev_priv = to_i915(dev);
1571 : : u32 tv_ctl, save_tv_ctl;
1572 : : u32 tv_dac, save_tv_dac;
1573 : : int type;
1574 : :
1575 : : /* Disable TV interrupts around load detect or we'll recurse */
1576 : : if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1577 : : spin_lock_irq(&dev_priv->irq_lock);
1578 : : i915_disable_pipestat(dev_priv, 0,
1579 : : PIPE_HOTPLUG_INTERRUPT_STATUS |
1580 : : PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1581 : : spin_unlock_irq(&dev_priv->irq_lock);
1582 : : }
1583 : :
1584 : : save_tv_dac = tv_dac = I915_READ(TV_DAC);
1585 : : save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1586 : :
1587 : : /* Poll for TV detection */
1588 : : tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
1589 : : tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1590 : : tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1591 : :
1592 : : tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1593 : : tv_dac |= (TVDAC_STATE_CHG_EN |
1594 : : TVDAC_A_SENSE_CTL |
1595 : : TVDAC_B_SENSE_CTL |
1596 : : TVDAC_C_SENSE_CTL |
1597 : : DAC_CTL_OVERRIDE |
1598 : : DAC_A_0_7_V |
1599 : : DAC_B_0_7_V |
1600 : : DAC_C_0_7_V);
1601 : :
1602 : :
1603 : : /*
1604 : : * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1605 : : * the TV is misdetected. This is hardware requirement.
1606 : : */
1607 : : if (IS_GM45(dev_priv))
1608 : : tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1609 : : TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1610 : :
1611 : : I915_WRITE(TV_CTL, tv_ctl);
1612 : : I915_WRITE(TV_DAC, tv_dac);
1613 : : POSTING_READ(TV_DAC);
1614 : :
1615 : : intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1616 : :
1617 : : type = -1;
1618 : : tv_dac = I915_READ(TV_DAC);
1619 : : DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1620 : : /*
1621 : : * A B C
1622 : : * 0 1 1 Composite
1623 : : * 1 0 X svideo
1624 : : * 0 0 0 Component
1625 : : */
1626 : : if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1627 : : DRM_DEBUG_KMS("Detected Composite TV connection\n");
1628 : : type = DRM_MODE_CONNECTOR_Composite;
1629 : : } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1630 : : DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1631 : : type = DRM_MODE_CONNECTOR_SVIDEO;
1632 : : } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1633 : : DRM_DEBUG_KMS("Detected Component TV connection\n");
1634 : : type = DRM_MODE_CONNECTOR_Component;
1635 : : } else {
1636 : : DRM_DEBUG_KMS("Unrecognised TV connection\n");
1637 : : type = -1;
1638 : : }
1639 : :
1640 : : I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1641 : : I915_WRITE(TV_CTL, save_tv_ctl);
1642 : : POSTING_READ(TV_CTL);
1643 : :
1644 : : /* For unknown reasons the hw barfs if we don't do this vblank wait. */
1645 : : intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1646 : :
1647 : : /* Restore interrupt config */
1648 : : if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1649 : : spin_lock_irq(&dev_priv->irq_lock);
1650 : : i915_enable_pipestat(dev_priv, 0,
1651 : : PIPE_HOTPLUG_INTERRUPT_STATUS |
1652 : : PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1653 : : spin_unlock_irq(&dev_priv->irq_lock);
1654 : : }
1655 : :
1656 : : return type;
1657 : : }
1658 : :
1659 : : /*
1660 : : * Here we set accurate tv format according to connector type
1661 : : * i.e Component TV should not be assigned by NTSC or PAL
1662 : : */
1663 : 0 : static void intel_tv_find_better_format(struct drm_connector *connector)
1664 : : {
1665 : 0 : struct intel_tv *intel_tv = intel_attached_tv(to_intel_connector(connector));
1666 : 0 : const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1667 : 0 : int i;
1668 : :
1669 : : /* Component supports everything so we can keep the current mode */
1670 [ # # ]: 0 : if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
1671 : : return;
1672 : :
1673 : : /* If the current mode is fine don't change it */
1674 [ # # ]: 0 : if (!tv_mode->component_only)
1675 : : return;
1676 : :
1677 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1678 : 0 : tv_mode = &tv_modes[i];
1679 : :
1680 [ # # ]: 0 : if (!tv_mode->component_only)
1681 : : break;
1682 : : }
1683 : :
1684 : 0 : connector->state->tv.mode = i;
1685 : : }
1686 : :
1687 : : static int
1688 : 0 : intel_tv_detect(struct drm_connector *connector,
1689 : : struct drm_modeset_acquire_ctx *ctx,
1690 : : bool force)
1691 : : {
1692 : 0 : struct intel_tv *intel_tv = intel_attached_tv(to_intel_connector(connector));
1693 : 0 : enum drm_connector_status status;
1694 : 0 : int type;
1695 : :
1696 : 0 : DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
1697 : : connector->base.id, connector->name,
1698 : : force);
1699 : :
1700 [ # # ]: 0 : if (force) {
1701 : 0 : struct intel_load_detect_pipe tmp;
1702 : 0 : int ret;
1703 : :
1704 : 0 : ret = intel_get_load_detect_pipe(connector, &tmp, ctx);
1705 [ # # ]: 0 : if (ret < 0)
1706 : : return ret;
1707 : :
1708 [ # # ]: 0 : if (ret > 0) {
1709 : 0 : type = intel_tv_detect_type(intel_tv, connector);
1710 : 0 : intel_release_load_detect_pipe(connector, &tmp, ctx);
1711 : 0 : status = type < 0 ?
1712 [ # # ]: 0 : connector_status_disconnected :
1713 : : connector_status_connected;
1714 : : } else
1715 : : status = connector_status_unknown;
1716 : :
1717 [ # # ]: 0 : if (status == connector_status_connected) {
1718 : 0 : intel_tv->type = type;
1719 [ # # ]: 0 : intel_tv_find_better_format(connector);
1720 : : }
1721 : :
1722 : 0 : return status;
1723 : : } else
1724 : 0 : return connector->status;
1725 : : }
1726 : :
1727 : : static const struct input_res {
1728 : : u16 w, h;
1729 : : } input_res_table[] = {
1730 : : { 640, 480 },
1731 : : { 800, 600 },
1732 : : { 1024, 768 },
1733 : : { 1280, 1024 },
1734 : : { 848, 480 },
1735 : : { 1280, 720 },
1736 : : { 1920, 1080 },
1737 : : };
1738 : :
1739 : : /* Choose preferred mode according to line number of TV format */
1740 : : static bool
1741 : 0 : intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
1742 : : const struct tv_mode *tv_mode)
1743 : : {
1744 : 0 : int vdisplay = intel_tv_mode_vdisplay(tv_mode);
1745 : :
1746 : : /* prefer 480 line modes for all SD TV modes */
1747 [ # # ]: 0 : if (vdisplay <= 576)
1748 : 0 : vdisplay = 480;
1749 : :
1750 : 0 : return vdisplay == mode->vdisplay;
1751 : : }
1752 : :
1753 : : static void
1754 : 0 : intel_tv_set_mode_type(struct drm_display_mode *mode,
1755 : : const struct tv_mode *tv_mode)
1756 : : {
1757 : 0 : mode->type = DRM_MODE_TYPE_DRIVER;
1758 : :
1759 [ # # ]: 0 : if (intel_tv_is_preferred_mode(mode, tv_mode))
1760 : 0 : mode->type |= DRM_MODE_TYPE_PREFERRED;
1761 : : }
1762 : :
1763 : : static int
1764 : 0 : intel_tv_get_modes(struct drm_connector *connector)
1765 : : {
1766 : 0 : struct drm_i915_private *dev_priv = to_i915(connector->dev);
1767 : 0 : const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1768 : 0 : int i, count = 0;
1769 : :
1770 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
1771 : 0 : const struct input_res *input = &input_res_table[i];
1772 : 0 : struct drm_display_mode *mode;
1773 : :
1774 [ # # ]: 0 : if (input->w > 1024 &&
1775 [ # # ]: 0 : !tv_mode->progressive &&
1776 [ # # ]: 0 : !tv_mode->component_only)
1777 : 0 : continue;
1778 : :
1779 : : /* no vertical scaling with wide sources on gen3 */
1780 [ # # # # : 0 : if (IS_GEN(dev_priv, 3) && input->w > 1024 &&
# # ]
1781 [ # # ]: 0 : input->h > intel_tv_mode_vdisplay(tv_mode))
1782 : 0 : continue;
1783 : :
1784 : 0 : mode = drm_mode_create(connector->dev);
1785 [ # # ]: 0 : if (!mode)
1786 : 0 : continue;
1787 : :
1788 : : /*
1789 : : * We take the TV mode and scale it to look
1790 : : * like it had the expected h/vdisplay. This
1791 : : * provides the most information to userspace
1792 : : * about the actual timings of the mode. We
1793 : : * do ignore the margins though.
1794 : : */
1795 : 0 : intel_tv_mode_to_mode(mode, tv_mode);
1796 [ # # ]: 0 : if (count == 0) {
1797 : 0 : DRM_DEBUG_KMS("TV mode:\n");
1798 : 0 : drm_mode_debug_printmodeline(mode);
1799 : : }
1800 : 0 : intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
1801 : 0 : intel_tv_scale_mode_vert(mode, input->h, 0, 0);
1802 [ # # ]: 0 : intel_tv_set_mode_type(mode, tv_mode);
1803 : :
1804 : 0 : drm_mode_set_name(mode);
1805 : :
1806 : 0 : drm_mode_probed_add(connector, mode);
1807 : 0 : count++;
1808 : : }
1809 : :
1810 : 0 : return count;
1811 : : }
1812 : :
1813 : : static const struct drm_connector_funcs intel_tv_connector_funcs = {
1814 : : .late_register = intel_connector_register,
1815 : : .early_unregister = intel_connector_unregister,
1816 : : .destroy = intel_connector_destroy,
1817 : : .fill_modes = drm_helper_probe_single_connector_modes,
1818 : : .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1819 : : .atomic_duplicate_state = intel_tv_connector_duplicate_state,
1820 : : };
1821 : :
1822 : 0 : static int intel_tv_atomic_check(struct drm_connector *connector,
1823 : : struct drm_atomic_state *state)
1824 : : {
1825 : 0 : struct drm_connector_state *new_state;
1826 : 0 : struct drm_crtc_state *new_crtc_state;
1827 : 0 : struct drm_connector_state *old_state;
1828 : :
1829 [ # # ]: 0 : new_state = drm_atomic_get_new_connector_state(state, connector);
1830 [ # # ]: 0 : if (!new_state->crtc)
1831 : : return 0;
1832 : :
1833 [ # # ]: 0 : old_state = drm_atomic_get_old_connector_state(state, connector);
1834 [ # # ]: 0 : new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
1835 : :
1836 [ # # ]: 0 : if (old_state->tv.mode != new_state->tv.mode ||
1837 [ # # ]: 0 : old_state->tv.margins.left != new_state->tv.margins.left ||
1838 : 0 : old_state->tv.margins.right != new_state->tv.margins.right ||
1839 [ # # ]: 0 : old_state->tv.margins.top != new_state->tv.margins.top ||
1840 [ # # ]: 0 : old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1841 : : /* Force a modeset. */
1842 : :
1843 : 0 : new_crtc_state->connectors_changed = true;
1844 : : }
1845 : :
1846 : : return 0;
1847 : : }
1848 : :
1849 : : static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1850 : : .detect_ctx = intel_tv_detect,
1851 : : .mode_valid = intel_tv_mode_valid,
1852 : : .get_modes = intel_tv_get_modes,
1853 : : .atomic_check = intel_tv_atomic_check,
1854 : : };
1855 : :
1856 : : static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1857 : : .destroy = intel_encoder_destroy,
1858 : : };
1859 : :
1860 : : void
1861 : 0 : intel_tv_init(struct drm_i915_private *dev_priv)
1862 : : {
1863 : 0 : struct drm_device *dev = &dev_priv->drm;
1864 : 0 : struct drm_connector *connector;
1865 : 0 : struct intel_tv *intel_tv;
1866 : 0 : struct intel_encoder *intel_encoder;
1867 : 0 : struct intel_connector *intel_connector;
1868 : 0 : u32 tv_dac_on, tv_dac_off, save_tv_dac;
1869 : 0 : const char *tv_format_names[ARRAY_SIZE(tv_modes)];
1870 : 0 : int i, initial_mode = 0;
1871 : 0 : struct drm_connector_state *state;
1872 : :
1873 [ # # ]: 0 : if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1874 : 0 : return;
1875 : :
1876 [ # # ]: 0 : if (!intel_bios_is_tv_present(dev_priv)) {
1877 : 0 : DRM_DEBUG_KMS("Integrated TV is not present.\n");
1878 : 0 : return;
1879 : : }
1880 : :
1881 : : /*
1882 : : * Sanity check the TV output by checking to see if the
1883 : : * DAC register holds a value
1884 : : */
1885 : 0 : save_tv_dac = I915_READ(TV_DAC);
1886 : :
1887 : 0 : I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1888 : 0 : tv_dac_on = I915_READ(TV_DAC);
1889 : :
1890 : 0 : I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1891 : 0 : tv_dac_off = I915_READ(TV_DAC);
1892 : :
1893 : 0 : I915_WRITE(TV_DAC, save_tv_dac);
1894 : :
1895 : : /*
1896 : : * If the register does not hold the state change enable
1897 : : * bit, (either as a 0 or a 1), assume it doesn't really
1898 : : * exist
1899 : : */
1900 [ # # ]: 0 : if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1901 [ # # ]: 0 : (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1902 : : return;
1903 : :
1904 : 0 : intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
1905 [ # # ]: 0 : if (!intel_tv) {
1906 : : return;
1907 : : }
1908 : :
1909 : 0 : intel_connector = intel_connector_alloc();
1910 [ # # ]: 0 : if (!intel_connector) {
1911 : 0 : kfree(intel_tv);
1912 : 0 : return;
1913 : : }
1914 : :
1915 : 0 : intel_encoder = &intel_tv->base;
1916 : 0 : connector = &intel_connector->base;
1917 : 0 : state = connector->state;
1918 : :
1919 : : /*
1920 : : * The documentation, for the older chipsets at least, recommend
1921 : : * using a polling method rather than hotplug detection for TVs.
1922 : : * This is because in order to perform the hotplug detection, the PLLs
1923 : : * for the TV must be kept alive increasing power drain and starving
1924 : : * bandwidth from other encoders. Notably for instance, it causes
1925 : : * pipe underruns on Crestline when this encoder is supposedly idle.
1926 : : *
1927 : : * More recent chipsets favour HDMI rather than integrated S-Video.
1928 : : */
1929 : 0 : intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1930 : :
1931 : 0 : drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1932 : : DRM_MODE_CONNECTOR_SVIDEO);
1933 : :
1934 : 0 : drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1935 : : DRM_MODE_ENCODER_TVDAC, "TV");
1936 : :
1937 : 0 : intel_encoder->compute_config = intel_tv_compute_config;
1938 : 0 : intel_encoder->get_config = intel_tv_get_config;
1939 : 0 : intel_encoder->pre_enable = intel_tv_pre_enable;
1940 : 0 : intel_encoder->enable = intel_enable_tv;
1941 : 0 : intel_encoder->disable = intel_disable_tv;
1942 : 0 : intel_encoder->get_hw_state = intel_tv_get_hw_state;
1943 : 0 : intel_connector->get_hw_state = intel_connector_get_hw_state;
1944 : :
1945 : 0 : intel_connector_attach_encoder(intel_connector, intel_encoder);
1946 : :
1947 : 0 : intel_encoder->type = INTEL_OUTPUT_TVOUT;
1948 : 0 : intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
1949 : 0 : intel_encoder->port = PORT_NONE;
1950 : 0 : intel_encoder->pipe_mask = ~0;
1951 : 0 : intel_encoder->cloneable = 0;
1952 : 0 : intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1953 : :
1954 : : /* BIOS margin values */
1955 : 0 : state->tv.margins.left = 54;
1956 : 0 : state->tv.margins.top = 36;
1957 : 0 : state->tv.margins.right = 46;
1958 : 0 : state->tv.margins.bottom = 37;
1959 : :
1960 : 0 : state->tv.mode = initial_mode;
1961 : :
1962 : 0 : drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1963 : 0 : connector->interlace_allowed = false;
1964 : 0 : connector->doublescan_allowed = false;
1965 : :
1966 : : /* Create TV properties then attach current values */
1967 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1968 : : /* 1080p50/1080p60 not supported on gen3 */
1969 [ # # ]: 0 : if (IS_GEN(dev_priv, 3) &&
1970 [ # # ]: 0 : tv_modes[i].oversample == 1)
1971 : : break;
1972 : :
1973 : 0 : tv_format_names[i] = tv_modes[i].name;
1974 : : }
1975 : 0 : drm_mode_create_tv_properties(dev, i, tv_format_names);
1976 : :
1977 : 0 : drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
1978 : 0 : state->tv.mode);
1979 : 0 : drm_object_attach_property(&connector->base,
1980 : : dev->mode_config.tv_left_margin_property,
1981 : 0 : state->tv.margins.left);
1982 : 0 : drm_object_attach_property(&connector->base,
1983 : : dev->mode_config.tv_top_margin_property,
1984 : 0 : state->tv.margins.top);
1985 : 0 : drm_object_attach_property(&connector->base,
1986 : : dev->mode_config.tv_right_margin_property,
1987 : 0 : state->tv.margins.right);
1988 : 0 : drm_object_attach_property(&connector->base,
1989 : : dev->mode_config.tv_bottom_margin_property,
1990 : 0 : state->tv.margins.bottom);
1991 : : }
|