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.
37 #include "intel_drv.h"
42 TV_MARGIN_LEFT
, TV_MARGIN_TOP
,
43 TV_MARGIN_RIGHT
, TV_MARGIN_BOTTOM
46 /** Private structure for the integrated TV support */
48 struct intel_encoder base
;
51 const char *tv_format
;
63 u32 save_TV_SC_CTL_1
, save_TV_SC_CTL_2
, save_TV_SC_CTL_3
;
71 u32 save_TV_CLR_KNOBS
;
72 u32 save_TV_CLR_LEVEL
;
75 u32 save_TV_FILTER_CTL_1
;
76 u32 save_TV_FILTER_CTL_2
;
77 u32 save_TV_FILTER_CTL_3
;
79 u32 save_TV_H_LUMA
[60];
80 u32 save_TV_H_CHROMA
[60];
81 u32 save_TV_V_LUMA
[43];
82 u32 save_TV_V_CHROMA
[43];
89 int blank
, black
, burst
;
92 struct color_conversion
{
98 static const u32 filter_table
[] = {
99 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
100 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
101 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
102 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
103 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
104 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
105 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
106 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
107 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
108 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
109 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
110 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
111 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
112 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
113 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
114 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
115 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
116 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
117 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
118 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
119 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
120 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
121 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
122 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
123 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
124 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
125 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
126 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
127 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
128 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
129 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
130 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
131 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
132 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
133 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
134 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
135 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
136 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
137 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
138 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
139 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
140 0x2D002CC0, 0x30003640, 0x2D0036C0,
141 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
142 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
143 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
144 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
145 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
146 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
147 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
148 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
149 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
150 0x28003100, 0x28002F00, 0x00003100,
154 * Color conversion values have 3 separate fixed point formats:
156 * 10 bit fields (ay, au)
157 * 1.9 fixed point (b.bbbbbbbbb)
158 * 11 bit fields (ry, by, ru, gu, gv)
159 * exp.mantissa (ee.mmmmmmmmm)
160 * ee = 00 = 10^-1 (0.mmmmmmmmm)
161 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
162 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
163 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
164 * 12 bit fields (gy, rv, bu)
165 * exp.mantissa (eee.mmmmmmmmm)
166 * eee = 000 = 10^-1 (0.mmmmmmmmm)
167 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
168 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
169 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
170 * eee = 100 = reserved
171 * eee = 101 = reserved
172 * eee = 110 = reserved
173 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
175 * Saturation and contrast are 8 bits, with their own representation:
176 * 8 bit field (saturation, contrast)
177 * exp.mantissa (ee.mmmmmm)
178 * ee = 00 = 10^-1 (0.mmmmmm)
179 * ee = 01 = 10^0 (m.mmmmm)
180 * ee = 10 = 10^1 (mm.mmmm)
181 * ee = 11 = 10^2 (mmm.mmm)
183 * Simple conversion function:
186 * float_to_csc_11(float f)
199 * for (exp = 0; exp < 3 && f < 0.5; exp++)
201 * mant = (f * (1 << 9) + 0.5);
202 * if (mant >= (1 << 9))
203 * mant = (1 << 9) - 1;
205 * ret = (exp << 9) | mant;
211 * Behold, magic numbers! If we plant them they might grow a big
212 * s-video cable to the sky... or something.
214 * Pre-converted to appropriate hex value.
218 * PAL & NTSC values for composite & s-video connections
220 static const struct color_conversion ntsc_m_csc_composite
= {
221 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0104,
222 .ru
= 0x0733, .gu
= 0x052d, .bu
= 0x05c7, .au
= 0x0200,
223 .rv
= 0x0340, .gv
= 0x030c, .bv
= 0x06d0, .av
= 0x0200,
226 static const struct video_levels ntsc_m_levels_composite
= {
227 .blank
= 225, .black
= 267, .burst
= 113,
230 static const struct color_conversion ntsc_m_csc_svideo
= {
231 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0133,
232 .ru
= 0x076a, .gu
= 0x0564, .bu
= 0x030d, .au
= 0x0200,
233 .rv
= 0x037a, .gv
= 0x033d, .bv
= 0x06f6, .av
= 0x0200,
236 static const struct video_levels ntsc_m_levels_svideo
= {
237 .blank
= 266, .black
= 316, .burst
= 133,
240 static const struct color_conversion ntsc_j_csc_composite
= {
241 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0119,
242 .ru
= 0x074c, .gu
= 0x0546, .bu
= 0x05ec, .au
= 0x0200,
243 .rv
= 0x035a, .gv
= 0x0322, .bv
= 0x06e1, .av
= 0x0200,
246 static const struct video_levels ntsc_j_levels_composite
= {
247 .blank
= 225, .black
= 225, .burst
= 113,
250 static const struct color_conversion ntsc_j_csc_svideo
= {
251 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x014c,
252 .ru
= 0x0788, .gu
= 0x0581, .bu
= 0x0322, .au
= 0x0200,
253 .rv
= 0x0399, .gv
= 0x0356, .bv
= 0x070a, .av
= 0x0200,
256 static const struct video_levels ntsc_j_levels_svideo
= {
257 .blank
= 266, .black
= 266, .burst
= 133,
260 static const struct color_conversion pal_csc_composite
= {
261 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0113,
262 .ru
= 0x0745, .gu
= 0x053f, .bu
= 0x05e1, .au
= 0x0200,
263 .rv
= 0x0353, .gv
= 0x031c, .bv
= 0x06dc, .av
= 0x0200,
266 static const struct video_levels pal_levels_composite
= {
267 .blank
= 237, .black
= 237, .burst
= 118,
270 static const struct color_conversion pal_csc_svideo
= {
271 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0145,
272 .ru
= 0x0780, .gu
= 0x0579, .bu
= 0x031c, .au
= 0x0200,
273 .rv
= 0x0390, .gv
= 0x034f, .bv
= 0x0705, .av
= 0x0200,
276 static const struct video_levels pal_levels_svideo
= {
277 .blank
= 280, .black
= 280, .burst
= 139,
280 static const struct color_conversion pal_m_csc_composite
= {
281 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0104,
282 .ru
= 0x0733, .gu
= 0x052d, .bu
= 0x05c7, .au
= 0x0200,
283 .rv
= 0x0340, .gv
= 0x030c, .bv
= 0x06d0, .av
= 0x0200,
286 static const struct video_levels pal_m_levels_composite
= {
287 .blank
= 225, .black
= 267, .burst
= 113,
290 static const struct color_conversion pal_m_csc_svideo
= {
291 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0133,
292 .ru
= 0x076a, .gu
= 0x0564, .bu
= 0x030d, .au
= 0x0200,
293 .rv
= 0x037a, .gv
= 0x033d, .bv
= 0x06f6, .av
= 0x0200,
296 static const struct video_levels pal_m_levels_svideo
= {
297 .blank
= 266, .black
= 316, .burst
= 133,
300 static const struct color_conversion pal_n_csc_composite
= {
301 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0104,
302 .ru
= 0x0733, .gu
= 0x052d, .bu
= 0x05c7, .au
= 0x0200,
303 .rv
= 0x0340, .gv
= 0x030c, .bv
= 0x06d0, .av
= 0x0200,
306 static const struct video_levels pal_n_levels_composite
= {
307 .blank
= 225, .black
= 267, .burst
= 118,
310 static const struct color_conversion pal_n_csc_svideo
= {
311 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0133,
312 .ru
= 0x076a, .gu
= 0x0564, .bu
= 0x030d, .au
= 0x0200,
313 .rv
= 0x037a, .gv
= 0x033d, .bv
= 0x06f6, .av
= 0x0200,
316 static const struct video_levels pal_n_levels_svideo
= {
317 .blank
= 266, .black
= 316, .burst
= 139,
321 * Component connections
323 static const struct color_conversion sdtv_csc_yprpb
= {
324 .ry
= 0x0332, .gy
= 0x012d, .by
= 0x07d3, .ay
= 0x0145,
325 .ru
= 0x0559, .gu
= 0x0353, .bu
= 0x0100, .au
= 0x0200,
326 .rv
= 0x0100, .gv
= 0x03ad, .bv
= 0x074d, .av
= 0x0200,
329 static const struct color_conversion sdtv_csc_rgb
= {
330 .ry
= 0x0000, .gy
= 0x0f00, .by
= 0x0000, .ay
= 0x0166,
331 .ru
= 0x0000, .gu
= 0x0000, .bu
= 0x0f00, .au
= 0x0166,
332 .rv
= 0x0f00, .gv
= 0x0000, .bv
= 0x0000, .av
= 0x0166,
335 static const struct color_conversion hdtv_csc_yprpb
= {
336 .ry
= 0x05b3, .gy
= 0x016e, .by
= 0x0728, .ay
= 0x0145,
337 .ru
= 0x07d5, .gu
= 0x038b, .bu
= 0x0100, .au
= 0x0200,
338 .rv
= 0x0100, .gv
= 0x03d1, .bv
= 0x06bc, .av
= 0x0200,
341 static const struct color_conversion hdtv_csc_rgb
= {
342 .ry
= 0x0000, .gy
= 0x0f00, .by
= 0x0000, .ay
= 0x0166,
343 .ru
= 0x0000, .gu
= 0x0000, .bu
= 0x0f00, .au
= 0x0166,
344 .rv
= 0x0f00, .gv
= 0x0000, .bv
= 0x0000, .av
= 0x0166,
347 static const struct video_levels component_levels
= {
348 .blank
= 279, .black
= 279, .burst
= 0,
355 int refresh
; /* in millihertz (for precision) */
357 int hsync_end
, hblank_start
, hblank_end
, htotal
;
358 bool progressive
, trilevel_sync
, component_only
;
359 int vsync_start_f1
, vsync_start_f2
, vsync_len
;
361 int veq_start_f1
, veq_start_f2
, veq_len
;
362 int vi_end_f1
, vi_end_f2
, nbr_end
;
364 int hburst_start
, hburst_len
;
365 int vburst_start_f1
, vburst_end_f1
;
366 int vburst_start_f2
, vburst_end_f2
;
367 int vburst_start_f3
, vburst_end_f3
;
368 int vburst_start_f4
, vburst_end_f4
;
370 * subcarrier programming
372 int dda2_size
, dda3_size
, dda1_inc
, dda2_inc
, dda3_inc
;
378 const struct video_levels
*composite_levels
, *svideo_levels
;
379 const struct color_conversion
*composite_color
, *svideo_color
;
380 const u32
*filter_table
;
388 * I think this works as follows:
390 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
392 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
395 * dda1_ideal = subcarrier/pixel * 4096
396 * dda1_inc = floor (dda1_ideal)
397 * dda2 = dda1_ideal - dda1_inc
399 * then pick a ratio for dda2 that gives the closest approximation. If
400 * you can't get close enough, you can play with dda3 as well. This
401 * seems likely to happen when dda2 is small as the jumps would be larger
405 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
407 * The constants below were all computed using a 107.520MHz clock
411 * Register programming values for TV modes.
413 * These values account for -1s required.
416 static const struct tv_mode tv_modes
[] = {
421 .oversample
= TV_OVERSAMPLE_8X
,
423 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
425 .hsync_end
= 64, .hblank_end
= 124,
426 .hblank_start
= 836, .htotal
= 857,
428 .progressive
= false, .trilevel_sync
= false,
430 .vsync_start_f1
= 6, .vsync_start_f2
= 7,
433 .veq_ena
= true, .veq_start_f1
= 0,
434 .veq_start_f2
= 1, .veq_len
= 18,
436 .vi_end_f1
= 20, .vi_end_f2
= 21,
440 .hburst_start
= 72, .hburst_len
= 34,
441 .vburst_start_f1
= 9, .vburst_end_f1
= 240,
442 .vburst_start_f2
= 10, .vburst_end_f2
= 240,
443 .vburst_start_f3
= 9, .vburst_end_f3
= 240,
444 .vburst_start_f4
= 10, .vburst_end_f4
= 240,
446 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
448 .dda2_inc
= 20800, .dda2_size
= 27456,
449 .dda3_inc
= 0, .dda3_size
= 0,
450 .sc_reset
= TV_SC_RESET_EVERY_4
,
453 .composite_levels
= &ntsc_m_levels_composite
,
454 .composite_color
= &ntsc_m_csc_composite
,
455 .svideo_levels
= &ntsc_m_levels_svideo
,
456 .svideo_color
= &ntsc_m_csc_svideo
,
458 .filter_table
= filter_table
,
464 .oversample
= TV_OVERSAMPLE_8X
,
466 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
467 .hsync_end
= 64, .hblank_end
= 124,
468 .hblank_start
= 836, .htotal
= 857,
470 .progressive
= false, .trilevel_sync
= false,
472 .vsync_start_f1
= 6, .vsync_start_f2
= 7,
475 .veq_ena
= true, .veq_start_f1
= 0,
476 .veq_start_f2
= 1, .veq_len
= 18,
478 .vi_end_f1
= 20, .vi_end_f2
= 21,
482 .hburst_start
= 72, .hburst_len
= 34,
483 .vburst_start_f1
= 9, .vburst_end_f1
= 240,
484 .vburst_start_f2
= 10, .vburst_end_f2
= 240,
485 .vburst_start_f3
= 9, .vburst_end_f3
= 240,
486 .vburst_start_f4
= 10, .vburst_end_f4
= 240,
488 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
490 .dda2_inc
= 4093, .dda2_size
= 27456,
491 .dda3_inc
= 310, .dda3_size
= 525,
492 .sc_reset
= TV_SC_RESET_NEVER
,
495 .composite_levels
= &ntsc_m_levels_composite
,
496 .composite_color
= &ntsc_m_csc_composite
,
497 .svideo_levels
= &ntsc_m_levels_svideo
,
498 .svideo_color
= &ntsc_m_csc_svideo
,
500 .filter_table
= filter_table
,
506 .oversample
= TV_OVERSAMPLE_8X
,
509 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
510 .hsync_end
= 64, .hblank_end
= 124,
511 .hblank_start
= 836, .htotal
= 857,
513 .progressive
= false, .trilevel_sync
= false,
515 .vsync_start_f1
= 6, .vsync_start_f2
= 7,
518 .veq_ena
= true, .veq_start_f1
= 0,
519 .veq_start_f2
= 1, .veq_len
= 18,
521 .vi_end_f1
= 20, .vi_end_f2
= 21,
525 .hburst_start
= 72, .hburst_len
= 34,
526 .vburst_start_f1
= 9, .vburst_end_f1
= 240,
527 .vburst_start_f2
= 10, .vburst_end_f2
= 240,
528 .vburst_start_f3
= 9, .vburst_end_f3
= 240,
529 .vburst_start_f4
= 10, .vburst_end_f4
= 240,
531 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
533 .dda2_inc
= 20800, .dda2_size
= 27456,
534 .dda3_inc
= 0, .dda3_size
= 0,
535 .sc_reset
= TV_SC_RESET_EVERY_4
,
538 .composite_levels
= &ntsc_j_levels_composite
,
539 .composite_color
= &ntsc_j_csc_composite
,
540 .svideo_levels
= &ntsc_j_levels_svideo
,
541 .svideo_color
= &ntsc_j_csc_svideo
,
543 .filter_table
= filter_table
,
549 .oversample
= TV_OVERSAMPLE_8X
,
552 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
553 .hsync_end
= 64, .hblank_end
= 124,
554 .hblank_start
= 836, .htotal
= 857,
556 .progressive
= false, .trilevel_sync
= false,
558 .vsync_start_f1
= 6, .vsync_start_f2
= 7,
561 .veq_ena
= true, .veq_start_f1
= 0,
562 .veq_start_f2
= 1, .veq_len
= 18,
564 .vi_end_f1
= 20, .vi_end_f2
= 21,
568 .hburst_start
= 72, .hburst_len
= 34,
569 .vburst_start_f1
= 9, .vburst_end_f1
= 240,
570 .vburst_start_f2
= 10, .vburst_end_f2
= 240,
571 .vburst_start_f3
= 9, .vburst_end_f3
= 240,
572 .vburst_start_f4
= 10, .vburst_end_f4
= 240,
574 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
576 .dda2_inc
= 16704, .dda2_size
= 27456,
577 .dda3_inc
= 0, .dda3_size
= 0,
578 .sc_reset
= TV_SC_RESET_EVERY_8
,
581 .composite_levels
= &pal_m_levels_composite
,
582 .composite_color
= &pal_m_csc_composite
,
583 .svideo_levels
= &pal_m_levels_svideo
,
584 .svideo_color
= &pal_m_csc_svideo
,
586 .filter_table
= filter_table
,
589 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
593 .oversample
= TV_OVERSAMPLE_8X
,
596 .hsync_end
= 64, .hblank_end
= 128,
597 .hblank_start
= 844, .htotal
= 863,
599 .progressive
= false, .trilevel_sync
= false,
602 .vsync_start_f1
= 6, .vsync_start_f2
= 7,
605 .veq_ena
= true, .veq_start_f1
= 0,
606 .veq_start_f2
= 1, .veq_len
= 18,
608 .vi_end_f1
= 24, .vi_end_f2
= 25,
612 .hburst_start
= 73, .hburst_len
= 34,
613 .vburst_start_f1
= 8, .vburst_end_f1
= 285,
614 .vburst_start_f2
= 8, .vburst_end_f2
= 286,
615 .vburst_start_f3
= 9, .vburst_end_f3
= 286,
616 .vburst_start_f4
= 9, .vburst_end_f4
= 285,
619 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
621 .dda2_inc
= 23578, .dda2_size
= 27648,
622 .dda3_inc
= 134, .dda3_size
= 625,
623 .sc_reset
= TV_SC_RESET_EVERY_8
,
626 .composite_levels
= &pal_n_levels_composite
,
627 .composite_color
= &pal_n_csc_composite
,
628 .svideo_levels
= &pal_n_levels_svideo
,
629 .svideo_color
= &pal_n_csc_svideo
,
631 .filter_table
= filter_table
,
634 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
638 .oversample
= TV_OVERSAMPLE_8X
,
641 .hsync_end
= 64, .hblank_end
= 142,
642 .hblank_start
= 844, .htotal
= 863,
644 .progressive
= false, .trilevel_sync
= false,
646 .vsync_start_f1
= 5, .vsync_start_f2
= 6,
649 .veq_ena
= true, .veq_start_f1
= 0,
650 .veq_start_f2
= 1, .veq_len
= 15,
652 .vi_end_f1
= 24, .vi_end_f2
= 25,
656 .hburst_start
= 73, .hburst_len
= 32,
657 .vburst_start_f1
= 8, .vburst_end_f1
= 285,
658 .vburst_start_f2
= 8, .vburst_end_f2
= 286,
659 .vburst_start_f3
= 9, .vburst_end_f3
= 286,
660 .vburst_start_f4
= 9, .vburst_end_f4
= 285,
662 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
664 .dda2_inc
= 4122, .dda2_size
= 27648,
665 .dda3_inc
= 67, .dda3_size
= 625,
666 .sc_reset
= TV_SC_RESET_EVERY_8
,
669 .composite_levels
= &pal_levels_composite
,
670 .composite_color
= &pal_csc_composite
,
671 .svideo_levels
= &pal_levels_svideo
,
672 .svideo_color
= &pal_csc_svideo
,
674 .filter_table
= filter_table
,
680 .oversample
= TV_OVERSAMPLE_4X
,
683 .hsync_end
= 64, .hblank_end
= 122,
684 .hblank_start
= 842, .htotal
= 857,
686 .progressive
= true, .trilevel_sync
= false,
688 .vsync_start_f1
= 12, .vsync_start_f2
= 12,
693 .vi_end_f1
= 44, .vi_end_f2
= 44,
698 .filter_table
= filter_table
,
704 .oversample
= TV_OVERSAMPLE_4X
,
707 .hsync_end
= 64, .hblank_end
= 139,
708 .hblank_start
= 859, .htotal
= 863,
710 .progressive
= true, .trilevel_sync
= false,
712 .vsync_start_f1
= 10, .vsync_start_f2
= 10,
717 .vi_end_f1
= 48, .vi_end_f2
= 48,
722 .filter_table
= filter_table
,
728 .oversample
= TV_OVERSAMPLE_2X
,
731 .hsync_end
= 80, .hblank_end
= 300,
732 .hblank_start
= 1580, .htotal
= 1649,
734 .progressive
= true, .trilevel_sync
= true,
736 .vsync_start_f1
= 10, .vsync_start_f2
= 10,
741 .vi_end_f1
= 29, .vi_end_f2
= 29,
746 .filter_table
= filter_table
,
752 .oversample
= TV_OVERSAMPLE_2X
,
755 .hsync_end
= 80, .hblank_end
= 300,
756 .hblank_start
= 1580, .htotal
= 1979,
758 .progressive
= true, .trilevel_sync
= true,
760 .vsync_start_f1
= 10, .vsync_start_f2
= 10,
765 .vi_end_f1
= 29, .vi_end_f2
= 29,
770 .filter_table
= filter_table
,
774 .name
= "1080i@50Hz",
777 .oversample
= TV_OVERSAMPLE_2X
,
780 .hsync_end
= 88, .hblank_end
= 235,
781 .hblank_start
= 2155, .htotal
= 2639,
783 .progressive
= false, .trilevel_sync
= true,
785 .vsync_start_f1
= 4, .vsync_start_f2
= 5,
788 .veq_ena
= true, .veq_start_f1
= 4,
789 .veq_start_f2
= 4, .veq_len
= 10,
792 .vi_end_f1
= 21, .vi_end_f2
= 22,
797 .filter_table
= filter_table
,
800 .name
= "1080i@60Hz",
803 .oversample
= TV_OVERSAMPLE_2X
,
806 .hsync_end
= 88, .hblank_end
= 235,
807 .hblank_start
= 2155, .htotal
= 2199,
809 .progressive
= false, .trilevel_sync
= true,
811 .vsync_start_f1
= 4, .vsync_start_f2
= 5,
814 .veq_ena
= true, .veq_start_f1
= 4,
815 .veq_start_f2
= 4, .veq_len
= 10,
818 .vi_end_f1
= 21, .vi_end_f2
= 22,
823 .filter_table
= filter_table
,
827 static struct intel_tv
*enc_to_intel_tv(struct drm_encoder
*encoder
)
829 return container_of(encoder
, struct intel_tv
, base
.base
);
832 static struct intel_tv
*intel_attached_tv(struct drm_connector
*connector
)
834 return container_of(intel_attached_encoder(connector
),
840 intel_tv_get_hw_state(struct intel_encoder
*encoder
, enum pipe
*pipe
)
842 struct drm_device
*dev
= encoder
->base
.dev
;
843 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
844 u32 tmp
= I915_READ(TV_CTL
);
846 if (!(tmp
& TV_ENC_ENABLE
))
849 *pipe
= PORT_TO_PIPE(tmp
);
855 intel_enable_tv(struct intel_encoder
*encoder
)
857 struct drm_device
*dev
= encoder
->base
.dev
;
858 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
860 I915_WRITE(TV_CTL
, I915_READ(TV_CTL
) | TV_ENC_ENABLE
);
864 intel_disable_tv(struct intel_encoder
*encoder
)
866 struct drm_device
*dev
= encoder
->base
.dev
;
867 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
869 I915_WRITE(TV_CTL
, I915_READ(TV_CTL
) & ~TV_ENC_ENABLE
);
872 static const struct tv_mode
*
873 intel_tv_mode_lookup(const char *tv_format
)
877 for (i
= 0; i
< ARRAY_SIZE(tv_modes
); i
++) {
878 const struct tv_mode
*tv_mode
= &tv_modes
[i
];
880 if (!strcmp(tv_format
, tv_mode
->name
))
886 static const struct tv_mode
*
887 intel_tv_mode_find(struct intel_tv
*intel_tv
)
889 return intel_tv_mode_lookup(intel_tv
->tv_format
);
892 static enum drm_mode_status
893 intel_tv_mode_valid(struct drm_connector
*connector
,
894 struct drm_display_mode
*mode
)
896 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
897 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
899 /* Ensure TV refresh is close to desired refresh */
900 if (tv_mode
&& abs(tv_mode
->refresh
- drm_mode_vrefresh(mode
) * 1000)
904 return MODE_CLOCK_RANGE
;
909 intel_tv_mode_fixup(struct drm_encoder
*encoder
,
910 const struct drm_display_mode
*mode
,
911 struct drm_display_mode
*adjusted_mode
)
913 struct intel_tv
*intel_tv
= enc_to_intel_tv(encoder
);
914 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
919 if (intel_encoder_check_is_cloned(&intel_tv
->base
))
922 adjusted_mode
->clock
= tv_mode
->clock
;
927 intel_tv_mode_set(struct drm_encoder
*encoder
, struct drm_display_mode
*mode
,
928 struct drm_display_mode
*adjusted_mode
)
930 struct drm_device
*dev
= encoder
->dev
;
931 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
932 struct drm_crtc
*crtc
= encoder
->crtc
;
933 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
934 struct intel_tv
*intel_tv
= enc_to_intel_tv(encoder
);
935 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
937 u32 hctl1
, hctl2
, hctl3
;
938 u32 vctl1
, vctl2
, vctl3
, vctl4
, vctl5
, vctl6
, vctl7
;
939 u32 scctl1
, scctl2
, scctl3
;
941 const struct video_levels
*video_levels
;
942 const struct color_conversion
*color_conversion
;
944 int pipe
= intel_crtc
->pipe
;
947 return; /* can't happen (mode_prepare prevents this) */
949 tv_ctl
= I915_READ(TV_CTL
);
950 tv_ctl
&= TV_CTL_SAVE
;
952 switch (intel_tv
->type
) {
954 case DRM_MODE_CONNECTOR_Unknown
:
955 case DRM_MODE_CONNECTOR_Composite
:
956 tv_ctl
|= TV_ENC_OUTPUT_COMPOSITE
;
957 video_levels
= tv_mode
->composite_levels
;
958 color_conversion
= tv_mode
->composite_color
;
959 burst_ena
= tv_mode
->burst_ena
;
961 case DRM_MODE_CONNECTOR_Component
:
962 tv_ctl
|= TV_ENC_OUTPUT_COMPONENT
;
963 video_levels
= &component_levels
;
964 if (tv_mode
->burst_ena
)
965 color_conversion
= &sdtv_csc_yprpb
;
967 color_conversion
= &hdtv_csc_yprpb
;
970 case DRM_MODE_CONNECTOR_SVIDEO
:
971 tv_ctl
|= TV_ENC_OUTPUT_SVIDEO
;
972 video_levels
= tv_mode
->svideo_levels
;
973 color_conversion
= tv_mode
->svideo_color
;
974 burst_ena
= tv_mode
->burst_ena
;
977 hctl1
= (tv_mode
->hsync_end
<< TV_HSYNC_END_SHIFT
) |
978 (tv_mode
->htotal
<< TV_HTOTAL_SHIFT
);
980 hctl2
= (tv_mode
->hburst_start
<< 16) |
981 (tv_mode
->hburst_len
<< TV_HBURST_LEN_SHIFT
);
984 hctl2
|= TV_BURST_ENA
;
986 hctl3
= (tv_mode
->hblank_start
<< TV_HBLANK_START_SHIFT
) |
987 (tv_mode
->hblank_end
<< TV_HBLANK_END_SHIFT
);
989 vctl1
= (tv_mode
->nbr_end
<< TV_NBR_END_SHIFT
) |
990 (tv_mode
->vi_end_f1
<< TV_VI_END_F1_SHIFT
) |
991 (tv_mode
->vi_end_f2
<< TV_VI_END_F2_SHIFT
);
993 vctl2
= (tv_mode
->vsync_len
<< TV_VSYNC_LEN_SHIFT
) |
994 (tv_mode
->vsync_start_f1
<< TV_VSYNC_START_F1_SHIFT
) |
995 (tv_mode
->vsync_start_f2
<< TV_VSYNC_START_F2_SHIFT
);
997 vctl3
= (tv_mode
->veq_len
<< TV_VEQ_LEN_SHIFT
) |
998 (tv_mode
->veq_start_f1
<< TV_VEQ_START_F1_SHIFT
) |
999 (tv_mode
->veq_start_f2
<< TV_VEQ_START_F2_SHIFT
);
1001 if (tv_mode
->veq_ena
)
1002 vctl3
|= TV_EQUAL_ENA
;
1004 vctl4
= (tv_mode
->vburst_start_f1
<< TV_VBURST_START_F1_SHIFT
) |
1005 (tv_mode
->vburst_end_f1
<< TV_VBURST_END_F1_SHIFT
);
1007 vctl5
= (tv_mode
->vburst_start_f2
<< TV_VBURST_START_F2_SHIFT
) |
1008 (tv_mode
->vburst_end_f2
<< TV_VBURST_END_F2_SHIFT
);
1010 vctl6
= (tv_mode
->vburst_start_f3
<< TV_VBURST_START_F3_SHIFT
) |
1011 (tv_mode
->vburst_end_f3
<< TV_VBURST_END_F3_SHIFT
);
1013 vctl7
= (tv_mode
->vburst_start_f4
<< TV_VBURST_START_F4_SHIFT
) |
1014 (tv_mode
->vburst_end_f4
<< TV_VBURST_END_F4_SHIFT
);
1016 if (intel_crtc
->pipe
== 1)
1017 tv_ctl
|= TV_ENC_PIPEB_SELECT
;
1018 tv_ctl
|= tv_mode
->oversample
;
1020 if (tv_mode
->progressive
)
1021 tv_ctl
|= TV_PROGRESSIVE
;
1022 if (tv_mode
->trilevel_sync
)
1023 tv_ctl
|= TV_TRILEVEL_SYNC
;
1024 if (tv_mode
->pal_burst
)
1025 tv_ctl
|= TV_PAL_BURST
;
1028 if (tv_mode
->dda1_inc
)
1029 scctl1
|= TV_SC_DDA1_EN
;
1030 if (tv_mode
->dda2_inc
)
1031 scctl1
|= TV_SC_DDA2_EN
;
1032 if (tv_mode
->dda3_inc
)
1033 scctl1
|= TV_SC_DDA3_EN
;
1034 scctl1
|= tv_mode
->sc_reset
;
1036 scctl1
|= video_levels
->burst
<< TV_BURST_LEVEL_SHIFT
;
1037 scctl1
|= tv_mode
->dda1_inc
<< TV_SCDDA1_INC_SHIFT
;
1039 scctl2
= tv_mode
->dda2_size
<< TV_SCDDA2_SIZE_SHIFT
|
1040 tv_mode
->dda2_inc
<< TV_SCDDA2_INC_SHIFT
;
1042 scctl3
= tv_mode
->dda3_size
<< TV_SCDDA3_SIZE_SHIFT
|
1043 tv_mode
->dda3_inc
<< TV_SCDDA3_INC_SHIFT
;
1045 /* Enable two fixes for the chips that need them. */
1046 if (dev
->pci_device
< 0x2772)
1047 tv_ctl
|= TV_ENC_C0_FIX
| TV_ENC_SDP_FIX
;
1049 I915_WRITE(TV_H_CTL_1
, hctl1
);
1050 I915_WRITE(TV_H_CTL_2
, hctl2
);
1051 I915_WRITE(TV_H_CTL_3
, hctl3
);
1052 I915_WRITE(TV_V_CTL_1
, vctl1
);
1053 I915_WRITE(TV_V_CTL_2
, vctl2
);
1054 I915_WRITE(TV_V_CTL_3
, vctl3
);
1055 I915_WRITE(TV_V_CTL_4
, vctl4
);
1056 I915_WRITE(TV_V_CTL_5
, vctl5
);
1057 I915_WRITE(TV_V_CTL_6
, vctl6
);
1058 I915_WRITE(TV_V_CTL_7
, vctl7
);
1059 I915_WRITE(TV_SC_CTL_1
, scctl1
);
1060 I915_WRITE(TV_SC_CTL_2
, scctl2
);
1061 I915_WRITE(TV_SC_CTL_3
, scctl3
);
1063 if (color_conversion
) {
1064 I915_WRITE(TV_CSC_Y
, (color_conversion
->ry
<< 16) |
1065 color_conversion
->gy
);
1066 I915_WRITE(TV_CSC_Y2
, (color_conversion
->by
<< 16) |
1067 color_conversion
->ay
);
1068 I915_WRITE(TV_CSC_U
, (color_conversion
->ru
<< 16) |
1069 color_conversion
->gu
);
1070 I915_WRITE(TV_CSC_U2
, (color_conversion
->bu
<< 16) |
1071 color_conversion
->au
);
1072 I915_WRITE(TV_CSC_V
, (color_conversion
->rv
<< 16) |
1073 color_conversion
->gv
);
1074 I915_WRITE(TV_CSC_V2
, (color_conversion
->bv
<< 16) |
1075 color_conversion
->av
);
1078 if (INTEL_INFO(dev
)->gen
>= 4)
1079 I915_WRITE(TV_CLR_KNOBS
, 0x00404000);
1081 I915_WRITE(TV_CLR_KNOBS
, 0x00606000);
1084 I915_WRITE(TV_CLR_LEVEL
,
1085 ((video_levels
->black
<< TV_BLACK_LEVEL_SHIFT
) |
1086 (video_levels
->blank
<< TV_BLANK_LEVEL_SHIFT
)));
1088 int pipeconf_reg
= PIPECONF(pipe
);
1089 int dspcntr_reg
= DSPCNTR(intel_crtc
->plane
);
1090 int pipeconf
= I915_READ(pipeconf_reg
);
1091 int dspcntr
= I915_READ(dspcntr_reg
);
1092 int dspbase_reg
= DSPADDR(intel_crtc
->plane
);
1093 int xpos
= 0x0, ypos
= 0x0;
1094 unsigned int xsize
, ysize
;
1095 /* Pipe must be off here */
1096 I915_WRITE(dspcntr_reg
, dspcntr
& ~DISPLAY_PLANE_ENABLE
);
1097 /* Flush the plane changes */
1098 I915_WRITE(dspbase_reg
, I915_READ(dspbase_reg
));
1100 /* Wait for vblank for the disable to take effect */
1102 intel_wait_for_vblank(dev
, intel_crtc
->pipe
);
1104 I915_WRITE(pipeconf_reg
, pipeconf
& ~PIPECONF_ENABLE
);
1105 /* Wait for vblank for the disable to take effect. */
1106 intel_wait_for_pipe_off(dev
, intel_crtc
->pipe
);
1108 /* Filter ctl must be set before TV_WIN_SIZE */
1109 I915_WRITE(TV_FILTER_CTL_1
, TV_AUTO_SCALE
);
1110 xsize
= tv_mode
->hblank_start
- tv_mode
->hblank_end
;
1111 if (tv_mode
->progressive
)
1112 ysize
= tv_mode
->nbr_end
+ 1;
1114 ysize
= 2*tv_mode
->nbr_end
+ 1;
1116 xpos
+= intel_tv
->margin
[TV_MARGIN_LEFT
];
1117 ypos
+= intel_tv
->margin
[TV_MARGIN_TOP
];
1118 xsize
-= (intel_tv
->margin
[TV_MARGIN_LEFT
] +
1119 intel_tv
->margin
[TV_MARGIN_RIGHT
]);
1120 ysize
-= (intel_tv
->margin
[TV_MARGIN_TOP
] +
1121 intel_tv
->margin
[TV_MARGIN_BOTTOM
]);
1122 I915_WRITE(TV_WIN_POS
, (xpos
<<16)|ypos
);
1123 I915_WRITE(TV_WIN_SIZE
, (xsize
<<16)|ysize
);
1125 I915_WRITE(pipeconf_reg
, pipeconf
);
1126 I915_WRITE(dspcntr_reg
, dspcntr
);
1127 /* Flush the plane changes */
1128 I915_WRITE(dspbase_reg
, I915_READ(dspbase_reg
));
1132 for (i
= 0; i
< 60; i
++)
1133 I915_WRITE(TV_H_LUMA_0
+ (i
<<2), tv_mode
->filter_table
[j
++]);
1134 for (i
= 0; i
< 60; i
++)
1135 I915_WRITE(TV_H_CHROMA_0
+ (i
<<2), tv_mode
->filter_table
[j
++]);
1136 for (i
= 0; i
< 43; i
++)
1137 I915_WRITE(TV_V_LUMA_0
+ (i
<<2), tv_mode
->filter_table
[j
++]);
1138 for (i
= 0; i
< 43; i
++)
1139 I915_WRITE(TV_V_CHROMA_0
+ (i
<<2), tv_mode
->filter_table
[j
++]);
1140 I915_WRITE(TV_DAC
, I915_READ(TV_DAC
) & TV_DAC_SAVE
);
1141 I915_WRITE(TV_CTL
, tv_ctl
);
1144 static const struct drm_display_mode reported_modes
[] = {
1146 .name
= "NTSC 480i",
1149 .hsync_start
= 1368,
1154 .vsync_start
= 1027,
1157 .type
= DRM_MODE_TYPE_DRIVER
,
1162 * Detects TV presence by checking for load.
1164 * Requires that the current pipe's DPLL is active.
1166 * \return true if TV is connected.
1167 * \return false if TV is disconnected.
1170 intel_tv_detect_type(struct intel_tv
*intel_tv
,
1171 struct drm_connector
*connector
)
1173 struct drm_encoder
*encoder
= &intel_tv
->base
.base
;
1174 struct drm_crtc
*crtc
= encoder
->crtc
;
1175 struct intel_crtc
*intel_crtc
= to_intel_crtc(crtc
);
1176 struct drm_device
*dev
= encoder
->dev
;
1177 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
1178 unsigned long irqflags
;
1179 u32 tv_ctl
, save_tv_ctl
;
1180 u32 tv_dac
, save_tv_dac
;
1183 /* Disable TV interrupts around load detect or we'll recurse */
1184 if (connector
->polled
& DRM_CONNECTOR_POLL_HPD
) {
1185 spin_lock_irqsave(&dev_priv
->irq_lock
, irqflags
);
1186 i915_disable_pipestat(dev_priv
, 0,
1187 PIPE_HOTPLUG_INTERRUPT_ENABLE
|
1188 PIPE_HOTPLUG_TV_INTERRUPT_ENABLE
);
1189 spin_unlock_irqrestore(&dev_priv
->irq_lock
, irqflags
);
1192 save_tv_dac
= tv_dac
= I915_READ(TV_DAC
);
1193 save_tv_ctl
= tv_ctl
= I915_READ(TV_CTL
);
1195 /* Poll for TV detection */
1196 tv_ctl
&= ~(TV_ENC_ENABLE
| TV_TEST_MODE_MASK
);
1197 tv_ctl
|= TV_TEST_MODE_MONITOR_DETECT
;
1198 if (intel_crtc
->pipe
== 1)
1199 tv_ctl
|= TV_ENC_PIPEB_SELECT
;
1201 tv_ctl
&= ~TV_ENC_PIPEB_SELECT
;
1203 tv_dac
&= ~(TVDAC_SENSE_MASK
| DAC_A_MASK
| DAC_B_MASK
| DAC_C_MASK
);
1204 tv_dac
|= (TVDAC_STATE_CHG_EN
|
1215 * The TV sense state should be cleared to zero on cantiga platform. Otherwise
1216 * the TV is misdetected. This is hardware requirement.
1219 tv_dac
&= ~(TVDAC_STATE_CHG_EN
| TVDAC_A_SENSE_CTL
|
1220 TVDAC_B_SENSE_CTL
| TVDAC_C_SENSE_CTL
);
1222 I915_WRITE(TV_CTL
, tv_ctl
);
1223 I915_WRITE(TV_DAC
, tv_dac
);
1224 POSTING_READ(TV_DAC
);
1226 intel_wait_for_vblank(intel_tv
->base
.base
.dev
,
1227 to_intel_crtc(intel_tv
->base
.base
.crtc
)->pipe
);
1230 tv_dac
= I915_READ(TV_DAC
);
1231 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl
, tv_dac
);
1238 if ((tv_dac
& TVDAC_SENSE_MASK
) == (TVDAC_B_SENSE
| TVDAC_C_SENSE
)) {
1239 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1240 type
= DRM_MODE_CONNECTOR_Composite
;
1241 } else if ((tv_dac
& (TVDAC_A_SENSE
|TVDAC_B_SENSE
)) == TVDAC_A_SENSE
) {
1242 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1243 type
= DRM_MODE_CONNECTOR_SVIDEO
;
1244 } else if ((tv_dac
& TVDAC_SENSE_MASK
) == 0) {
1245 DRM_DEBUG_KMS("Detected Component TV connection\n");
1246 type
= DRM_MODE_CONNECTOR_Component
;
1248 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1252 I915_WRITE(TV_DAC
, save_tv_dac
& ~TVDAC_STATE_CHG_EN
);
1253 I915_WRITE(TV_CTL
, save_tv_ctl
);
1254 POSTING_READ(TV_CTL
);
1256 /* For unknown reasons the hw barfs if we don't do this vblank wait. */
1257 intel_wait_for_vblank(intel_tv
->base
.base
.dev
,
1258 to_intel_crtc(intel_tv
->base
.base
.crtc
)->pipe
);
1260 /* Restore interrupt config */
1261 if (connector
->polled
& DRM_CONNECTOR_POLL_HPD
) {
1262 spin_lock_irqsave(&dev_priv
->irq_lock
, irqflags
);
1263 i915_enable_pipestat(dev_priv
, 0,
1264 PIPE_HOTPLUG_INTERRUPT_ENABLE
|
1265 PIPE_HOTPLUG_TV_INTERRUPT_ENABLE
);
1266 spin_unlock_irqrestore(&dev_priv
->irq_lock
, irqflags
);
1273 * Here we set accurate tv format according to connector type
1274 * i.e Component TV should not be assigned by NTSC or PAL
1276 static void intel_tv_find_better_format(struct drm_connector
*connector
)
1278 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
1279 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
1282 if ((intel_tv
->type
== DRM_MODE_CONNECTOR_Component
) ==
1283 tv_mode
->component_only
)
1287 for (i
= 0; i
< sizeof(tv_modes
) / sizeof(*tv_modes
); i
++) {
1288 tv_mode
= tv_modes
+ i
;
1290 if ((intel_tv
->type
== DRM_MODE_CONNECTOR_Component
) ==
1291 tv_mode
->component_only
)
1295 intel_tv
->tv_format
= tv_mode
->name
;
1296 drm_connector_property_set_value(connector
,
1297 connector
->dev
->mode_config
.tv_mode_property
, i
);
1301 * Detect the TV connection.
1303 * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
1304 * we have a pipe programmed in order to probe the TV.
1306 static enum drm_connector_status
1307 intel_tv_detect(struct drm_connector
*connector
, bool force
)
1309 struct drm_display_mode mode
;
1310 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
1313 mode
= reported_modes
[0];
1316 struct intel_load_detect_pipe tmp
;
1318 if (intel_get_load_detect_pipe(connector
, &mode
, &tmp
)) {
1319 type
= intel_tv_detect_type(intel_tv
, connector
);
1320 intel_release_load_detect_pipe(connector
, &tmp
);
1322 return connector_status_unknown
;
1324 return connector
->status
;
1327 return connector_status_disconnected
;
1329 intel_tv
->type
= type
;
1330 intel_tv_find_better_format(connector
);
1332 return connector_status_connected
;
1335 static const struct input_res
{
1338 } input_res_table
[] = {
1339 {"640x480", 640, 480},
1340 {"800x600", 800, 600},
1341 {"1024x768", 1024, 768},
1342 {"1280x1024", 1280, 1024},
1343 {"848x480", 848, 480},
1344 {"1280x720", 1280, 720},
1345 {"1920x1080", 1920, 1080},
1349 * Chose preferred mode according to line number of TV format
1352 intel_tv_chose_preferred_modes(struct drm_connector
*connector
,
1353 struct drm_display_mode
*mode_ptr
)
1355 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
1356 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
1358 if (tv_mode
->nbr_end
< 480 && mode_ptr
->vdisplay
== 480)
1359 mode_ptr
->type
|= DRM_MODE_TYPE_PREFERRED
;
1360 else if (tv_mode
->nbr_end
> 480) {
1361 if (tv_mode
->progressive
== true && tv_mode
->nbr_end
< 720) {
1362 if (mode_ptr
->vdisplay
== 720)
1363 mode_ptr
->type
|= DRM_MODE_TYPE_PREFERRED
;
1364 } else if (mode_ptr
->vdisplay
== 1080)
1365 mode_ptr
->type
|= DRM_MODE_TYPE_PREFERRED
;
1370 * Stub get_modes function.
1372 * This should probably return a set of fixed modes, unless we can figure out
1373 * how to probe modes off of TV connections.
1377 intel_tv_get_modes(struct drm_connector
*connector
)
1379 struct drm_display_mode
*mode_ptr
;
1380 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
1381 const struct tv_mode
*tv_mode
= intel_tv_mode_find(intel_tv
);
1385 for (j
= 0; j
< ARRAY_SIZE(input_res_table
);
1387 const struct input_res
*input
= &input_res_table
[j
];
1388 unsigned int hactive_s
= input
->w
;
1389 unsigned int vactive_s
= input
->h
;
1391 if (tv_mode
->max_srcw
&& input
->w
> tv_mode
->max_srcw
)
1394 if (input
->w
> 1024 && (!tv_mode
->progressive
1395 && !tv_mode
->component_only
))
1398 mode_ptr
= drm_mode_create(connector
->dev
);
1401 strncpy(mode_ptr
->name
, input
->name
, DRM_DISPLAY_MODE_LEN
);
1403 mode_ptr
->hdisplay
= hactive_s
;
1404 mode_ptr
->hsync_start
= hactive_s
+ 1;
1405 mode_ptr
->hsync_end
= hactive_s
+ 64;
1406 if (mode_ptr
->hsync_end
<= mode_ptr
->hsync_start
)
1407 mode_ptr
->hsync_end
= mode_ptr
->hsync_start
+ 1;
1408 mode_ptr
->htotal
= hactive_s
+ 96;
1410 mode_ptr
->vdisplay
= vactive_s
;
1411 mode_ptr
->vsync_start
= vactive_s
+ 1;
1412 mode_ptr
->vsync_end
= vactive_s
+ 32;
1413 if (mode_ptr
->vsync_end
<= mode_ptr
->vsync_start
)
1414 mode_ptr
->vsync_end
= mode_ptr
->vsync_start
+ 1;
1415 mode_ptr
->vtotal
= vactive_s
+ 33;
1417 tmp
= (u64
) tv_mode
->refresh
* mode_ptr
->vtotal
;
1418 tmp
*= mode_ptr
->htotal
;
1419 tmp
= div_u64(tmp
, 1000000);
1420 mode_ptr
->clock
= (int) tmp
;
1422 mode_ptr
->type
= DRM_MODE_TYPE_DRIVER
;
1423 intel_tv_chose_preferred_modes(connector
, mode_ptr
);
1424 drm_mode_probed_add(connector
, mode_ptr
);
1432 intel_tv_destroy(struct drm_connector
*connector
)
1434 drm_sysfs_connector_remove(connector
);
1435 drm_connector_cleanup(connector
);
1441 intel_tv_set_property(struct drm_connector
*connector
, struct drm_property
*property
,
1444 struct drm_device
*dev
= connector
->dev
;
1445 struct intel_tv
*intel_tv
= intel_attached_tv(connector
);
1446 struct drm_crtc
*crtc
= intel_tv
->base
.base
.crtc
;
1448 bool changed
= false;
1450 ret
= drm_connector_property_set_value(connector
, property
, val
);
1454 if (property
== dev
->mode_config
.tv_left_margin_property
&&
1455 intel_tv
->margin
[TV_MARGIN_LEFT
] != val
) {
1456 intel_tv
->margin
[TV_MARGIN_LEFT
] = val
;
1458 } else if (property
== dev
->mode_config
.tv_right_margin_property
&&
1459 intel_tv
->margin
[TV_MARGIN_RIGHT
] != val
) {
1460 intel_tv
->margin
[TV_MARGIN_RIGHT
] = val
;
1462 } else if (property
== dev
->mode_config
.tv_top_margin_property
&&
1463 intel_tv
->margin
[TV_MARGIN_TOP
] != val
) {
1464 intel_tv
->margin
[TV_MARGIN_TOP
] = val
;
1466 } else if (property
== dev
->mode_config
.tv_bottom_margin_property
&&
1467 intel_tv
->margin
[TV_MARGIN_BOTTOM
] != val
) {
1468 intel_tv
->margin
[TV_MARGIN_BOTTOM
] = val
;
1470 } else if (property
== dev
->mode_config
.tv_mode_property
) {
1471 if (val
>= ARRAY_SIZE(tv_modes
)) {
1475 if (!strcmp(intel_tv
->tv_format
, tv_modes
[val
].name
))
1478 intel_tv
->tv_format
= tv_modes
[val
].name
;
1485 if (changed
&& crtc
)
1486 intel_set_mode(crtc
, &crtc
->mode
,
1487 crtc
->x
, crtc
->y
, crtc
->fb
);
1492 static const struct drm_encoder_helper_funcs intel_tv_helper_funcs
= {
1493 .mode_fixup
= intel_tv_mode_fixup
,
1494 .mode_set
= intel_tv_mode_set
,
1495 .disable
= intel_encoder_noop
,
1498 static const struct drm_connector_funcs intel_tv_connector_funcs
= {
1499 .dpms
= intel_connector_dpms
,
1500 .detect
= intel_tv_detect
,
1501 .destroy
= intel_tv_destroy
,
1502 .set_property
= intel_tv_set_property
,
1503 .fill_modes
= drm_helper_probe_single_connector_modes
,
1506 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs
= {
1507 .mode_valid
= intel_tv_mode_valid
,
1508 .get_modes
= intel_tv_get_modes
,
1509 .best_encoder
= intel_best_encoder
,
1512 static const struct drm_encoder_funcs intel_tv_enc_funcs
= {
1513 .destroy
= intel_encoder_destroy
,
1517 * Enumerate the child dev array parsed from VBT to check whether
1518 * the integrated TV is present.
1519 * If it is present, return 1.
1520 * If it is not present, return false.
1521 * If no child dev is parsed from VBT, it assumes that the TV is present.
1523 static int tv_is_present_in_vbt(struct drm_device
*dev
)
1525 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
1526 struct child_device_config
*p_child
;
1529 if (!dev_priv
->child_dev_num
)
1533 for (i
= 0; i
< dev_priv
->child_dev_num
; i
++) {
1534 p_child
= dev_priv
->child_dev
+ i
;
1536 * If the device type is not TV, continue.
1538 if (p_child
->device_type
!= DEVICE_TYPE_INT_TV
&&
1539 p_child
->device_type
!= DEVICE_TYPE_TV
)
1541 /* Only when the addin_offset is non-zero, it is regarded
1544 if (p_child
->addin_offset
) {
1553 intel_tv_init(struct drm_device
*dev
)
1555 struct drm_i915_private
*dev_priv
= dev
->dev_private
;
1556 struct drm_connector
*connector
;
1557 struct intel_tv
*intel_tv
;
1558 struct intel_encoder
*intel_encoder
;
1559 struct intel_connector
*intel_connector
;
1560 u32 tv_dac_on
, tv_dac_off
, save_tv_dac
;
1561 char *tv_format_names
[ARRAY_SIZE(tv_modes
)];
1562 int i
, initial_mode
= 0;
1564 if ((I915_READ(TV_CTL
) & TV_FUSE_STATE_MASK
) == TV_FUSE_STATE_DISABLED
)
1567 if (!tv_is_present_in_vbt(dev
)) {
1568 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1571 /* Even if we have an encoder we may not have a connector */
1572 if (!dev_priv
->int_tv_support
)
1576 * Sanity check the TV output by checking to see if the
1577 * DAC register holds a value
1579 save_tv_dac
= I915_READ(TV_DAC
);
1581 I915_WRITE(TV_DAC
, save_tv_dac
| TVDAC_STATE_CHG_EN
);
1582 tv_dac_on
= I915_READ(TV_DAC
);
1584 I915_WRITE(TV_DAC
, save_tv_dac
& ~TVDAC_STATE_CHG_EN
);
1585 tv_dac_off
= I915_READ(TV_DAC
);
1587 I915_WRITE(TV_DAC
, save_tv_dac
);
1590 * If the register does not hold the state change enable
1591 * bit, (either as a 0 or a 1), assume it doesn't really
1594 if ((tv_dac_on
& TVDAC_STATE_CHG_EN
) == 0 ||
1595 (tv_dac_off
& TVDAC_STATE_CHG_EN
) != 0)
1598 intel_tv
= kzalloc(sizeof(struct intel_tv
), GFP_KERNEL
);
1603 intel_connector
= kzalloc(sizeof(struct intel_connector
), GFP_KERNEL
);
1604 if (!intel_connector
) {
1609 intel_encoder
= &intel_tv
->base
;
1610 connector
= &intel_connector
->base
;
1612 /* The documentation, for the older chipsets at least, recommend
1613 * using a polling method rather than hotplug detection for TVs.
1614 * This is because in order to perform the hotplug detection, the PLLs
1615 * for the TV must be kept alive increasing power drain and starving
1616 * bandwidth from other encoders. Notably for instance, it causes
1617 * pipe underruns on Crestline when this encoder is supposedly idle.
1619 * More recent chipsets favour HDMI rather than integrated S-Video.
1621 connector
->polled
= DRM_CONNECTOR_POLL_CONNECT
;
1623 drm_connector_init(dev
, connector
, &intel_tv_connector_funcs
,
1624 DRM_MODE_CONNECTOR_SVIDEO
);
1626 drm_encoder_init(dev
, &intel_encoder
->base
, &intel_tv_enc_funcs
,
1627 DRM_MODE_ENCODER_TVDAC
);
1629 intel_encoder
->enable
= intel_enable_tv
;
1630 intel_encoder
->disable
= intel_disable_tv
;
1631 intel_encoder
->get_hw_state
= intel_tv_get_hw_state
;
1632 intel_connector
->get_hw_state
= intel_connector_get_hw_state
;
1634 intel_connector_attach_encoder(intel_connector
, intel_encoder
);
1635 intel_encoder
->type
= INTEL_OUTPUT_TVOUT
;
1636 intel_encoder
->crtc_mask
= (1 << 0) | (1 << 1);
1637 intel_encoder
->cloneable
= false;
1638 intel_encoder
->base
.possible_crtcs
= ((1 << 0) | (1 << 1));
1639 intel_encoder
->base
.possible_clones
= (1 << INTEL_OUTPUT_TVOUT
);
1640 intel_tv
->type
= DRM_MODE_CONNECTOR_Unknown
;
1642 /* BIOS margin values */
1643 intel_tv
->margin
[TV_MARGIN_LEFT
] = 54;
1644 intel_tv
->margin
[TV_MARGIN_TOP
] = 36;
1645 intel_tv
->margin
[TV_MARGIN_RIGHT
] = 46;
1646 intel_tv
->margin
[TV_MARGIN_BOTTOM
] = 37;
1648 intel_tv
->tv_format
= tv_modes
[initial_mode
].name
;
1650 drm_encoder_helper_add(&intel_encoder
->base
, &intel_tv_helper_funcs
);
1651 drm_connector_helper_add(connector
, &intel_tv_connector_helper_funcs
);
1652 connector
->interlace_allowed
= false;
1653 connector
->doublescan_allowed
= false;
1655 /* Create TV properties then attach current values */
1656 for (i
= 0; i
< ARRAY_SIZE(tv_modes
); i
++)
1657 tv_format_names
[i
] = (char *)tv_modes
[i
].name
;
1658 drm_mode_create_tv_properties(dev
,
1659 ARRAY_SIZE(tv_modes
),
1662 drm_connector_attach_property(connector
, dev
->mode_config
.tv_mode_property
,
1664 drm_connector_attach_property(connector
,
1665 dev
->mode_config
.tv_left_margin_property
,
1666 intel_tv
->margin
[TV_MARGIN_LEFT
]);
1667 drm_connector_attach_property(connector
,
1668 dev
->mode_config
.tv_top_margin_property
,
1669 intel_tv
->margin
[TV_MARGIN_TOP
]);
1670 drm_connector_attach_property(connector
,
1671 dev
->mode_config
.tv_right_margin_property
,
1672 intel_tv
->margin
[TV_MARGIN_RIGHT
]);
1673 drm_connector_attach_property(connector
,
1674 dev
->mode_config
.tv_bottom_margin_property
,
1675 intel_tv
->margin
[TV_MARGIN_BOTTOM
]);
1676 drm_sysfs_connector_add(connector
);