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>
27 * $FreeBSD: src/sys/dev/drm2/i915/intel_tv.c,v 1.1 2012/05/22 11:07:44 kib Exp $
31 * Integrated TV-out support for the 915GM and 945GM.
36 #include <drm/drm_crtc.h>
37 #include <drm/drm_edid.h>
38 #include "intel_drv.h"
39 #include <drm/i915_drm.h>
43 TV_MARGIN_LEFT, TV_MARGIN_TOP,
44 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
47 /** Private structure for the integrated TV support */
49 struct intel_encoder base;
52 const char *tv_format;
64 u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
72 u32 save_TV_CLR_KNOBS;
73 u32 save_TV_CLR_LEVEL;
76 u32 save_TV_FILTER_CTL_1;
77 u32 save_TV_FILTER_CTL_2;
78 u32 save_TV_FILTER_CTL_3;
80 u32 save_TV_H_LUMA[60];
81 u32 save_TV_H_CHROMA[60];
82 u32 save_TV_V_LUMA[43];
83 u32 save_TV_V_CHROMA[43];
90 int blank, black, burst;
93 struct color_conversion {
99 static const u32 filter_table[] = {
100 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
101 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
102 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
103 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
104 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
105 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
106 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
107 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
108 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
109 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
110 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
111 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
112 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
113 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
114 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
115 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
116 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
117 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
118 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
119 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
120 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
121 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
122 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
123 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
124 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
125 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
126 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
127 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
128 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
129 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
130 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
131 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
132 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
133 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
134 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
135 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
136 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
137 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
138 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
139 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
140 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
141 0x2D002CC0, 0x30003640, 0x2D0036C0,
142 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
143 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
144 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
145 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
146 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
147 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
148 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
149 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
150 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
151 0x28003100, 0x28002F00, 0x00003100,
155 * Color conversion values have 3 separate fixed point formats:
157 * 10 bit fields (ay, au)
158 * 1.9 fixed point (b.bbbbbbbbb)
159 * 11 bit fields (ry, by, ru, gu, gv)
160 * exp.mantissa (ee.mmmmmmmmm)
161 * ee = 00 = 10^-1 (0.mmmmmmmmm)
162 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
163 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
164 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
165 * 12 bit fields (gy, rv, bu)
166 * exp.mantissa (eee.mmmmmmmmm)
167 * eee = 000 = 10^-1 (0.mmmmmmmmm)
168 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
169 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
170 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
171 * eee = 100 = reserved
172 * eee = 101 = reserved
173 * eee = 110 = reserved
174 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
176 * Saturation and contrast are 8 bits, with their own representation:
177 * 8 bit field (saturation, contrast)
178 * exp.mantissa (ee.mmmmmm)
179 * ee = 00 = 10^-1 (0.mmmmmm)
180 * ee = 01 = 10^0 (m.mmmmm)
181 * ee = 10 = 10^1 (mm.mmmm)
182 * ee = 11 = 10^2 (mmm.mmm)
184 * Simple conversion function:
187 * float_to_csc_11(float f)
200 * for (exp = 0; exp < 3 && f < 0.5; exp++)
202 * mant = (f * (1 << 9) + 0.5);
203 * if (mant >= (1 << 9))
204 * mant = (1 << 9) - 1;
206 * ret = (exp << 9) | mant;
212 * Behold, magic numbers! If we plant them they might grow a big
213 * s-video cable to the sky... or something.
215 * Pre-converted to appropriate hex value.
219 * PAL & NTSC values for composite & s-video connections
221 static const struct color_conversion ntsc_m_csc_composite = {
222 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
223 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
224 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
227 static const struct video_levels ntsc_m_levels_composite = {
228 .blank = 225, .black = 267, .burst = 113,
231 static const struct color_conversion ntsc_m_csc_svideo = {
232 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
233 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
234 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
237 static const struct video_levels ntsc_m_levels_svideo = {
238 .blank = 266, .black = 316, .burst = 133,
241 static const struct color_conversion ntsc_j_csc_composite = {
242 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
243 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
244 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
247 static const struct video_levels ntsc_j_levels_composite = {
248 .blank = 225, .black = 225, .burst = 113,
251 static const struct color_conversion ntsc_j_csc_svideo = {
252 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
253 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
254 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
257 static const struct video_levels ntsc_j_levels_svideo = {
258 .blank = 266, .black = 266, .burst = 133,
261 static const struct color_conversion pal_csc_composite = {
262 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
263 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
264 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
267 static const struct video_levels pal_levels_composite = {
268 .blank = 237, .black = 237, .burst = 118,
271 static const struct color_conversion pal_csc_svideo = {
272 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
273 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
274 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
277 static const struct video_levels pal_levels_svideo = {
278 .blank = 280, .black = 280, .burst = 139,
281 static const struct color_conversion pal_m_csc_composite = {
282 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
283 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
284 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
287 static const struct video_levels pal_m_levels_composite = {
288 .blank = 225, .black = 267, .burst = 113,
291 static const struct color_conversion pal_m_csc_svideo = {
292 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
293 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
294 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
297 static const struct video_levels pal_m_levels_svideo = {
298 .blank = 266, .black = 316, .burst = 133,
301 static const struct color_conversion pal_n_csc_composite = {
302 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
303 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
304 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
307 static const struct video_levels pal_n_levels_composite = {
308 .blank = 225, .black = 267, .burst = 118,
311 static const struct color_conversion pal_n_csc_svideo = {
312 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
313 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
314 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
317 static const struct video_levels pal_n_levels_svideo = {
318 .blank = 266, .black = 316, .burst = 139,
322 * Component connections
324 static const struct color_conversion sdtv_csc_yprpb = {
325 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
326 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
327 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
330 static const struct color_conversion sdtv_csc_rgb = {
331 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
332 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
333 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
336 static const struct color_conversion hdtv_csc_yprpb = {
337 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
338 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
339 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
342 static const struct color_conversion hdtv_csc_rgb = {
343 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
344 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
345 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
348 static const struct video_levels component_levels = {
349 .blank = 279, .black = 279, .burst = 0,
356 int refresh; /* in millihertz (for precision) */
358 int hsync_end, hblank_start, hblank_end, htotal;
359 bool progressive, trilevel_sync, component_only;
360 int vsync_start_f1, vsync_start_f2, vsync_len;
362 int veq_start_f1, veq_start_f2, veq_len;
363 int vi_end_f1, vi_end_f2, nbr_end;
365 int hburst_start, hburst_len;
366 int vburst_start_f1, vburst_end_f1;
367 int vburst_start_f2, vburst_end_f2;
368 int vburst_start_f3, vburst_end_f3;
369 int vburst_start_f4, vburst_end_f4;
371 * subcarrier programming
373 int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
379 const struct video_levels *composite_levels, *svideo_levels;
380 const struct color_conversion *composite_color, *svideo_color;
381 const u32 *filter_table;
389 * I think this works as follows:
391 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
393 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
396 * dda1_ideal = subcarrier/pixel * 4096
397 * dda1_inc = floor (dda1_ideal)
398 * dda2 = dda1_ideal - dda1_inc
400 * then pick a ratio for dda2 that gives the closest approximation. If
401 * you can't get close enough, you can play with dda3 as well. This
402 * seems likely to happen when dda2 is small as the jumps would be larger
406 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
408 * The constants below were all computed using a 107.520MHz clock
412 * Register programming values for TV modes.
414 * These values account for -1s required.
417 static const struct tv_mode tv_modes[] = {
422 .oversample = TV_OVERSAMPLE_8X,
424 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
426 .hsync_end = 64, .hblank_end = 124,
427 .hblank_start = 836, .htotal = 857,
429 .progressive = false, .trilevel_sync = false,
431 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
434 .veq_ena = true, .veq_start_f1 = 0,
435 .veq_start_f2 = 1, .veq_len = 18,
437 .vi_end_f1 = 20, .vi_end_f2 = 21,
441 .hburst_start = 72, .hburst_len = 34,
442 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
443 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
444 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
445 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
447 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
449 .dda2_inc = 20800, .dda2_size = 27456,
450 .dda3_inc = 0, .dda3_size = 0,
451 .sc_reset = TV_SC_RESET_EVERY_4,
454 .composite_levels = &ntsc_m_levels_composite,
455 .composite_color = &ntsc_m_csc_composite,
456 .svideo_levels = &ntsc_m_levels_svideo,
457 .svideo_color = &ntsc_m_csc_svideo,
459 .filter_table = filter_table,
465 .oversample = TV_OVERSAMPLE_8X,
467 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
468 .hsync_end = 64, .hblank_end = 124,
469 .hblank_start = 836, .htotal = 857,
471 .progressive = false, .trilevel_sync = false,
473 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
476 .veq_ena = true, .veq_start_f1 = 0,
477 .veq_start_f2 = 1, .veq_len = 18,
479 .vi_end_f1 = 20, .vi_end_f2 = 21,
483 .hburst_start = 72, .hburst_len = 34,
484 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
485 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
486 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
487 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
489 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
491 .dda2_inc = 4093, .dda2_size = 27456,
492 .dda3_inc = 310, .dda3_size = 525,
493 .sc_reset = TV_SC_RESET_NEVER,
496 .composite_levels = &ntsc_m_levels_composite,
497 .composite_color = &ntsc_m_csc_composite,
498 .svideo_levels = &ntsc_m_levels_svideo,
499 .svideo_color = &ntsc_m_csc_svideo,
501 .filter_table = filter_table,
507 .oversample = TV_OVERSAMPLE_8X,
510 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
511 .hsync_end = 64, .hblank_end = 124,
512 .hblank_start = 836, .htotal = 857,
514 .progressive = false, .trilevel_sync = false,
516 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
519 .veq_ena = true, .veq_start_f1 = 0,
520 .veq_start_f2 = 1, .veq_len = 18,
522 .vi_end_f1 = 20, .vi_end_f2 = 21,
526 .hburst_start = 72, .hburst_len = 34,
527 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
528 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
529 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
530 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
532 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
534 .dda2_inc = 20800, .dda2_size = 27456,
535 .dda3_inc = 0, .dda3_size = 0,
536 .sc_reset = TV_SC_RESET_EVERY_4,
539 .composite_levels = &ntsc_j_levels_composite,
540 .composite_color = &ntsc_j_csc_composite,
541 .svideo_levels = &ntsc_j_levels_svideo,
542 .svideo_color = &ntsc_j_csc_svideo,
544 .filter_table = filter_table,
550 .oversample = TV_OVERSAMPLE_8X,
553 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
554 .hsync_end = 64, .hblank_end = 124,
555 .hblank_start = 836, .htotal = 857,
557 .progressive = false, .trilevel_sync = false,
559 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
562 .veq_ena = true, .veq_start_f1 = 0,
563 .veq_start_f2 = 1, .veq_len = 18,
565 .vi_end_f1 = 20, .vi_end_f2 = 21,
569 .hburst_start = 72, .hburst_len = 34,
570 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
571 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
572 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
573 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
575 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
577 .dda2_inc = 16704, .dda2_size = 27456,
578 .dda3_inc = 0, .dda3_size = 0,
579 .sc_reset = TV_SC_RESET_EVERY_8,
582 .composite_levels = &pal_m_levels_composite,
583 .composite_color = &pal_m_csc_composite,
584 .svideo_levels = &pal_m_levels_svideo,
585 .svideo_color = &pal_m_csc_svideo,
587 .filter_table = filter_table,
590 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
594 .oversample = TV_OVERSAMPLE_8X,
597 .hsync_end = 64, .hblank_end = 128,
598 .hblank_start = 844, .htotal = 863,
600 .progressive = false, .trilevel_sync = false,
603 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
606 .veq_ena = true, .veq_start_f1 = 0,
607 .veq_start_f2 = 1, .veq_len = 18,
609 .vi_end_f1 = 24, .vi_end_f2 = 25,
613 .hburst_start = 73, .hburst_len = 34,
614 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
615 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
616 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
617 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
620 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
622 .dda2_inc = 23578, .dda2_size = 27648,
623 .dda3_inc = 134, .dda3_size = 625,
624 .sc_reset = TV_SC_RESET_EVERY_8,
627 .composite_levels = &pal_n_levels_composite,
628 .composite_color = &pal_n_csc_composite,
629 .svideo_levels = &pal_n_levels_svideo,
630 .svideo_color = &pal_n_csc_svideo,
632 .filter_table = filter_table,
635 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
639 .oversample = TV_OVERSAMPLE_8X,
642 .hsync_end = 64, .hblank_end = 142,
643 .hblank_start = 844, .htotal = 863,
645 .progressive = false, .trilevel_sync = false,
647 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
650 .veq_ena = true, .veq_start_f1 = 0,
651 .veq_start_f2 = 1, .veq_len = 15,
653 .vi_end_f1 = 24, .vi_end_f2 = 25,
657 .hburst_start = 73, .hburst_len = 32,
658 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
659 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
660 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
661 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
663 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
665 .dda2_inc = 4122, .dda2_size = 27648,
666 .dda3_inc = 67, .dda3_size = 625,
667 .sc_reset = TV_SC_RESET_EVERY_8,
670 .composite_levels = &pal_levels_composite,
671 .composite_color = &pal_csc_composite,
672 .svideo_levels = &pal_levels_svideo,
673 .svideo_color = &pal_csc_svideo,
675 .filter_table = filter_table,
681 .oversample = TV_OVERSAMPLE_2X,
684 .hsync_end = 80, .hblank_end = 300,
685 .hblank_start = 1580, .htotal = 1649,
687 .progressive = true, .trilevel_sync = true,
689 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
694 .vi_end_f1 = 29, .vi_end_f2 = 29,
699 .filter_table = filter_table,
705 .oversample = TV_OVERSAMPLE_2X,
708 .hsync_end = 80, .hblank_end = 300,
709 .hblank_start = 1580, .htotal = 1979,
711 .progressive = true, .trilevel_sync = true,
713 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
718 .vi_end_f1 = 29, .vi_end_f2 = 29,
723 .filter_table = filter_table,
727 .name = "1080i@50Hz",
730 .oversample = TV_OVERSAMPLE_2X,
733 .hsync_end = 88, .hblank_end = 235,
734 .hblank_start = 2155, .htotal = 2639,
736 .progressive = false, .trilevel_sync = true,
738 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
741 .veq_ena = true, .veq_start_f1 = 4,
742 .veq_start_f2 = 4, .veq_len = 10,
745 .vi_end_f1 = 21, .vi_end_f2 = 22,
750 .filter_table = filter_table,
753 .name = "1080i@60Hz",
756 .oversample = TV_OVERSAMPLE_2X,
759 .hsync_end = 88, .hblank_end = 235,
760 .hblank_start = 2155, .htotal = 2199,
762 .progressive = false, .trilevel_sync = true,
764 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
767 .veq_ena = true, .veq_start_f1 = 4,
768 .veq_start_f2 = 4, .veq_len = 10,
771 .vi_end_f1 = 21, .vi_end_f2 = 22,
776 .filter_table = filter_table,
780 static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
782 return container_of(encoder, struct intel_tv, base.base);
785 static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
787 return container_of(intel_attached_encoder(connector),
793 intel_tv_dpms(struct drm_encoder *encoder, int mode)
795 struct drm_device *dev = encoder->dev;
796 struct drm_i915_private *dev_priv = dev->dev_private;
799 case DRM_MODE_DPMS_ON:
800 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
802 case DRM_MODE_DPMS_STANDBY:
803 case DRM_MODE_DPMS_SUSPEND:
804 case DRM_MODE_DPMS_OFF:
805 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
810 static const struct tv_mode *
811 intel_tv_mode_lookup(const char *tv_format)
815 for (i = 0; i < sizeof(tv_modes) / sizeof(tv_modes[0]); i++) {
816 const struct tv_mode *tv_mode = &tv_modes[i];
818 if (!strcmp(tv_format, tv_mode->name))
824 static const struct tv_mode *
825 intel_tv_mode_find(struct intel_tv *intel_tv)
827 return intel_tv_mode_lookup(intel_tv->tv_format);
830 static enum drm_mode_status
831 intel_tv_mode_valid(struct drm_connector *connector,
832 struct drm_display_mode *mode)
834 struct intel_tv *intel_tv = intel_attached_tv(connector);
835 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
837 /* Ensure TV refresh is close to desired refresh */
838 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
842 return MODE_CLOCK_RANGE;
847 intel_tv_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode,
848 struct drm_display_mode *adjusted_mode)
850 struct drm_device *dev = encoder->dev;
851 struct drm_mode_config *drm_config = &dev->mode_config;
852 struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
853 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
854 struct drm_encoder *other_encoder;
859 /* FIXME: lock encoder list */
860 list_for_each_entry(other_encoder, &drm_config->encoder_list, head) {
861 if (other_encoder != encoder &&
862 other_encoder->crtc == encoder->crtc)
866 adjusted_mode->clock = tv_mode->clock;
871 intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
872 struct drm_display_mode *adjusted_mode)
874 struct drm_device *dev = encoder->dev;
875 struct drm_i915_private *dev_priv = dev->dev_private;
876 struct drm_crtc *crtc = encoder->crtc;
877 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
878 struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
879 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
881 u32 hctl1, hctl2, hctl3;
882 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
883 u32 scctl1, scctl2, scctl3;
885 const struct video_levels *video_levels;
886 const struct color_conversion *color_conversion;
888 int pipe = intel_crtc->pipe;
891 return; /* can't happen (mode_prepare prevents this) */
893 tv_ctl = I915_READ(TV_CTL);
894 tv_ctl &= TV_CTL_SAVE;
896 switch (intel_tv->type) {
898 case DRM_MODE_CONNECTOR_Unknown:
899 case DRM_MODE_CONNECTOR_Composite:
900 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
901 video_levels = tv_mode->composite_levels;
902 color_conversion = tv_mode->composite_color;
903 burst_ena = tv_mode->burst_ena;
905 case DRM_MODE_CONNECTOR_Component:
906 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
907 video_levels = &component_levels;
908 if (tv_mode->burst_ena)
909 color_conversion = &sdtv_csc_yprpb;
911 color_conversion = &hdtv_csc_yprpb;
914 case DRM_MODE_CONNECTOR_SVIDEO:
915 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
916 video_levels = tv_mode->svideo_levels;
917 color_conversion = tv_mode->svideo_color;
918 burst_ena = tv_mode->burst_ena;
921 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
922 (tv_mode->htotal << TV_HTOTAL_SHIFT);
924 hctl2 = (tv_mode->hburst_start << 16) |
925 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
928 hctl2 |= TV_BURST_ENA;
930 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
931 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
933 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
934 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
935 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
937 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
938 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
939 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
941 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
942 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
943 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
945 if (tv_mode->veq_ena)
946 vctl3 |= TV_EQUAL_ENA;
948 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
949 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
951 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
952 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
954 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
955 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
957 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
958 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
960 if (intel_crtc->pipe == 1)
961 tv_ctl |= TV_ENC_PIPEB_SELECT;
962 tv_ctl |= tv_mode->oversample;
964 if (tv_mode->progressive)
965 tv_ctl |= TV_PROGRESSIVE;
966 if (tv_mode->trilevel_sync)
967 tv_ctl |= TV_TRILEVEL_SYNC;
968 if (tv_mode->pal_burst)
969 tv_ctl |= TV_PAL_BURST;
972 if (tv_mode->dda1_inc)
973 scctl1 |= TV_SC_DDA1_EN;
974 if (tv_mode->dda2_inc)
975 scctl1 |= TV_SC_DDA2_EN;
976 if (tv_mode->dda3_inc)
977 scctl1 |= TV_SC_DDA3_EN;
978 scctl1 |= tv_mode->sc_reset;
980 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
981 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
983 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
984 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
986 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
987 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
989 /* Enable two fixes for the chips that need them. */
990 if (dev->pci_device < 0x2772)
991 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
993 I915_WRITE(TV_H_CTL_1, hctl1);
994 I915_WRITE(TV_H_CTL_2, hctl2);
995 I915_WRITE(TV_H_CTL_3, hctl3);
996 I915_WRITE(TV_V_CTL_1, vctl1);
997 I915_WRITE(TV_V_CTL_2, vctl2);
998 I915_WRITE(TV_V_CTL_3, vctl3);
999 I915_WRITE(TV_V_CTL_4, vctl4);
1000 I915_WRITE(TV_V_CTL_5, vctl5);
1001 I915_WRITE(TV_V_CTL_6, vctl6);
1002 I915_WRITE(TV_V_CTL_7, vctl7);
1003 I915_WRITE(TV_SC_CTL_1, scctl1);
1004 I915_WRITE(TV_SC_CTL_2, scctl2);
1005 I915_WRITE(TV_SC_CTL_3, scctl3);
1007 if (color_conversion) {
1008 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1009 color_conversion->gy);
1010 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
1011 color_conversion->ay);
1012 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1013 color_conversion->gu);
1014 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1015 color_conversion->au);
1016 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1017 color_conversion->gv);
1018 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1019 color_conversion->av);
1022 if (INTEL_INFO(dev)->gen >= 4)
1023 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1025 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1028 I915_WRITE(TV_CLR_LEVEL,
1029 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1030 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1032 int pipeconf_reg = PIPECONF(pipe);
1033 int dspcntr_reg = DSPCNTR(intel_crtc->plane);
1034 int pipeconf = I915_READ(pipeconf_reg);
1035 int dspcntr = I915_READ(dspcntr_reg);
1036 int dspbase_reg = DSPADDR(intel_crtc->plane);
1037 int xpos = 0x0, ypos = 0x0;
1038 unsigned int xsize, ysize;
1039 /* Pipe must be off here */
1040 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1041 /* Flush the plane changes */
1042 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1044 /* Wait for vblank for the disable to take effect */
1046 intel_wait_for_vblank(dev, intel_crtc->pipe);
1048 I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
1049 /* Wait for vblank for the disable to take effect. */
1050 intel_wait_for_pipe_off(dev, intel_crtc->pipe);
1052 /* Filter ctl must be set before TV_WIN_SIZE */
1053 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1054 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1055 if (tv_mode->progressive)
1056 ysize = tv_mode->nbr_end + 1;
1058 ysize = 2*tv_mode->nbr_end + 1;
1060 xpos += intel_tv->margin[TV_MARGIN_LEFT];
1061 ypos += intel_tv->margin[TV_MARGIN_TOP];
1062 xsize -= (intel_tv->margin[TV_MARGIN_LEFT] +
1063 intel_tv->margin[TV_MARGIN_RIGHT]);
1064 ysize -= (intel_tv->margin[TV_MARGIN_TOP] +
1065 intel_tv->margin[TV_MARGIN_BOTTOM]);
1066 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1067 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1069 I915_WRITE(pipeconf_reg, pipeconf);
1070 I915_WRITE(dspcntr_reg, dspcntr);
1071 /* Flush the plane changes */
1072 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1076 for (i = 0; i < 60; i++)
1077 I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1078 for (i = 0; i < 60; i++)
1079 I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1080 for (i = 0; i < 43; i++)
1081 I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1082 for (i = 0; i < 43; i++)
1083 I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1084 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1085 I915_WRITE(TV_CTL, tv_ctl);
1088 static const struct drm_display_mode reported_modes[] = {
1090 .name = "NTSC 480i",
1093 .hsync_start = 1368,
1098 .vsync_start = 1027,
1101 .type = DRM_MODE_TYPE_DRIVER,
1106 * Detects TV presence by checking for load.
1108 * Requires that the current pipe's DPLL is active.
1110 * \return true if TV is connected.
1111 * \return false if TV is disconnected.
1114 intel_tv_detect_type(struct intel_tv *intel_tv,
1115 struct drm_connector *connector)
1117 struct drm_encoder *encoder = &intel_tv->base.base;
1118 struct drm_crtc *crtc = encoder->crtc;
1119 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1120 struct drm_device *dev = encoder->dev;
1121 struct drm_i915_private *dev_priv = dev->dev_private;
1122 u32 tv_ctl, save_tv_ctl;
1123 u32 tv_dac, save_tv_dac;
1126 /* Disable TV interrupts around load detect or we'll recurse */
1127 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1128 lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1129 i915_disable_pipestat(dev_priv, 0,
1130 PIPE_HOTPLUG_INTERRUPT_ENABLE |
1131 PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
1132 lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1135 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1136 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1138 /* Poll for TV detection */
1139 tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
1140 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1141 if (intel_crtc->pipe == 1)
1142 tv_ctl |= TV_ENC_PIPEB_SELECT;
1144 tv_ctl &= ~TV_ENC_PIPEB_SELECT;
1146 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1147 tv_dac |= (TVDAC_STATE_CHG_EN |
1156 I915_WRITE(TV_CTL, tv_ctl);
1157 I915_WRITE(TV_DAC, tv_dac);
1158 POSTING_READ(TV_DAC);
1160 intel_wait_for_vblank(intel_tv->base.base.dev,
1161 to_intel_crtc(intel_tv->base.base.crtc)->pipe);
1164 tv_dac = I915_READ(TV_DAC);
1165 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1172 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1173 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1174 type = DRM_MODE_CONNECTOR_Composite;
1175 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1176 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1177 type = DRM_MODE_CONNECTOR_SVIDEO;
1178 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1179 DRM_DEBUG_KMS("Detected Component TV connection\n");
1180 type = DRM_MODE_CONNECTOR_Component;
1182 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1186 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1187 I915_WRITE(TV_CTL, save_tv_ctl);
1189 /* Restore interrupt config */
1190 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1191 lockmgr(&dev_priv->irq_lock, LK_EXCLUSIVE);
1192 i915_enable_pipestat(dev_priv, 0,
1193 PIPE_HOTPLUG_INTERRUPT_ENABLE |
1194 PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
1195 lockmgr(&dev_priv->irq_lock, LK_RELEASE);
1202 * Here we set accurate tv format according to connector type
1203 * i.e Component TV should not be assigned by NTSC or PAL
1205 static void intel_tv_find_better_format(struct drm_connector *connector)
1207 struct intel_tv *intel_tv = intel_attached_tv(connector);
1208 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1211 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1212 tv_mode->component_only)
1216 for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) {
1217 tv_mode = tv_modes + i;
1219 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1220 tv_mode->component_only)
1224 intel_tv->tv_format = tv_mode->name;
1225 drm_connector_property_set_value(connector,
1226 connector->dev->mode_config.tv_mode_property, i);
1230 * Detect the TV connection.
1232 * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
1233 * we have a pipe programmed in order to probe the TV.
1235 static enum drm_connector_status
1236 intel_tv_detect(struct drm_connector *connector, bool force)
1238 struct drm_display_mode mode;
1239 struct intel_tv *intel_tv = intel_attached_tv(connector);
1242 mode = reported_modes[0];
1243 drm_mode_set_crtcinfo(&mode, 0);
1245 if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
1246 type = intel_tv_detect_type(intel_tv, connector);
1248 struct intel_load_detect_pipe tmp;
1250 if (intel_get_load_detect_pipe(&intel_tv->base, connector,
1252 type = intel_tv_detect_type(intel_tv, connector);
1253 intel_release_load_detect_pipe(&intel_tv->base,
1257 return connector_status_unknown;
1259 return connector->status;
1262 return connector_status_disconnected;
1264 intel_tv->type = type;
1265 intel_tv_find_better_format(connector);
1267 return connector_status_connected;
1270 static const struct input_res {
1273 } input_res_table[] = {
1274 {"640x480", 640, 480},
1275 {"800x600", 800, 600},
1276 {"1024x768", 1024, 768},
1277 {"1280x1024", 1280, 1024},
1278 {"848x480", 848, 480},
1279 {"1280x720", 1280, 720},
1280 {"1920x1080", 1920, 1080},
1284 * Chose preferred mode according to line number of TV format
1287 intel_tv_chose_preferred_modes(struct drm_connector *connector,
1288 struct drm_display_mode *mode_ptr)
1290 struct intel_tv *intel_tv = intel_attached_tv(connector);
1291 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1293 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1294 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1295 else if (tv_mode->nbr_end > 480) {
1296 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1297 if (mode_ptr->vdisplay == 720)
1298 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1299 } else if (mode_ptr->vdisplay == 1080)
1300 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1305 * Stub get_modes function.
1307 * This should probably return a set of fixed modes, unless we can figure out
1308 * how to probe modes off of TV connections.
1312 intel_tv_get_modes(struct drm_connector *connector)
1314 struct drm_display_mode *mode_ptr;
1315 struct intel_tv *intel_tv = intel_attached_tv(connector);
1316 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
1320 for (j = 0; j < DRM_ARRAY_SIZE(input_res_table);
1322 const struct input_res *input = &input_res_table[j];
1323 unsigned int hactive_s = input->w;
1324 unsigned int vactive_s = input->h;
1326 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1329 if (input->w > 1024 && (!tv_mode->progressive
1330 && !tv_mode->component_only))
1333 mode_ptr = drm_mode_create(connector->dev);
1336 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1338 mode_ptr->hdisplay = hactive_s;
1339 mode_ptr->hsync_start = hactive_s + 1;
1340 mode_ptr->hsync_end = hactive_s + 64;
1341 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1342 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1343 mode_ptr->htotal = hactive_s + 96;
1345 mode_ptr->vdisplay = vactive_s;
1346 mode_ptr->vsync_start = vactive_s + 1;
1347 mode_ptr->vsync_end = vactive_s + 32;
1348 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1349 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1350 mode_ptr->vtotal = vactive_s + 33;
1352 tmp = (u64) tv_mode->refresh * mode_ptr->vtotal;
1353 tmp *= mode_ptr->htotal;
1354 tmp = tmp / 1000000;
1355 mode_ptr->clock = (int) tmp;
1357 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1358 intel_tv_chose_preferred_modes(connector, mode_ptr);
1359 drm_mode_probed_add(connector, mode_ptr);
1367 intel_tv_destroy(struct drm_connector *connector)
1370 drm_sysfs_connector_remove(connector);
1372 drm_connector_cleanup(connector);
1373 drm_free(connector, DRM_MEM_KMS);
1378 intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
1381 struct drm_device *dev = connector->dev;
1382 struct intel_tv *intel_tv = intel_attached_tv(connector);
1383 struct drm_crtc *crtc = intel_tv->base.base.crtc;
1385 bool changed = false;
1387 ret = drm_connector_property_set_value(connector, property, val);
1391 if (property == dev->mode_config.tv_left_margin_property &&
1392 intel_tv->margin[TV_MARGIN_LEFT] != val) {
1393 intel_tv->margin[TV_MARGIN_LEFT] = val;
1395 } else if (property == dev->mode_config.tv_right_margin_property &&
1396 intel_tv->margin[TV_MARGIN_RIGHT] != val) {
1397 intel_tv->margin[TV_MARGIN_RIGHT] = val;
1399 } else if (property == dev->mode_config.tv_top_margin_property &&
1400 intel_tv->margin[TV_MARGIN_TOP] != val) {
1401 intel_tv->margin[TV_MARGIN_TOP] = val;
1403 } else if (property == dev->mode_config.tv_bottom_margin_property &&
1404 intel_tv->margin[TV_MARGIN_BOTTOM] != val) {
1405 intel_tv->margin[TV_MARGIN_BOTTOM] = val;
1407 } else if (property == dev->mode_config.tv_mode_property) {
1408 if (val >= DRM_ARRAY_SIZE(tv_modes)) {
1412 if (!strcmp(intel_tv->tv_format, tv_modes[val].name))
1415 intel_tv->tv_format = tv_modes[val].name;
1422 if (changed && crtc)
1423 drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
1429 static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
1430 .dpms = intel_tv_dpms,
1431 .mode_fixup = intel_tv_mode_fixup,
1432 .prepare = intel_encoder_prepare,
1433 .mode_set = intel_tv_mode_set,
1434 .commit = intel_encoder_commit,
1437 static const struct drm_connector_funcs intel_tv_connector_funcs = {
1438 .dpms = drm_helper_connector_dpms,
1439 .detect = intel_tv_detect,
1440 .destroy = intel_tv_destroy,
1441 .set_property = intel_tv_set_property,
1442 .fill_modes = drm_helper_probe_single_connector_modes,
1445 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1446 .mode_valid = intel_tv_mode_valid,
1447 .get_modes = intel_tv_get_modes,
1448 .best_encoder = intel_best_encoder,
1451 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1452 .destroy = intel_encoder_destroy,
1456 * Enumerate the child dev array parsed from VBT to check whether
1457 * the integrated TV is present.
1458 * If it is present, return 1.
1459 * If it is not present, return false.
1460 * If no child dev is parsed from VBT, it assumes that the TV is present.
1462 static int tv_is_present_in_vbt(struct drm_device *dev)
1464 struct drm_i915_private *dev_priv = dev->dev_private;
1465 struct child_device_config *p_child;
1468 if (!dev_priv->child_dev_num)
1472 for (i = 0; i < dev_priv->child_dev_num; i++) {
1473 p_child = dev_priv->child_dev + i;
1475 * If the device type is not TV, continue.
1477 if (p_child->device_type != DEVICE_TYPE_INT_TV &&
1478 p_child->device_type != DEVICE_TYPE_TV)
1480 /* Only when the addin_offset is non-zero, it is regarded
1483 if (p_child->addin_offset) {
1492 intel_tv_init(struct drm_device *dev)
1494 struct drm_i915_private *dev_priv = dev->dev_private;
1495 struct drm_connector *connector;
1496 struct intel_tv *intel_tv;
1497 struct intel_encoder *intel_encoder;
1498 struct intel_connector *intel_connector;
1499 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1500 char *tv_format_names[DRM_ARRAY_SIZE(tv_modes)];
1501 int i, initial_mode = 0;
1503 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1506 if (!tv_is_present_in_vbt(dev)) {
1507 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1510 /* Even if we have an encoder we may not have a connector */
1511 if (!dev_priv->int_tv_support)
1515 * Sanity check the TV output by checking to see if the
1516 * DAC register holds a value
1518 save_tv_dac = I915_READ(TV_DAC);
1520 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1521 tv_dac_on = I915_READ(TV_DAC);
1523 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1524 tv_dac_off = I915_READ(TV_DAC);
1526 I915_WRITE(TV_DAC, save_tv_dac);
1529 * If the register does not hold the state change enable
1530 * bit, (either as a 0 or a 1), assume it doesn't really
1533 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1534 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1537 intel_tv = kmalloc(sizeof(struct intel_tv), DRM_MEM_KMS,
1539 intel_connector = kmalloc(sizeof(struct intel_connector), DRM_MEM_KMS,
1542 intel_encoder = &intel_tv->base;
1543 connector = &intel_connector->base;
1545 /* The documentation, for the older chipsets at least, recommend
1546 * using a polling method rather than hotplug detection for TVs.
1547 * This is because in order to perform the hotplug detection, the PLLs
1548 * for the TV must be kept alive increasing power drain and starving
1549 * bandwidth from other encoders. Notably for instance, it causes
1550 * pipe underruns on Crestline when this encoder is supposedly idle.
1552 * More recent chipsets favour HDMI rather than integrated S-Video.
1554 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1556 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1557 DRM_MODE_CONNECTOR_SVIDEO);
1559 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1560 DRM_MODE_ENCODER_TVDAC);
1562 intel_connector_attach_encoder(intel_connector, intel_encoder);
1563 intel_encoder->type = INTEL_OUTPUT_TVOUT;
1564 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1565 intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
1566 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
1567 intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
1568 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1570 /* BIOS margin values */
1571 intel_tv->margin[TV_MARGIN_LEFT] = 54;
1572 intel_tv->margin[TV_MARGIN_TOP] = 36;
1573 intel_tv->margin[TV_MARGIN_RIGHT] = 46;
1574 intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
1576 intel_tv->tv_format = tv_modes[initial_mode].name;
1578 drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
1579 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1580 connector->interlace_allowed = false;
1581 connector->doublescan_allowed = false;
1583 /* Create TV properties then attach current values */
1584 for (i = 0; i < DRM_ARRAY_SIZE(tv_modes); i++)
1585 tv_format_names[i] = __DECONST(char *, tv_modes[i].name);
1586 drm_mode_create_tv_properties(dev,
1587 DRM_ARRAY_SIZE(tv_modes),
1590 drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
1592 drm_connector_attach_property(connector,
1593 dev->mode_config.tv_left_margin_property,
1594 intel_tv->margin[TV_MARGIN_LEFT]);
1595 drm_connector_attach_property(connector,
1596 dev->mode_config.tv_top_margin_property,
1597 intel_tv->margin[TV_MARGIN_TOP]);
1598 drm_connector_attach_property(connector,
1599 dev->mode_config.tv_right_margin_property,
1600 intel_tv->margin[TV_MARGIN_RIGHT]);
1601 drm_connector_attach_property(connector,
1602 dev->mode_config.tv_bottom_margin_property,
1603 intel_tv->margin[TV_MARGIN_BOTTOM]);
1605 drm_sysfs_connector_add(connector);