2 * Copyright © 2006-2008 Intel Corporation
3 * Jesse Barnes <jesse.barnes@intel.com>
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.
25 * Eric Anholt <eric@anholt.net>
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_device *dev = encoder->base.dev;
802 struct drm_i915_private *dev_priv = to_i915(dev);
803 u32 tmp = I915_READ(TV_CTL);
805 if (!(tmp & TV_ENC_ENABLE))
808 *pipe = PORT_TO_PIPE(tmp);
814 intel_enable_tv(struct intel_encoder *encoder,
815 const struct intel_crtc_state *pipe_config,
816 const struct drm_connector_state *conn_state)
818 struct drm_device *dev = encoder->base.dev;
819 struct drm_i915_private *dev_priv = to_i915(dev);
821 /* Prevents vblank waits from timing out in intel_tv_detect_type() */
822 intel_wait_for_vblank(dev_priv,
823 to_intel_crtc(pipe_config->base.crtc)->pipe);
825 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
829 intel_disable_tv(struct intel_encoder *encoder,
830 const struct intel_crtc_state *old_crtc_state,
831 const struct drm_connector_state *old_conn_state)
833 struct drm_device *dev = encoder->base.dev;
834 struct drm_i915_private *dev_priv = to_i915(dev);
836 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
839 static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
841 int format = conn_state->tv.mode;
843 return &tv_modes[format];
846 static enum drm_mode_status
847 intel_tv_mode_valid(struct drm_connector *connector,
848 struct drm_display_mode *mode)
850 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
851 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
853 if (mode->clock > max_dotclk)
854 return MODE_CLOCK_HIGH;
856 /* Ensure TV refresh is close to desired refresh */
857 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
861 return MODE_CLOCK_RANGE;
866 intel_tv_get_config(struct intel_encoder *encoder,
867 struct intel_crtc_state *pipe_config)
869 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
871 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
875 intel_tv_compute_config(struct intel_encoder *encoder,
876 struct intel_crtc_state *pipe_config,
877 struct drm_connector_state *conn_state)
879 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
884 pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
885 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
886 pipe_config->pipe_bpp = 8*3;
888 /* TV has it's own notion of sync and other mode flags, so clear them. */
889 pipe_config->base.adjusted_mode.flags = 0;
892 * FIXME: We don't check whether the input mode is actually what we want
893 * or whether userspace is doing something stupid.
900 set_tv_mode_timings(struct drm_i915_private *dev_priv,
901 const struct tv_mode *tv_mode,
904 u32 hctl1, hctl2, hctl3;
905 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
907 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
908 (tv_mode->htotal << TV_HTOTAL_SHIFT);
910 hctl2 = (tv_mode->hburst_start << 16) |
911 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
914 hctl2 |= TV_BURST_ENA;
916 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
917 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
919 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
920 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
921 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
923 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
924 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
925 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
927 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
928 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
929 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
931 if (tv_mode->veq_ena)
932 vctl3 |= TV_EQUAL_ENA;
934 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
935 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
937 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
938 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
940 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
941 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
943 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
944 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
946 I915_WRITE(TV_H_CTL_1, hctl1);
947 I915_WRITE(TV_H_CTL_2, hctl2);
948 I915_WRITE(TV_H_CTL_3, hctl3);
949 I915_WRITE(TV_V_CTL_1, vctl1);
950 I915_WRITE(TV_V_CTL_2, vctl2);
951 I915_WRITE(TV_V_CTL_3, vctl3);
952 I915_WRITE(TV_V_CTL_4, vctl4);
953 I915_WRITE(TV_V_CTL_5, vctl5);
954 I915_WRITE(TV_V_CTL_6, vctl6);
955 I915_WRITE(TV_V_CTL_7, vctl7);
958 static void set_color_conversion(struct drm_i915_private *dev_priv,
959 const struct color_conversion *color_conversion)
961 if (!color_conversion)
964 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
965 color_conversion->gy);
966 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
967 color_conversion->ay);
968 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
969 color_conversion->gu);
970 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
971 color_conversion->au);
972 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
973 color_conversion->gv);
974 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
975 color_conversion->av);
978 static void intel_tv_pre_enable(struct intel_encoder *encoder,
979 const struct intel_crtc_state *pipe_config,
980 const struct drm_connector_state *conn_state)
982 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
983 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
984 struct intel_tv *intel_tv = enc_to_tv(encoder);
985 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
987 u32 scctl1, scctl2, scctl3;
989 const struct video_levels *video_levels;
990 const struct color_conversion *color_conversion;
992 int xpos = 0x0, ypos = 0x0;
993 unsigned int xsize, ysize;
996 return; /* can't happen (mode_prepare prevents this) */
998 tv_ctl = I915_READ(TV_CTL);
999 tv_ctl &= TV_CTL_SAVE;
1001 switch (intel_tv->type) {
1003 case DRM_MODE_CONNECTOR_Unknown:
1004 case DRM_MODE_CONNECTOR_Composite:
1005 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1006 video_levels = tv_mode->composite_levels;
1007 color_conversion = tv_mode->composite_color;
1008 burst_ena = tv_mode->burst_ena;
1010 case DRM_MODE_CONNECTOR_Component:
1011 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1012 video_levels = &component_levels;
1013 if (tv_mode->burst_ena)
1014 color_conversion = &sdtv_csc_yprpb;
1016 color_conversion = &hdtv_csc_yprpb;
1019 case DRM_MODE_CONNECTOR_SVIDEO:
1020 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1021 video_levels = tv_mode->svideo_levels;
1022 color_conversion = tv_mode->svideo_color;
1023 burst_ena = tv_mode->burst_ena;
1027 if (intel_crtc->pipe == 1)
1028 tv_ctl |= TV_ENC_PIPEB_SELECT;
1029 tv_ctl |= tv_mode->oversample;
1031 if (tv_mode->progressive)
1032 tv_ctl |= TV_PROGRESSIVE;
1033 if (tv_mode->trilevel_sync)
1034 tv_ctl |= TV_TRILEVEL_SYNC;
1035 if (tv_mode->pal_burst)
1036 tv_ctl |= TV_PAL_BURST;
1039 if (tv_mode->dda1_inc)
1040 scctl1 |= TV_SC_DDA1_EN;
1041 if (tv_mode->dda2_inc)
1042 scctl1 |= TV_SC_DDA2_EN;
1043 if (tv_mode->dda3_inc)
1044 scctl1 |= TV_SC_DDA3_EN;
1045 scctl1 |= tv_mode->sc_reset;
1047 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1048 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1050 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1051 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1053 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1054 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1056 /* Enable two fixes for the chips that need them. */
1057 if (IS_I915GM(dev_priv))
1058 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1060 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1062 I915_WRITE(TV_SC_CTL_1, scctl1);
1063 I915_WRITE(TV_SC_CTL_2, scctl2);
1064 I915_WRITE(TV_SC_CTL_3, scctl3);
1066 set_color_conversion(dev_priv, color_conversion);
1068 if (INTEL_GEN(dev_priv) >= 4)
1069 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1071 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1074 I915_WRITE(TV_CLR_LEVEL,
1075 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1076 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1078 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
1080 /* Filter ctl must be set before TV_WIN_SIZE */
1081 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1082 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1083 if (tv_mode->progressive)
1084 ysize = tv_mode->nbr_end + 1;
1086 ysize = 2*tv_mode->nbr_end + 1;
1088 xpos += conn_state->tv.margins.left;
1089 ypos += conn_state->tv.margins.top;
1090 xsize -= (conn_state->tv.margins.left +
1091 conn_state->tv.margins.right);
1092 ysize -= (conn_state->tv.margins.top +
1093 conn_state->tv.margins.bottom);
1094 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1095 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1098 for (i = 0; i < 60; i++)
1099 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
1100 for (i = 0; i < 60; i++)
1101 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
1102 for (i = 0; i < 43; i++)
1103 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
1104 for (i = 0; i < 43; i++)
1105 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
1106 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1107 I915_WRITE(TV_CTL, tv_ctl);
1110 static const struct drm_display_mode reported_modes[] = {
1112 .name = "NTSC 480i",
1115 .hsync_start = 1368,
1120 .vsync_start = 1027,
1123 .type = DRM_MODE_TYPE_DRIVER,
1128 intel_tv_detect_type(struct intel_tv *intel_tv,
1129 struct drm_connector *connector)
1131 struct drm_crtc *crtc = connector->state->crtc;
1132 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1133 struct drm_device *dev = connector->dev;
1134 struct drm_i915_private *dev_priv = to_i915(dev);
1135 u32 tv_ctl, save_tv_ctl;
1136 u32 tv_dac, save_tv_dac;
1139 /* Disable TV interrupts around load detect or we'll recurse */
1140 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1141 spin_lock_irq(&dev_priv->irq_lock);
1142 i915_disable_pipestat(dev_priv, 0,
1143 PIPE_HOTPLUG_INTERRUPT_STATUS |
1144 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1145 spin_unlock_irq(&dev_priv->irq_lock);
1148 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1149 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1151 /* Poll for TV detection */
1152 tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
1153 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1154 if (intel_crtc->pipe == 1)
1155 tv_ctl |= TV_ENC_PIPEB_SELECT;
1157 tv_ctl &= ~TV_ENC_PIPEB_SELECT;
1159 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1160 tv_dac |= (TVDAC_STATE_CHG_EN |
1171 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1172 * the TV is misdetected. This is hardware requirement.
1174 if (IS_GM45(dev_priv))
1175 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1176 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1178 I915_WRITE(TV_CTL, tv_ctl);
1179 I915_WRITE(TV_DAC, tv_dac);
1180 POSTING_READ(TV_DAC);
1182 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1185 tv_dac = I915_READ(TV_DAC);
1186 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1193 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1194 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1195 type = DRM_MODE_CONNECTOR_Composite;
1196 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1197 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1198 type = DRM_MODE_CONNECTOR_SVIDEO;
1199 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1200 DRM_DEBUG_KMS("Detected Component TV connection\n");
1201 type = DRM_MODE_CONNECTOR_Component;
1203 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1207 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1208 I915_WRITE(TV_CTL, save_tv_ctl);
1209 POSTING_READ(TV_CTL);
1211 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
1212 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1214 /* Restore interrupt config */
1215 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1216 spin_lock_irq(&dev_priv->irq_lock);
1217 i915_enable_pipestat(dev_priv, 0,
1218 PIPE_HOTPLUG_INTERRUPT_STATUS |
1219 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1220 spin_unlock_irq(&dev_priv->irq_lock);
1227 * Here we set accurate tv format according to connector type
1228 * i.e Component TV should not be assigned by NTSC or PAL
1230 static void intel_tv_find_better_format(struct drm_connector *connector)
1232 struct intel_tv *intel_tv = intel_attached_tv(connector);
1233 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1236 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1237 tv_mode->component_only)
1241 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1242 tv_mode = tv_modes + i;
1244 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1245 tv_mode->component_only)
1249 connector->state->tv.mode = i;
1253 intel_tv_detect(struct drm_connector *connector,
1254 struct drm_modeset_acquire_ctx *ctx,
1257 struct drm_display_mode mode;
1258 struct intel_tv *intel_tv = intel_attached_tv(connector);
1259 enum drm_connector_status status;
1262 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
1263 connector->base.id, connector->name,
1266 mode = reported_modes[0];
1269 struct intel_load_detect_pipe tmp;
1272 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1277 type = intel_tv_detect_type(intel_tv, connector);
1278 intel_release_load_detect_pipe(connector, &tmp, ctx);
1280 connector_status_disconnected :
1281 connector_status_connected;
1283 status = connector_status_unknown;
1285 if (status == connector_status_connected) {
1286 intel_tv->type = type;
1287 intel_tv_find_better_format(connector);
1292 return connector->status;
1295 static const struct input_res {
1298 } input_res_table[] = {
1299 {"640x480", 640, 480},
1300 {"800x600", 800, 600},
1301 {"1024x768", 1024, 768},
1302 {"1280x1024", 1280, 1024},
1303 {"848x480", 848, 480},
1304 {"1280x720", 1280, 720},
1305 {"1920x1080", 1920, 1080},
1309 * Chose preferred mode according to line number of TV format
1312 intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
1313 struct drm_display_mode *mode_ptr)
1315 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1316 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1317 else if (tv_mode->nbr_end > 480) {
1318 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1319 if (mode_ptr->vdisplay == 720)
1320 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1321 } else if (mode_ptr->vdisplay == 1080)
1322 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1327 intel_tv_get_modes(struct drm_connector *connector)
1329 struct drm_display_mode *mode_ptr;
1330 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1334 for (j = 0; j < ARRAY_SIZE(input_res_table);
1336 const struct input_res *input = &input_res_table[j];
1337 unsigned int hactive_s = input->w;
1338 unsigned int vactive_s = input->h;
1340 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1343 if (input->w > 1024 && (!tv_mode->progressive
1344 && !tv_mode->component_only))
1347 mode_ptr = drm_mode_create(connector->dev);
1350 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1351 mode_ptr->name[DRM_DISPLAY_MODE_LEN - 1] = '\0';
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);
1382 intel_tv_destroy(struct drm_connector *connector)
1384 drm_connector_cleanup(connector);
1388 static const struct drm_connector_funcs intel_tv_connector_funcs = {
1389 .late_register = intel_connector_register,
1390 .early_unregister = intel_connector_unregister,
1391 .destroy = intel_tv_destroy,
1392 .fill_modes = drm_helper_probe_single_connector_modes,
1393 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1394 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1397 static int intel_tv_atomic_check(struct drm_connector *connector,
1398 struct drm_connector_state *new_state)
1400 struct drm_crtc_state *new_crtc_state;
1401 struct drm_connector_state *old_state;
1403 if (!new_state->crtc)
1406 old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
1407 new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
1409 if (old_state->tv.mode != new_state->tv.mode ||
1410 old_state->tv.margins.left != new_state->tv.margins.left ||
1411 old_state->tv.margins.right != new_state->tv.margins.right ||
1412 old_state->tv.margins.top != new_state->tv.margins.top ||
1413 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1414 /* Force a modeset. */
1416 new_crtc_state->connectors_changed = true;
1422 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1423 .detect_ctx = intel_tv_detect,
1424 .mode_valid = intel_tv_mode_valid,
1425 .get_modes = intel_tv_get_modes,
1426 .atomic_check = intel_tv_atomic_check,
1429 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1430 .destroy = intel_encoder_destroy,
1434 intel_tv_init(struct drm_i915_private *dev_priv)
1436 struct drm_device *dev = &dev_priv->drm;
1437 struct drm_connector *connector;
1438 struct intel_tv *intel_tv;
1439 struct intel_encoder *intel_encoder;
1440 struct intel_connector *intel_connector;
1441 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1442 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
1443 int i, initial_mode = 0;
1444 struct drm_connector_state *state;
1446 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1449 if (!intel_bios_is_tv_present(dev_priv)) {
1450 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1455 * Sanity check the TV output by checking to see if the
1456 * DAC register holds a value
1458 save_tv_dac = I915_READ(TV_DAC);
1460 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1461 tv_dac_on = I915_READ(TV_DAC);
1463 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1464 tv_dac_off = I915_READ(TV_DAC);
1466 I915_WRITE(TV_DAC, save_tv_dac);
1469 * If the register does not hold the state change enable
1470 * bit, (either as a 0 or a 1), assume it doesn't really
1473 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1474 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1477 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
1482 intel_connector = intel_connector_alloc();
1483 if (!intel_connector) {
1488 intel_encoder = &intel_tv->base;
1489 connector = &intel_connector->base;
1490 state = connector->state;
1493 * The documentation, for the older chipsets at least, recommend
1494 * using a polling method rather than hotplug detection for TVs.
1495 * This is because in order to perform the hotplug detection, the PLLs
1496 * for the TV must be kept alive increasing power drain and starving
1497 * bandwidth from other encoders. Notably for instance, it causes
1498 * pipe underruns on Crestline when this encoder is supposedly idle.
1500 * More recent chipsets favour HDMI rather than integrated S-Video.
1502 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1504 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1505 DRM_MODE_CONNECTOR_SVIDEO);
1507 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1508 DRM_MODE_ENCODER_TVDAC, "TV");
1510 intel_encoder->compute_config = intel_tv_compute_config;
1511 intel_encoder->get_config = intel_tv_get_config;
1512 intel_encoder->pre_enable = intel_tv_pre_enable;
1513 intel_encoder->enable = intel_enable_tv;
1514 intel_encoder->disable = intel_disable_tv;
1515 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1516 intel_connector->get_hw_state = intel_connector_get_hw_state;
1518 intel_connector_attach_encoder(intel_connector, intel_encoder);
1520 intel_encoder->type = INTEL_OUTPUT_TVOUT;
1521 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
1522 intel_encoder->port = PORT_NONE;
1523 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1524 intel_encoder->cloneable = 0;
1525 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
1526 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1528 /* BIOS margin values */
1529 state->tv.margins.left = 54;
1530 state->tv.margins.top = 36;
1531 state->tv.margins.right = 46;
1532 state->tv.margins.bottom = 37;
1534 state->tv.mode = initial_mode;
1536 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1537 connector->interlace_allowed = false;
1538 connector->doublescan_allowed = false;
1540 /* Create TV properties then attach current values */
1541 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
1542 tv_format_names[i] = tv_modes[i].name;
1543 drm_mode_create_tv_properties(dev,
1544 ARRAY_SIZE(tv_modes),
1547 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
1549 drm_object_attach_property(&connector->base,
1550 dev->mode_config.tv_left_margin_property,
1551 state->tv.margins.left);
1552 drm_object_attach_property(&connector->base,
1553 dev->mode_config.tv_top_margin_property,
1554 state->tv.margins.top);
1555 drm_object_attach_property(&connector->base,
1556 dev->mode_config.tv_right_margin_property,
1557 state->tv.margins.right);
1558 drm_object_attach_property(&connector->base,
1559 dev->mode_config.tv_bottom_margin_property,
1560 state->tv.margins.bottom);