2 * Copyright © 2006-2008 Intel Corporation
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:
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
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.
30 * Integrated TV-out support for the 915GM and 945GM.
34 #include <drm/drm_atomic_helper.h>
35 #include <drm/drm_crtc.h>
36 #include <drm/drm_edid.h>
37 #include "intel_drv.h"
38 #include <drm/i915_drm.h>
42 TV_MARGIN_LEFT, TV_MARGIN_TOP,
43 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
47 struct intel_encoder base;
57 struct color_conversion {
63 static 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,
119 * Color conversion values have 3 separate fixed point formats:
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)
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)
148 * Simple conversion function:
151 * float_to_csc_11(float f)
164 * for (exp = 0; exp < 3 && f < 0.5; exp++)
166 * mant = (f * (1 << 9) + 0.5);
167 * if (mant >= (1 << 9))
168 * mant = (1 << 9) - 1;
170 * ret = (exp << 9) | mant;
176 * Behold, magic numbers! If we plant them they might grow a big
177 * s-video cable to the sky... or something.
179 * Pre-converted to appropriate hex value.
183 * PAL & NTSC values for composite & s-video connections
185 static const struct color_conversion ntsc_m_csc_composite = {
186 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
187 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
188 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
191 static const struct video_levels ntsc_m_levels_composite = {
192 .blank = 225, .black = 267, .burst = 113,
195 static const struct color_conversion ntsc_m_csc_svideo = {
196 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
197 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
198 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
201 static const struct video_levels ntsc_m_levels_svideo = {
202 .blank = 266, .black = 316, .burst = 133,
205 static const struct color_conversion ntsc_j_csc_composite = {
206 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
207 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
208 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
211 static const struct video_levels ntsc_j_levels_composite = {
212 .blank = 225, .black = 225, .burst = 113,
215 static const struct color_conversion ntsc_j_csc_svideo = {
216 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
217 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
218 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
221 static const struct video_levels ntsc_j_levels_svideo = {
222 .blank = 266, .black = 266, .burst = 133,
225 static const struct color_conversion pal_csc_composite = {
226 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
227 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
228 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
231 static const struct video_levels pal_levels_composite = {
232 .blank = 237, .black = 237, .burst = 118,
235 static const struct color_conversion pal_csc_svideo = {
236 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
237 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
238 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
241 static const struct video_levels pal_levels_svideo = {
242 .blank = 280, .black = 280, .burst = 139,
245 static const struct color_conversion pal_m_csc_composite = {
246 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
247 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
248 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
251 static const struct video_levels pal_m_levels_composite = {
252 .blank = 225, .black = 267, .burst = 113,
255 static const struct color_conversion pal_m_csc_svideo = {
256 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
257 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
258 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
261 static const struct video_levels pal_m_levels_svideo = {
262 .blank = 266, .black = 316, .burst = 133,
265 static const struct color_conversion pal_n_csc_composite = {
266 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
267 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
268 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
271 static const struct video_levels pal_n_levels_composite = {
272 .blank = 225, .black = 267, .burst = 118,
275 static const struct color_conversion pal_n_csc_svideo = {
276 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
277 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
278 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
281 static const struct video_levels pal_n_levels_svideo = {
282 .blank = 266, .black = 316, .burst = 139,
286 * Component connections
288 static const struct color_conversion sdtv_csc_yprpb = {
289 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
290 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
291 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
294 static const struct color_conversion hdtv_csc_yprpb = {
295 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
296 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
297 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
300 static const struct video_levels component_levels = {
301 .blank = 279, .black = 279, .burst = 0,
309 u16 refresh; /* in millihertz (for precision) */
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;
316 u8 veq_start_f1, veq_start_f2, veq_len;
317 u8 vi_end_f1, vi_end_f2;
320 u8 hburst_start, hburst_len;
330 * subcarrier programming
332 u16 dda2_size, dda3_size;
334 u16 dda2_inc, dda3_inc;
340 const struct video_levels *composite_levels, *svideo_levels;
341 const struct color_conversion *composite_color, *svideo_color;
342 const u32 *filter_table;
350 * I think this works as follows:
352 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
354 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
357 * dda1_ideal = subcarrier/pixel * 4096
358 * dda1_inc = floor (dda1_ideal)
359 * dda2 = dda1_ideal - dda1_inc
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
367 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
369 * The constants below were all computed using a 107.520MHz clock
373 * Register programming values for TV modes.
375 * These values account for -1s required.
377 static const struct tv_mode tv_modes[] = {
382 .oversample = TV_OVERSAMPLE_8X,
384 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
386 .hsync_end = 64, .hblank_end = 124,
387 .hblank_start = 836, .htotal = 857,
389 .progressive = false, .trilevel_sync = false,
391 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
394 .veq_ena = true, .veq_start_f1 = 0,
395 .veq_start_f2 = 1, .veq_len = 18,
397 .vi_end_f1 = 20, .vi_end_f2 = 21,
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,
407 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
409 .dda2_inc = 20800, .dda2_size = 27456,
410 .dda3_inc = 0, .dda3_size = 0,
411 .sc_reset = TV_SC_RESET_EVERY_4,
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,
419 .filter_table = filter_table,
425 .oversample = TV_OVERSAMPLE_8X,
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,
431 .progressive = false, .trilevel_sync = false,
433 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
436 .veq_ena = true, .veq_start_f1 = 0,
437 .veq_start_f2 = 1, .veq_len = 18,
439 .vi_end_f1 = 20, .vi_end_f2 = 21,
443 .hburst_start = 72, .hburst_len = 34,
444 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
445 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
446 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
447 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
449 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
451 .dda2_inc = 4093, .dda2_size = 27456,
452 .dda3_inc = 310, .dda3_size = 525,
453 .sc_reset = TV_SC_RESET_NEVER,
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,
461 .filter_table = filter_table,
467 .oversample = TV_OVERSAMPLE_8X,
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,
474 .progressive = false, .trilevel_sync = false,
476 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
479 .veq_ena = true, .veq_start_f1 = 0,
480 .veq_start_f2 = 1, .veq_len = 18,
482 .vi_end_f1 = 20, .vi_end_f2 = 21,
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,
492 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
494 .dda2_inc = 20800, .dda2_size = 27456,
495 .dda3_inc = 0, .dda3_size = 0,
496 .sc_reset = TV_SC_RESET_EVERY_4,
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,
504 .filter_table = filter_table,
510 .oversample = TV_OVERSAMPLE_8X,
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,
517 .progressive = false, .trilevel_sync = false,
519 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
522 .veq_ena = true, .veq_start_f1 = 0,
523 .veq_start_f2 = 1, .veq_len = 18,
525 .vi_end_f1 = 20, .vi_end_f2 = 21,
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,
535 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
537 .dda2_inc = 16704, .dda2_size = 27456,
538 .dda3_inc = 0, .dda3_size = 0,
539 .sc_reset = TV_SC_RESET_EVERY_8,
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,
547 .filter_table = filter_table,
550 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
554 .oversample = TV_OVERSAMPLE_8X,
557 .hsync_end = 64, .hblank_end = 128,
558 .hblank_start = 844, .htotal = 863,
560 .progressive = false, .trilevel_sync = false,
563 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
566 .veq_ena = true, .veq_start_f1 = 0,
567 .veq_start_f2 = 1, .veq_len = 18,
569 .vi_end_f1 = 24, .vi_end_f2 = 25,
573 .hburst_start = 73, .hburst_len = 34,
574 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
575 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
576 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
577 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
580 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
582 .dda2_inc = 23578, .dda2_size = 27648,
583 .dda3_inc = 134, .dda3_size = 625,
584 .sc_reset = TV_SC_RESET_EVERY_8,
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,
592 .filter_table = filter_table,
595 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
599 .oversample = TV_OVERSAMPLE_8X,
602 .hsync_end = 64, .hblank_end = 142,
603 .hblank_start = 844, .htotal = 863,
605 .progressive = false, .trilevel_sync = false,
607 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
610 .veq_ena = true, .veq_start_f1 = 0,
611 .veq_start_f2 = 1, .veq_len = 15,
613 .vi_end_f1 = 24, .vi_end_f2 = 25,
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,
623 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
625 .dda2_inc = 4122, .dda2_size = 27648,
626 .dda3_inc = 67, .dda3_size = 625,
627 .sc_reset = TV_SC_RESET_EVERY_8,
630 .composite_levels = &pal_levels_composite,
631 .composite_color = &pal_csc_composite,
632 .svideo_levels = &pal_levels_svideo,
633 .svideo_color = &pal_csc_svideo,
635 .filter_table = filter_table,
641 .oversample = TV_OVERSAMPLE_4X,
644 .hsync_end = 64, .hblank_end = 122,
645 .hblank_start = 842, .htotal = 857,
647 .progressive = true, .trilevel_sync = false,
649 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
654 .vi_end_f1 = 44, .vi_end_f2 = 44,
659 .filter_table = filter_table,
665 .oversample = TV_OVERSAMPLE_4X,
668 .hsync_end = 64, .hblank_end = 139,
669 .hblank_start = 859, .htotal = 863,
671 .progressive = true, .trilevel_sync = false,
673 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
678 .vi_end_f1 = 48, .vi_end_f2 = 48,
683 .filter_table = filter_table,
689 .oversample = TV_OVERSAMPLE_2X,
692 .hsync_end = 80, .hblank_end = 300,
693 .hblank_start = 1580, .htotal = 1649,
695 .progressive = true, .trilevel_sync = true,
697 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
702 .vi_end_f1 = 29, .vi_end_f2 = 29,
707 .filter_table = filter_table,
713 .oversample = TV_OVERSAMPLE_2X,
716 .hsync_end = 80, .hblank_end = 300,
717 .hblank_start = 1580, .htotal = 1979,
719 .progressive = true, .trilevel_sync = true,
721 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
726 .vi_end_f1 = 29, .vi_end_f2 = 29,
731 .filter_table = filter_table,
735 .name = "1080i@50Hz",
738 .oversample = TV_OVERSAMPLE_2X,
741 .hsync_end = 88, .hblank_end = 235,
742 .hblank_start = 2155, .htotal = 2639,
744 .progressive = false, .trilevel_sync = true,
746 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
749 .veq_ena = true, .veq_start_f1 = 4,
750 .veq_start_f2 = 4, .veq_len = 10,
753 .vi_end_f1 = 21, .vi_end_f2 = 22,
758 .filter_table = filter_table,
761 .name = "1080i@60Hz",
764 .oversample = TV_OVERSAMPLE_2X,
767 .hsync_end = 88, .hblank_end = 235,
768 .hblank_start = 2155, .htotal = 2199,
770 .progressive = false, .trilevel_sync = true,
772 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
775 .veq_ena = true, .veq_start_f1 = 4,
776 .veq_start_f2 = 4, .veq_len = 10,
779 .vi_end_f1 = 21, .vi_end_f2 = 22,
784 .filter_table = filter_table,
788 static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
790 return container_of(encoder, struct intel_tv, base);
793 static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
795 return enc_to_tv(intel_attached_encoder(connector));
799 intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
801 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
802 u32 tmp = I915_READ(TV_CTL);
804 *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
806 return tmp & TV_ENC_ENABLE;
810 intel_enable_tv(struct intel_encoder *encoder,
811 const struct intel_crtc_state *pipe_config,
812 const struct drm_connector_state *conn_state)
814 struct drm_device *dev = encoder->base.dev;
815 struct drm_i915_private *dev_priv = to_i915(dev);
817 /* Prevents vblank waits from timing out in intel_tv_detect_type() */
818 intel_wait_for_vblank(dev_priv,
819 to_intel_crtc(pipe_config->base.crtc)->pipe);
821 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
825 intel_disable_tv(struct intel_encoder *encoder,
826 const struct intel_crtc_state *old_crtc_state,
827 const struct drm_connector_state *old_conn_state)
829 struct drm_device *dev = encoder->base.dev;
830 struct drm_i915_private *dev_priv = to_i915(dev);
832 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
835 static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
837 int format = conn_state->tv.mode;
839 return &tv_modes[format];
842 static enum drm_mode_status
843 intel_tv_mode_valid(struct drm_connector *connector,
844 struct drm_display_mode *mode)
846 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
847 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
849 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
850 return MODE_NO_DBLESCAN;
852 if (mode->clock > max_dotclk)
853 return MODE_CLOCK_HIGH;
855 /* Ensure TV refresh is close to desired refresh */
856 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
860 return MODE_CLOCK_RANGE;
865 intel_tv_get_config(struct intel_encoder *encoder,
866 struct intel_crtc_state *pipe_config)
868 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
870 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
874 intel_tv_compute_config(struct intel_encoder *encoder,
875 struct intel_crtc_state *pipe_config,
876 struct drm_connector_state *conn_state)
878 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
879 struct drm_display_mode *adjusted_mode =
880 &pipe_config->base.adjusted_mode;
885 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
888 pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
889 adjusted_mode->crtc_clock = tv_mode->clock;
890 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
891 pipe_config->pipe_bpp = 8*3;
893 /* TV has it's own notion of sync and other mode flags, so clear them. */
894 adjusted_mode->flags = 0;
897 * FIXME: We don't check whether the input mode is actually what we want
898 * or whether userspace is doing something stupid.
905 set_tv_mode_timings(struct drm_i915_private *dev_priv,
906 const struct tv_mode *tv_mode,
909 u32 hctl1, hctl2, hctl3;
910 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
912 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
913 (tv_mode->htotal << TV_HTOTAL_SHIFT);
915 hctl2 = (tv_mode->hburst_start << 16) |
916 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
919 hctl2 |= TV_BURST_ENA;
921 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
922 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
924 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
925 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
926 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
928 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
929 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
930 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
932 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
933 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
934 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
936 if (tv_mode->veq_ena)
937 vctl3 |= TV_EQUAL_ENA;
939 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
940 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
942 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
943 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
945 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
946 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
948 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
949 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
951 I915_WRITE(TV_H_CTL_1, hctl1);
952 I915_WRITE(TV_H_CTL_2, hctl2);
953 I915_WRITE(TV_H_CTL_3, hctl3);
954 I915_WRITE(TV_V_CTL_1, vctl1);
955 I915_WRITE(TV_V_CTL_2, vctl2);
956 I915_WRITE(TV_V_CTL_3, vctl3);
957 I915_WRITE(TV_V_CTL_4, vctl4);
958 I915_WRITE(TV_V_CTL_5, vctl5);
959 I915_WRITE(TV_V_CTL_6, vctl6);
960 I915_WRITE(TV_V_CTL_7, vctl7);
963 static void set_color_conversion(struct drm_i915_private *dev_priv,
964 const struct color_conversion *color_conversion)
966 if (!color_conversion)
969 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
970 color_conversion->gy);
971 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
972 color_conversion->ay);
973 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
974 color_conversion->gu);
975 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
976 color_conversion->au);
977 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
978 color_conversion->gv);
979 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
980 color_conversion->av);
983 static void intel_tv_pre_enable(struct intel_encoder *encoder,
984 const struct intel_crtc_state *pipe_config,
985 const struct drm_connector_state *conn_state)
987 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
988 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
989 struct intel_tv *intel_tv = enc_to_tv(encoder);
990 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
992 u32 scctl1, scctl2, scctl3;
994 const struct video_levels *video_levels;
995 const struct color_conversion *color_conversion;
997 int xpos = 0x0, ypos = 0x0;
998 unsigned int xsize, ysize;
1001 return; /* can't happen (mode_prepare prevents this) */
1003 tv_ctl = I915_READ(TV_CTL);
1004 tv_ctl &= TV_CTL_SAVE;
1006 switch (intel_tv->type) {
1008 case DRM_MODE_CONNECTOR_Unknown:
1009 case DRM_MODE_CONNECTOR_Composite:
1010 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1011 video_levels = tv_mode->composite_levels;
1012 color_conversion = tv_mode->composite_color;
1013 burst_ena = tv_mode->burst_ena;
1015 case DRM_MODE_CONNECTOR_Component:
1016 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1017 video_levels = &component_levels;
1018 if (tv_mode->burst_ena)
1019 color_conversion = &sdtv_csc_yprpb;
1021 color_conversion = &hdtv_csc_yprpb;
1024 case DRM_MODE_CONNECTOR_SVIDEO:
1025 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1026 video_levels = tv_mode->svideo_levels;
1027 color_conversion = tv_mode->svideo_color;
1028 burst_ena = tv_mode->burst_ena;
1032 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1033 tv_ctl |= tv_mode->oversample;
1035 if (tv_mode->progressive)
1036 tv_ctl |= TV_PROGRESSIVE;
1037 if (tv_mode->trilevel_sync)
1038 tv_ctl |= TV_TRILEVEL_SYNC;
1039 if (tv_mode->pal_burst)
1040 tv_ctl |= TV_PAL_BURST;
1043 if (tv_mode->dda1_inc)
1044 scctl1 |= TV_SC_DDA1_EN;
1045 if (tv_mode->dda2_inc)
1046 scctl1 |= TV_SC_DDA2_EN;
1047 if (tv_mode->dda3_inc)
1048 scctl1 |= TV_SC_DDA3_EN;
1049 scctl1 |= tv_mode->sc_reset;
1051 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1052 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1054 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1055 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1057 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1058 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1060 /* Enable two fixes for the chips that need them. */
1061 if (IS_I915GM(dev_priv))
1062 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1064 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1066 I915_WRITE(TV_SC_CTL_1, scctl1);
1067 I915_WRITE(TV_SC_CTL_2, scctl2);
1068 I915_WRITE(TV_SC_CTL_3, scctl3);
1070 set_color_conversion(dev_priv, color_conversion);
1072 if (INTEL_GEN(dev_priv) >= 4)
1073 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1075 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1078 I915_WRITE(TV_CLR_LEVEL,
1079 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1080 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1082 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
1084 /* Filter ctl must be set before TV_WIN_SIZE */
1085 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1086 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1087 if (tv_mode->progressive)
1088 ysize = tv_mode->nbr_end + 1;
1090 ysize = 2*tv_mode->nbr_end + 1;
1092 xpos += conn_state->tv.margins.left;
1093 ypos += conn_state->tv.margins.top;
1094 xsize -= (conn_state->tv.margins.left +
1095 conn_state->tv.margins.right);
1096 ysize -= (conn_state->tv.margins.top +
1097 conn_state->tv.margins.bottom);
1098 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1099 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1102 for (i = 0; i < 60; i++)
1103 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
1104 for (i = 0; i < 60; i++)
1105 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
1106 for (i = 0; i < 43; i++)
1107 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
1108 for (i = 0; i < 43; i++)
1109 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
1110 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1111 I915_WRITE(TV_CTL, tv_ctl);
1114 static const struct drm_display_mode reported_modes[] = {
1116 .name = "NTSC 480i",
1119 .hsync_start = 1368,
1124 .vsync_start = 1027,
1127 .type = DRM_MODE_TYPE_DRIVER,
1132 intel_tv_detect_type(struct intel_tv *intel_tv,
1133 struct drm_connector *connector)
1135 struct drm_crtc *crtc = connector->state->crtc;
1136 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1137 struct drm_device *dev = connector->dev;
1138 struct drm_i915_private *dev_priv = to_i915(dev);
1139 u32 tv_ctl, save_tv_ctl;
1140 u32 tv_dac, save_tv_dac;
1143 /* Disable TV interrupts around load detect or we'll recurse */
1144 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1145 spin_lock_irq(&dev_priv->irq_lock);
1146 i915_disable_pipestat(dev_priv, 0,
1147 PIPE_HOTPLUG_INTERRUPT_STATUS |
1148 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1149 spin_unlock_irq(&dev_priv->irq_lock);
1152 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1153 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1155 /* Poll for TV detection */
1156 tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
1157 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1158 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1160 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1161 tv_dac |= (TVDAC_STATE_CHG_EN |
1172 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1173 * the TV is misdetected. This is hardware requirement.
1175 if (IS_GM45(dev_priv))
1176 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1177 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1179 I915_WRITE(TV_CTL, tv_ctl);
1180 I915_WRITE(TV_DAC, tv_dac);
1181 POSTING_READ(TV_DAC);
1183 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1186 tv_dac = I915_READ(TV_DAC);
1187 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1194 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1195 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1196 type = DRM_MODE_CONNECTOR_Composite;
1197 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1198 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1199 type = DRM_MODE_CONNECTOR_SVIDEO;
1200 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1201 DRM_DEBUG_KMS("Detected Component TV connection\n");
1202 type = DRM_MODE_CONNECTOR_Component;
1204 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1208 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1209 I915_WRITE(TV_CTL, save_tv_ctl);
1210 POSTING_READ(TV_CTL);
1212 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
1213 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1215 /* Restore interrupt config */
1216 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1217 spin_lock_irq(&dev_priv->irq_lock);
1218 i915_enable_pipestat(dev_priv, 0,
1219 PIPE_HOTPLUG_INTERRUPT_STATUS |
1220 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1221 spin_unlock_irq(&dev_priv->irq_lock);
1228 * Here we set accurate tv format according to connector type
1229 * i.e Component TV should not be assigned by NTSC or PAL
1231 static void intel_tv_find_better_format(struct drm_connector *connector)
1233 struct intel_tv *intel_tv = intel_attached_tv(connector);
1234 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1237 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1238 tv_mode->component_only)
1242 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1243 tv_mode = tv_modes + i;
1245 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1246 tv_mode->component_only)
1250 connector->state->tv.mode = i;
1254 intel_tv_detect(struct drm_connector *connector,
1255 struct drm_modeset_acquire_ctx *ctx,
1258 struct drm_display_mode mode;
1259 struct intel_tv *intel_tv = intel_attached_tv(connector);
1260 enum drm_connector_status status;
1263 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
1264 connector->base.id, connector->name,
1267 mode = reported_modes[0];
1270 struct intel_load_detect_pipe tmp;
1273 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1278 type = intel_tv_detect_type(intel_tv, connector);
1279 intel_release_load_detect_pipe(connector, &tmp, ctx);
1281 connector_status_disconnected :
1282 connector_status_connected;
1284 status = connector_status_unknown;
1286 if (status == connector_status_connected) {
1287 intel_tv->type = type;
1288 intel_tv_find_better_format(connector);
1293 return connector->status;
1296 static const struct input_res {
1299 } input_res_table[] = {
1300 {"640x480", 640, 480},
1301 {"800x600", 800, 600},
1302 {"1024x768", 1024, 768},
1303 {"1280x1024", 1280, 1024},
1304 {"848x480", 848, 480},
1305 {"1280x720", 1280, 720},
1306 {"1920x1080", 1920, 1080},
1310 * Chose preferred mode according to line number of TV format
1313 intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
1314 struct drm_display_mode *mode_ptr)
1316 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1317 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1318 else if (tv_mode->nbr_end > 480) {
1319 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1320 if (mode_ptr->vdisplay == 720)
1321 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1322 } else if (mode_ptr->vdisplay == 1080)
1323 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1328 intel_tv_get_modes(struct drm_connector *connector)
1330 struct drm_display_mode *mode_ptr;
1331 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1335 for (j = 0; j < ARRAY_SIZE(input_res_table);
1337 const struct input_res *input = &input_res_table[j];
1338 unsigned int hactive_s = input->w;
1339 unsigned int vactive_s = input->h;
1341 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1344 if (input->w > 1024 && (!tv_mode->progressive
1345 && !tv_mode->component_only))
1348 mode_ptr = drm_mode_create(connector->dev);
1351 strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
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;
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;
1367 tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
1368 tmp *= mode_ptr->htotal;
1369 tmp = div_u64(tmp, 1000000);
1370 mode_ptr->clock = (int) tmp;
1372 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1373 intel_tv_choose_preferred_modes(tv_mode, mode_ptr);
1374 drm_mode_probed_add(connector, mode_ptr);
1381 static const struct drm_connector_funcs intel_tv_connector_funcs = {
1382 .late_register = intel_connector_register,
1383 .early_unregister = intel_connector_unregister,
1384 .destroy = intel_connector_destroy,
1385 .fill_modes = drm_helper_probe_single_connector_modes,
1386 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1387 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1390 static int intel_tv_atomic_check(struct drm_connector *connector,
1391 struct drm_connector_state *new_state)
1393 struct drm_crtc_state *new_crtc_state;
1394 struct drm_connector_state *old_state;
1396 if (!new_state->crtc)
1399 old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
1400 new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
1402 if (old_state->tv.mode != new_state->tv.mode ||
1403 old_state->tv.margins.left != new_state->tv.margins.left ||
1404 old_state->tv.margins.right != new_state->tv.margins.right ||
1405 old_state->tv.margins.top != new_state->tv.margins.top ||
1406 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1407 /* Force a modeset. */
1409 new_crtc_state->connectors_changed = true;
1415 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1416 .detect_ctx = intel_tv_detect,
1417 .mode_valid = intel_tv_mode_valid,
1418 .get_modes = intel_tv_get_modes,
1419 .atomic_check = intel_tv_atomic_check,
1422 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1423 .destroy = intel_encoder_destroy,
1427 intel_tv_init(struct drm_i915_private *dev_priv)
1429 struct drm_device *dev = &dev_priv->drm;
1430 struct drm_connector *connector;
1431 struct intel_tv *intel_tv;
1432 struct intel_encoder *intel_encoder;
1433 struct intel_connector *intel_connector;
1434 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1435 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
1436 int i, initial_mode = 0;
1437 struct drm_connector_state *state;
1439 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1442 if (!intel_bios_is_tv_present(dev_priv)) {
1443 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1448 * Sanity check the TV output by checking to see if the
1449 * DAC register holds a value
1451 save_tv_dac = I915_READ(TV_DAC);
1453 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1454 tv_dac_on = I915_READ(TV_DAC);
1456 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1457 tv_dac_off = I915_READ(TV_DAC);
1459 I915_WRITE(TV_DAC, save_tv_dac);
1462 * If the register does not hold the state change enable
1463 * bit, (either as a 0 or a 1), assume it doesn't really
1466 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1467 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1470 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
1475 intel_connector = intel_connector_alloc();
1476 if (!intel_connector) {
1481 intel_encoder = &intel_tv->base;
1482 connector = &intel_connector->base;
1483 state = connector->state;
1486 * The documentation, for the older chipsets at least, recommend
1487 * using a polling method rather than hotplug detection for TVs.
1488 * This is because in order to perform the hotplug detection, the PLLs
1489 * for the TV must be kept alive increasing power drain and starving
1490 * bandwidth from other encoders. Notably for instance, it causes
1491 * pipe underruns on Crestline when this encoder is supposedly idle.
1493 * More recent chipsets favour HDMI rather than integrated S-Video.
1495 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1497 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1498 DRM_MODE_CONNECTOR_SVIDEO);
1500 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1501 DRM_MODE_ENCODER_TVDAC, "TV");
1503 intel_encoder->compute_config = intel_tv_compute_config;
1504 intel_encoder->get_config = intel_tv_get_config;
1505 intel_encoder->pre_enable = intel_tv_pre_enable;
1506 intel_encoder->enable = intel_enable_tv;
1507 intel_encoder->disable = intel_disable_tv;
1508 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1509 intel_connector->get_hw_state = intel_connector_get_hw_state;
1511 intel_connector_attach_encoder(intel_connector, intel_encoder);
1513 intel_encoder->type = INTEL_OUTPUT_TVOUT;
1514 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
1515 intel_encoder->port = PORT_NONE;
1516 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1517 intel_encoder->cloneable = 0;
1518 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
1519 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1521 /* BIOS margin values */
1522 state->tv.margins.left = 54;
1523 state->tv.margins.top = 36;
1524 state->tv.margins.right = 46;
1525 state->tv.margins.bottom = 37;
1527 state->tv.mode = initial_mode;
1529 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1530 connector->interlace_allowed = false;
1531 connector->doublescan_allowed = false;
1533 /* Create TV properties then attach current values */
1534 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
1535 tv_format_names[i] = tv_modes[i].name;
1536 drm_mode_create_tv_properties(dev,
1537 ARRAY_SIZE(tv_modes),
1540 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
1542 drm_object_attach_property(&connector->base,
1543 dev->mode_config.tv_left_margin_property,
1544 state->tv.margins.left);
1545 drm_object_attach_property(&connector->base,
1546 dev->mode_config.tv_top_margin_property,
1547 state->tv.margins.top);
1548 drm_object_attach_property(&connector->base,
1549 dev->mode_config.tv_right_margin_property,
1550 state->tv.margins.right);
1551 drm_object_attach_property(&connector->base,
1552 dev->mode_config.tv_bottom_margin_property,
1553 state->tv.margins.bottom);