2 * Copyright © 2006 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 * Eric Anholt <eric@anholt.net>
29 * Integrated TV-out support for the 915GM and 945GM.
36 #include "intel_drv.h"
41 TV_MARGIN_LEFT, TV_MARGIN_TOP,
42 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
45 /** Private structure for the integrated TV support */
46 struct intel_tv_priv {
60 u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
68 u32 save_TV_CLR_KNOBS;
69 u32 save_TV_CLR_LEVEL;
72 u32 save_TV_FILTER_CTL_1;
73 u32 save_TV_FILTER_CTL_2;
74 u32 save_TV_FILTER_CTL_3;
76 u32 save_TV_H_LUMA[60];
77 u32 save_TV_H_CHROMA[60];
78 u32 save_TV_V_LUMA[43];
79 u32 save_TV_V_CHROMA[43];
86 int blank, black, burst;
89 struct color_conversion {
95 static const u32 filter_table[] = {
96 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
97 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
98 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
99 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
100 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
101 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
102 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
103 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
104 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
105 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
106 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
107 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
108 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
109 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
110 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
111 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
112 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
113 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
114 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
115 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
116 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
117 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
118 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
119 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
120 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
121 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
122 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
123 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
124 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
125 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
126 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
127 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
128 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
129 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
130 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
131 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
132 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
133 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
134 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
135 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
136 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
137 0x2D002CC0, 0x30003640, 0x2D0036C0,
138 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
139 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
140 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
141 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
142 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
143 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
144 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
145 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
146 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
147 0x28003100, 0x28002F00, 0x00003100,
151 * Color conversion values have 3 separate fixed point formats:
153 * 10 bit fields (ay, au)
154 * 1.9 fixed point (b.bbbbbbbbb)
155 * 11 bit fields (ry, by, ru, gu, gv)
156 * exp.mantissa (ee.mmmmmmmmm)
157 * ee = 00 = 10^-1 (0.mmmmmmmmm)
158 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
159 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
160 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
161 * 12 bit fields (gy, rv, bu)
162 * exp.mantissa (eee.mmmmmmmmm)
163 * eee = 000 = 10^-1 (0.mmmmmmmmm)
164 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
165 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
166 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
167 * eee = 100 = reserved
168 * eee = 101 = reserved
169 * eee = 110 = reserved
170 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
172 * Saturation and contrast are 8 bits, with their own representation:
173 * 8 bit field (saturation, contrast)
174 * exp.mantissa (ee.mmmmmm)
175 * ee = 00 = 10^-1 (0.mmmmmm)
176 * ee = 01 = 10^0 (m.mmmmm)
177 * ee = 10 = 10^1 (mm.mmmm)
178 * ee = 11 = 10^2 (mmm.mmm)
180 * Simple conversion function:
183 * float_to_csc_11(float f)
196 * for (exp = 0; exp < 3 && f < 0.5; exp++)
198 * mant = (f * (1 << 9) + 0.5);
199 * if (mant >= (1 << 9))
200 * mant = (1 << 9) - 1;
202 * ret = (exp << 9) | mant;
208 * Behold, magic numbers! If we plant them they might grow a big
209 * s-video cable to the sky... or something.
211 * Pre-converted to appropriate hex value.
215 * PAL & NTSC values for composite & s-video connections
217 static const struct color_conversion ntsc_m_csc_composite = {
218 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
219 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
220 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
223 static const struct video_levels ntsc_m_levels_composite = {
224 .blank = 225, .black = 267, .burst = 113,
227 static const struct color_conversion ntsc_m_csc_svideo = {
228 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
229 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
230 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
233 static const struct video_levels ntsc_m_levels_svideo = {
234 .blank = 266, .black = 316, .burst = 133,
237 static const struct color_conversion ntsc_j_csc_composite = {
238 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
239 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
240 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
243 static const struct video_levels ntsc_j_levels_composite = {
244 .blank = 225, .black = 225, .burst = 113,
247 static const struct color_conversion ntsc_j_csc_svideo = {
248 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
249 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
250 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
253 static const struct video_levels ntsc_j_levels_svideo = {
254 .blank = 266, .black = 266, .burst = 133,
257 static const struct color_conversion pal_csc_composite = {
258 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
259 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
260 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
263 static const struct video_levels pal_levels_composite = {
264 .blank = 237, .black = 237, .burst = 118,
267 static const struct color_conversion pal_csc_svideo = {
268 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
269 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
270 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
273 static const struct video_levels pal_levels_svideo = {
274 .blank = 280, .black = 280, .burst = 139,
277 static const struct color_conversion pal_m_csc_composite = {
278 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
279 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
280 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
283 static const struct video_levels pal_m_levels_composite = {
284 .blank = 225, .black = 267, .burst = 113,
287 static const struct color_conversion pal_m_csc_svideo = {
288 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
289 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
290 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
293 static const struct video_levels pal_m_levels_svideo = {
294 .blank = 266, .black = 316, .burst = 133,
297 static const struct color_conversion pal_n_csc_composite = {
298 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
299 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
300 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
303 static const struct video_levels pal_n_levels_composite = {
304 .blank = 225, .black = 267, .burst = 118,
307 static const struct color_conversion pal_n_csc_svideo = {
308 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
309 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
310 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
313 static const struct video_levels pal_n_levels_svideo = {
314 .blank = 266, .black = 316, .burst = 139,
318 * Component connections
320 static const struct color_conversion sdtv_csc_yprpb = {
321 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
322 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
323 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
326 static const struct color_conversion sdtv_csc_rgb = {
327 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
328 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
329 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
332 static const struct color_conversion hdtv_csc_yprpb = {
333 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
334 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
335 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
338 static const struct color_conversion hdtv_csc_rgb = {
339 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
340 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
341 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
344 static const struct video_levels component_levels = {
345 .blank = 279, .black = 279, .burst = 0,
352 int refresh; /* in millihertz (for precision) */
354 int hsync_end, hblank_start, hblank_end, htotal;
355 bool progressive, trilevel_sync, component_only;
356 int vsync_start_f1, vsync_start_f2, vsync_len;
358 int veq_start_f1, veq_start_f2, veq_len;
359 int vi_end_f1, vi_end_f2, nbr_end;
361 int hburst_start, hburst_len;
362 int vburst_start_f1, vburst_end_f1;
363 int vburst_start_f2, vburst_end_f2;
364 int vburst_start_f3, vburst_end_f3;
365 int vburst_start_f4, vburst_end_f4;
367 * subcarrier programming
369 int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
375 const struct video_levels *composite_levels, *svideo_levels;
376 const struct color_conversion *composite_color, *svideo_color;
377 const u32 *filter_table;
385 * I think this works as follows:
387 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
389 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
392 * dda1_ideal = subcarrier/pixel * 4096
393 * dda1_inc = floor (dda1_ideal)
394 * dda2 = dda1_ideal - dda1_inc
396 * then pick a ratio for dda2 that gives the closest approximation. If
397 * you can't get close enough, you can play with dda3 as well. This
398 * seems likely to happen when dda2 is small as the jumps would be larger
402 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
404 * The constants below were all computed using a 107.520MHz clock
408 * Register programming values for TV modes.
410 * These values account for -1s required.
413 const static struct tv_mode tv_modes[] = {
418 .oversample = TV_OVERSAMPLE_8X,
420 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
422 .hsync_end = 64, .hblank_end = 124,
423 .hblank_start = 836, .htotal = 857,
425 .progressive = FALSE, .trilevel_sync = FALSE,
427 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
430 .veq_ena = TRUE, .veq_start_f1 = 0,
431 .veq_start_f2 = 1, .veq_len = 18,
433 .vi_end_f1 = 20, .vi_end_f2 = 21,
437 .hburst_start = 72, .hburst_len = 34,
438 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
439 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
440 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
441 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
443 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
445 .dda2_inc = 7624, .dda2_size = 20013,
446 .dda3_inc = 0, .dda3_size = 0,
447 .sc_reset = TV_SC_RESET_EVERY_4,
450 .composite_levels = &ntsc_m_levels_composite,
451 .composite_color = &ntsc_m_csc_composite,
452 .svideo_levels = &ntsc_m_levels_svideo,
453 .svideo_color = &ntsc_m_csc_svideo,
455 .filter_table = filter_table,
461 .oversample = TV_OVERSAMPLE_8X,
463 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
464 .hsync_end = 64, .hblank_end = 124,
465 .hblank_start = 836, .htotal = 857,
467 .progressive = FALSE, .trilevel_sync = FALSE,
469 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
472 .veq_ena = TRUE, .veq_start_f1 = 0,
473 .veq_start_f2 = 1, .veq_len = 18,
475 .vi_end_f1 = 20, .vi_end_f2 = 21,
479 .hburst_start = 72, .hburst_len = 34,
480 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
481 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
482 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
483 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
485 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
487 .dda2_inc = 18557, .dda2_size = 20625,
488 .dda3_inc = 0, .dda3_size = 0,
489 .sc_reset = TV_SC_RESET_EVERY_8,
492 .composite_levels = &ntsc_m_levels_composite,
493 .composite_color = &ntsc_m_csc_composite,
494 .svideo_levels = &ntsc_m_levels_svideo,
495 .svideo_color = &ntsc_m_csc_svideo,
497 .filter_table = filter_table,
503 .oversample = TV_OVERSAMPLE_8X,
506 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
507 .hsync_end = 64, .hblank_end = 124,
508 .hblank_start = 836, .htotal = 857,
510 .progressive = FALSE, .trilevel_sync = FALSE,
512 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
515 .veq_ena = TRUE, .veq_start_f1 = 0,
516 .veq_start_f2 = 1, .veq_len = 18,
518 .vi_end_f1 = 20, .vi_end_f2 = 21,
522 .hburst_start = 72, .hburst_len = 34,
523 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
524 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
525 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
526 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
528 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
530 .dda2_inc = 7624, .dda2_size = 20013,
531 .dda3_inc = 0, .dda3_size = 0,
532 .sc_reset = TV_SC_RESET_EVERY_4,
535 .composite_levels = &ntsc_j_levels_composite,
536 .composite_color = &ntsc_j_csc_composite,
537 .svideo_levels = &ntsc_j_levels_svideo,
538 .svideo_color = &ntsc_j_csc_svideo,
540 .filter_table = filter_table,
546 .oversample = TV_OVERSAMPLE_8X,
549 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
550 .hsync_end = 64, .hblank_end = 124,
551 .hblank_start = 836, .htotal = 857,
553 .progressive = FALSE, .trilevel_sync = FALSE,
555 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
558 .veq_ena = TRUE, .veq_start_f1 = 0,
559 .veq_start_f2 = 1, .veq_len = 18,
561 .vi_end_f1 = 20, .vi_end_f2 = 21,
565 .hburst_start = 72, .hburst_len = 34,
566 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
567 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
568 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
569 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
571 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
573 .dda2_inc = 7624, .dda2_size = 20013,
574 .dda3_inc = 0, .dda3_size = 0,
575 .sc_reset = TV_SC_RESET_EVERY_4,
578 .composite_levels = &pal_m_levels_composite,
579 .composite_color = &pal_m_csc_composite,
580 .svideo_levels = &pal_m_levels_svideo,
581 .svideo_color = &pal_m_csc_svideo,
583 .filter_table = filter_table,
586 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
590 .oversample = TV_OVERSAMPLE_8X,
593 .hsync_end = 64, .hblank_end = 128,
594 .hblank_start = 844, .htotal = 863,
596 .progressive = FALSE, .trilevel_sync = FALSE,
599 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
602 .veq_ena = TRUE, .veq_start_f1 = 0,
603 .veq_start_f2 = 1, .veq_len = 18,
605 .vi_end_f1 = 24, .vi_end_f2 = 25,
609 .hburst_start = 73, .hburst_len = 34,
610 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
611 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
612 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
613 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
616 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
618 .dda2_inc = 18557, .dda2_size = 20625,
619 .dda3_inc = 0, .dda3_size = 0,
620 .sc_reset = TV_SC_RESET_EVERY_8,
623 .composite_levels = &pal_n_levels_composite,
624 .composite_color = &pal_n_csc_composite,
625 .svideo_levels = &pal_n_levels_svideo,
626 .svideo_color = &pal_n_csc_svideo,
628 .filter_table = filter_table,
631 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
635 .oversample = TV_OVERSAMPLE_8X,
638 .hsync_end = 64, .hblank_end = 128,
639 .hblank_start = 844, .htotal = 863,
641 .progressive = FALSE, .trilevel_sync = FALSE,
643 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
646 .veq_ena = TRUE, .veq_start_f1 = 0,
647 .veq_start_f2 = 1, .veq_len = 15,
649 .vi_end_f1 = 24, .vi_end_f2 = 25,
653 .hburst_start = 73, .hburst_len = 32,
654 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
655 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
656 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
657 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
659 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
661 .dda2_inc = 18557, .dda2_size = 20625,
662 .dda3_inc = 0, .dda3_size = 0,
663 .sc_reset = TV_SC_RESET_EVERY_8,
666 .composite_levels = &pal_levels_composite,
667 .composite_color = &pal_csc_composite,
668 .svideo_levels = &pal_levels_svideo,
669 .svideo_color = &pal_csc_svideo,
671 .filter_table = filter_table,
674 .name = "480p@59.94Hz",
677 .oversample = TV_OVERSAMPLE_4X,
680 .hsync_end = 64, .hblank_end = 122,
681 .hblank_start = 842, .htotal = 857,
683 .progressive = TRUE,.trilevel_sync = FALSE,
685 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
690 .vi_end_f1 = 44, .vi_end_f2 = 44,
695 .filter_table = filter_table,
701 .oversample = TV_OVERSAMPLE_4X,
704 .hsync_end = 64, .hblank_end = 122,
705 .hblank_start = 842, .htotal = 856,
707 .progressive = TRUE,.trilevel_sync = FALSE,
709 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
714 .vi_end_f1 = 44, .vi_end_f2 = 44,
719 .filter_table = filter_table,
725 .oversample = TV_OVERSAMPLE_4X,
728 .hsync_end = 64, .hblank_end = 139,
729 .hblank_start = 859, .htotal = 863,
731 .progressive = TRUE, .trilevel_sync = FALSE,
733 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
738 .vi_end_f1 = 48, .vi_end_f2 = 48,
743 .filter_table = filter_table,
749 .oversample = TV_OVERSAMPLE_2X,
752 .hsync_end = 80, .hblank_end = 300,
753 .hblank_start = 1580, .htotal = 1649,
755 .progressive = TRUE, .trilevel_sync = TRUE,
757 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
762 .vi_end_f1 = 29, .vi_end_f2 = 29,
767 .filter_table = filter_table,
770 .name = "720p@59.94Hz",
773 .oversample = TV_OVERSAMPLE_2X,
776 .hsync_end = 80, .hblank_end = 300,
777 .hblank_start = 1580, .htotal = 1651,
779 .progressive = TRUE, .trilevel_sync = TRUE,
781 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
786 .vi_end_f1 = 29, .vi_end_f2 = 29,
791 .filter_table = filter_table,
797 .oversample = TV_OVERSAMPLE_2X,
800 .hsync_end = 80, .hblank_end = 300,
801 .hblank_start = 1580, .htotal = 1979,
803 .progressive = TRUE, .trilevel_sync = TRUE,
805 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
810 .vi_end_f1 = 29, .vi_end_f2 = 29,
815 .filter_table = filter_table,
819 .name = "1080i@50Hz",
822 .oversample = TV_OVERSAMPLE_2X,
825 .hsync_end = 88, .hblank_end = 235,
826 .hblank_start = 2155, .htotal = 2639,
828 .progressive = FALSE, .trilevel_sync = TRUE,
830 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
833 .veq_ena = TRUE, .veq_start_f1 = 4,
834 .veq_start_f2 = 4, .veq_len = 10,
837 .vi_end_f1 = 21, .vi_end_f2 = 22,
842 .filter_table = filter_table,
845 .name = "1080i@60Hz",
848 .oversample = TV_OVERSAMPLE_2X,
851 .hsync_end = 88, .hblank_end = 235,
852 .hblank_start = 2155, .htotal = 2199,
854 .progressive = FALSE, .trilevel_sync = TRUE,
856 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
859 .veq_ena = TRUE, .veq_start_f1 = 4,
860 .veq_start_f2 = 4, .veq_len = 10,
863 .vi_end_f1 = 21, .vi_end_f2 = 22,
868 .filter_table = filter_table,
871 .name = "1080i@59.94Hz",
874 .oversample = TV_OVERSAMPLE_2X,
877 .hsync_end = 88, .hblank_end = 235,
878 .hblank_start = 2155, .htotal = 2200,
880 .progressive = FALSE, .trilevel_sync = TRUE,
882 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
885 .veq_ena = TRUE, .veq_start_f1 = 4,
886 .veq_start_f2 = 4, .veq_len = 10,
889 .vi_end_f1 = 21, .vi_end_f2 = 22,
894 .filter_table = filter_table,
898 #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
901 intel_tv_dpms(struct drm_encoder *encoder, int mode)
903 struct drm_device *dev = encoder->dev;
904 struct drm_i915_private *dev_priv = dev->dev_private;
908 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
910 case DPMSModeStandby:
911 case DPMSModeSuspend:
913 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
919 intel_tv_save(struct drm_connector *connector)
921 struct drm_device *dev = connector->dev;
922 struct drm_i915_private *dev_priv = dev->dev_private;
923 struct intel_output *intel_output = to_intel_output(connector);
924 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
927 tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
928 tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2);
929 tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3);
930 tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1);
931 tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2);
932 tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3);
933 tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4);
934 tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5);
935 tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6);
936 tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7);
937 tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1);
938 tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2);
939 tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3);
941 tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y);
942 tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2);
943 tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U);
944 tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2);
945 tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V);
946 tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2);
947 tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS);
948 tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL);
949 tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS);
950 tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE);
951 tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1);
952 tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2);
953 tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3);
955 for (i = 0; i < 60; i++)
956 tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2));
957 for (i = 0; i < 60; i++)
958 tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2));
959 for (i = 0; i < 43; i++)
960 tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2));
961 for (i = 0; i < 43; i++)
962 tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2));
964 tv_priv->save_TV_DAC = I915_READ(TV_DAC);
965 tv_priv->save_TV_CTL = I915_READ(TV_CTL);
969 intel_tv_restore(struct drm_connector *connector)
971 struct drm_device *dev = connector->dev;
972 struct drm_i915_private *dev_priv = dev->dev_private;
973 struct intel_output *intel_output = to_intel_output(connector);
974 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
975 struct drm_crtc *crtc = connector->encoder->crtc;
976 struct intel_crtc *intel_crtc;
979 /* FIXME: No CRTC? */
983 intel_crtc = to_intel_crtc(crtc);
984 I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1);
985 I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2);
986 I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3);
987 I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1);
988 I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2);
989 I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3);
990 I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4);
991 I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5);
992 I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6);
993 I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7);
994 I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1);
995 I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2);
996 I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3);
998 I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y);
999 I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2);
1000 I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U);
1001 I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2);
1002 I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V);
1003 I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2);
1004 I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS);
1005 I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL);
1008 int pipeconf_reg = (intel_crtc->pipe == 0) ?
1009 PIPEACONF : PIPEBCONF;
1010 int dspcntr_reg = (intel_crtc->plane == 0) ?
1011 DSPACNTR : DSPBCNTR;
1012 int pipeconf = I915_READ(pipeconf_reg);
1013 int dspcntr = I915_READ(dspcntr_reg);
1014 int dspbase_reg = (intel_crtc->plane == 0) ?
1015 DSPAADDR : DSPBADDR;
1016 /* Pipe must be off here */
1017 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1018 /* Flush the plane changes */
1019 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1021 if (!IS_I9XX(dev)) {
1022 /* Wait for vblank for the disable to take effect */
1023 intel_wait_for_vblank(dev);
1026 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1027 /* Wait for vblank for the disable to take effect. */
1028 intel_wait_for_vblank(dev);
1030 /* Filter ctl must be set before TV_WIN_SIZE */
1031 I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1);
1032 I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2);
1033 I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3);
1034 I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS);
1035 I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE);
1036 I915_WRITE(pipeconf_reg, pipeconf);
1037 I915_WRITE(dspcntr_reg, dspcntr);
1038 /* Flush the plane changes */
1039 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1042 for (i = 0; i < 60; i++)
1043 I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]);
1044 for (i = 0; i < 60; i++)
1045 I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]);
1046 for (i = 0; i < 43; i++)
1047 I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]);
1048 for (i = 0; i < 43; i++)
1049 I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]);
1051 I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
1052 I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
1055 static const struct tv_mode *
1056 intel_tv_mode_lookup (char *tv_format)
1060 for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
1061 const struct tv_mode *tv_mode = &tv_modes[i];
1063 if (!strcmp(tv_format, tv_mode->name))
1069 static const struct tv_mode *
1070 intel_tv_mode_find (struct intel_output *intel_output)
1072 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1074 return intel_tv_mode_lookup(tv_priv->tv_format);
1077 static enum drm_mode_status
1078 intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
1080 struct intel_output *intel_output = to_intel_output(connector);
1081 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
1083 /* Ensure TV refresh is close to desired refresh */
1084 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
1086 return MODE_CLOCK_RANGE;
1091 intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
1092 struct drm_display_mode *adjusted_mode)
1094 struct drm_device *dev = encoder->dev;
1095 struct drm_mode_config *drm_config = &dev->mode_config;
1096 struct intel_output *intel_output = enc_to_intel_output(encoder);
1097 const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output);
1098 struct drm_encoder *other_encoder;
1103 /* FIXME: lock encoder list */
1104 list_for_each_entry(other_encoder, &drm_config->encoder_list, head) {
1105 if (other_encoder != encoder &&
1106 other_encoder->crtc == encoder->crtc)
1110 adjusted_mode->clock = tv_mode->clock;
1115 intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
1116 struct drm_display_mode *adjusted_mode)
1118 struct drm_device *dev = encoder->dev;
1119 struct drm_i915_private *dev_priv = dev->dev_private;
1120 struct drm_crtc *crtc = encoder->crtc;
1121 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1122 struct intel_output *intel_output = enc_to_intel_output(encoder);
1123 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1124 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
1126 u32 hctl1, hctl2, hctl3;
1127 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1128 u32 scctl1, scctl2, scctl3;
1130 const struct video_levels *video_levels;
1131 const struct color_conversion *color_conversion;
1135 return; /* can't happen (mode_prepare prevents this) */
1139 switch (tv_priv->type) {
1141 case DRM_MODE_CONNECTOR_Unknown:
1142 case DRM_MODE_CONNECTOR_Composite:
1143 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1144 video_levels = tv_mode->composite_levels;
1145 color_conversion = tv_mode->composite_color;
1146 burst_ena = tv_mode->burst_ena;
1148 case DRM_MODE_CONNECTOR_Component:
1149 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1150 video_levels = &component_levels;
1151 if (tv_mode->burst_ena)
1152 color_conversion = &sdtv_csc_yprpb;
1154 color_conversion = &hdtv_csc_yprpb;
1157 case DRM_MODE_CONNECTOR_SVIDEO:
1158 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1159 video_levels = tv_mode->svideo_levels;
1160 color_conversion = tv_mode->svideo_color;
1161 burst_ena = tv_mode->burst_ena;
1164 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1165 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1167 hctl2 = (tv_mode->hburst_start << 16) |
1168 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1171 hctl2 |= TV_BURST_ENA;
1173 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1174 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1176 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1177 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1178 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1180 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1181 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1182 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1184 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1185 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1186 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1188 if (tv_mode->veq_ena)
1189 vctl3 |= TV_EQUAL_ENA;
1191 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1192 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1194 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1195 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1197 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1198 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1200 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1201 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1203 if (intel_crtc->pipe == 1)
1204 tv_ctl |= TV_ENC_PIPEB_SELECT;
1205 tv_ctl |= tv_mode->oversample;
1207 if (tv_mode->progressive)
1208 tv_ctl |= TV_PROGRESSIVE;
1209 if (tv_mode->trilevel_sync)
1210 tv_ctl |= TV_TRILEVEL_SYNC;
1211 if (tv_mode->pal_burst)
1212 tv_ctl |= TV_PAL_BURST;
1214 /* dda1 implies valid video levels */
1215 if (tv_mode->dda1_inc) {
1216 scctl1 |= TV_SC_DDA1_EN;
1217 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1220 if (tv_mode->dda2_inc)
1221 scctl1 |= TV_SC_DDA2_EN;
1223 if (tv_mode->dda3_inc)
1224 scctl1 |= TV_SC_DDA3_EN;
1226 scctl1 |= tv_mode->sc_reset;
1227 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1229 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1230 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1232 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1233 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1235 /* Enable two fixes for the chips that need them. */
1236 if (dev->pci_device < 0x2772)
1237 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1239 I915_WRITE(TV_H_CTL_1, hctl1);
1240 I915_WRITE(TV_H_CTL_2, hctl2);
1241 I915_WRITE(TV_H_CTL_3, hctl3);
1242 I915_WRITE(TV_V_CTL_1, vctl1);
1243 I915_WRITE(TV_V_CTL_2, vctl2);
1244 I915_WRITE(TV_V_CTL_3, vctl3);
1245 I915_WRITE(TV_V_CTL_4, vctl4);
1246 I915_WRITE(TV_V_CTL_5, vctl5);
1247 I915_WRITE(TV_V_CTL_6, vctl6);
1248 I915_WRITE(TV_V_CTL_7, vctl7);
1249 I915_WRITE(TV_SC_CTL_1, scctl1);
1250 I915_WRITE(TV_SC_CTL_2, scctl2);
1251 I915_WRITE(TV_SC_CTL_3, scctl3);
1253 if (color_conversion) {
1254 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1255 color_conversion->gy);
1256 I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
1257 color_conversion->ay);
1258 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1259 color_conversion->gu);
1260 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1261 color_conversion->au);
1262 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1263 color_conversion->gv);
1264 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1265 color_conversion->av);
1268 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1270 I915_WRITE(TV_CLR_LEVEL,
1271 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1272 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1274 int pipeconf_reg = (intel_crtc->pipe == 0) ?
1275 PIPEACONF : PIPEBCONF;
1276 int dspcntr_reg = (intel_crtc->plane == 0) ?
1277 DSPACNTR : DSPBCNTR;
1278 int pipeconf = I915_READ(pipeconf_reg);
1279 int dspcntr = I915_READ(dspcntr_reg);
1280 int dspbase_reg = (intel_crtc->plane == 0) ?
1281 DSPAADDR : DSPBADDR;
1282 int xpos = 0x0, ypos = 0x0;
1283 unsigned int xsize, ysize;
1284 /* Pipe must be off here */
1285 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1286 /* Flush the plane changes */
1287 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1289 /* Wait for vblank for the disable to take effect */
1291 intel_wait_for_vblank(dev);
1293 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1294 /* Wait for vblank for the disable to take effect. */
1295 intel_wait_for_vblank(dev);
1297 /* Filter ctl must be set before TV_WIN_SIZE */
1298 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1299 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1300 if (tv_mode->progressive)
1301 ysize = tv_mode->nbr_end + 1;
1303 ysize = 2*tv_mode->nbr_end + 1;
1305 xpos += tv_priv->margin[TV_MARGIN_LEFT];
1306 ypos += tv_priv->margin[TV_MARGIN_TOP];
1307 xsize -= (tv_priv->margin[TV_MARGIN_LEFT] +
1308 tv_priv->margin[TV_MARGIN_RIGHT]);
1309 ysize -= (tv_priv->margin[TV_MARGIN_TOP] +
1310 tv_priv->margin[TV_MARGIN_BOTTOM]);
1311 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1312 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1314 I915_WRITE(pipeconf_reg, pipeconf);
1315 I915_WRITE(dspcntr_reg, dspcntr);
1316 /* Flush the plane changes */
1317 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1321 for (i = 0; i < 60; i++)
1322 I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1323 for (i = 0; i < 60; i++)
1324 I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1325 for (i = 0; i < 43; i++)
1326 I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1327 for (i = 0; i < 43; i++)
1328 I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1329 I915_WRITE(TV_DAC, 0);
1330 I915_WRITE(TV_CTL, tv_ctl);
1333 static const struct drm_display_mode reported_modes[] = {
1335 .name = "NTSC 480i",
1338 .hsync_start = 1368,
1343 .vsync_start = 1027,
1346 .type = DRM_MODE_TYPE_DRIVER,
1351 * Detects TV presence by checking for load.
1353 * Requires that the current pipe's DPLL is active.
1355 * \return TRUE if TV is connected.
1356 * \return FALSE if TV is disconnected.
1359 intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
1361 struct drm_encoder *encoder = &intel_output->enc;
1362 struct drm_device *dev = encoder->dev;
1363 struct drm_i915_private *dev_priv = dev->dev_private;
1364 u32 pipeastat, pipeastat_save;
1365 u32 tv_ctl, save_tv_ctl;
1366 u32 tv_dac, save_tv_dac;
1367 int type = DRM_MODE_CONNECTOR_Unknown;
1369 tv_dac = I915_READ(TV_DAC);
1371 /* Disable TV interrupts around load detect or we'll recurse */
1372 pipeastat = I915_READ(PIPEASTAT);
1373 pipeastat_save = pipeastat;
1374 pipeastat &= ~PIPE_HOTPLUG_INTERRUPT_ENABLE;
1375 pipeastat &= ~PIPE_HOTPLUG_TV_INTERRUPT_ENABLE;
1376 I915_WRITE(PIPEASTAT, pipeastat | PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
1377 PIPE_HOTPLUG_INTERRUPT_STATUS);
1380 * Detect TV by polling)
1382 if (intel_output->load_detect_temp) {
1383 /* TV not currently running, prod it with destructive detect */
1384 save_tv_dac = tv_dac;
1385 tv_ctl = I915_READ(TV_CTL);
1386 save_tv_ctl = tv_ctl;
1387 tv_ctl &= ~TV_ENC_ENABLE;
1388 tv_ctl &= ~TV_TEST_MODE_MASK;
1389 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1390 tv_dac &= ~TVDAC_SENSE_MASK;
1391 tv_dac |= (TVDAC_STATE_CHG_EN |
1399 I915_WRITE(TV_CTL, tv_ctl);
1400 I915_WRITE(TV_DAC, tv_dac);
1401 intel_wait_for_vblank(dev);
1402 tv_dac = I915_READ(TV_DAC);
1403 I915_WRITE(TV_DAC, save_tv_dac);
1404 I915_WRITE(TV_CTL, save_tv_ctl);
1412 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1413 DRM_DEBUG("Detected Composite TV connection\n");
1414 type = DRM_MODE_CONNECTOR_Composite;
1415 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1416 DRM_DEBUG("Detected S-Video TV connection\n");
1417 type = DRM_MODE_CONNECTOR_SVIDEO;
1418 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1419 DRM_DEBUG("Detected Component TV connection\n");
1420 type = DRM_MODE_CONNECTOR_Component;
1422 DRM_DEBUG("No TV connection detected\n");
1426 /* Restore interrupt config */
1427 I915_WRITE(PIPEASTAT, pipeastat_save | PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
1428 PIPE_HOTPLUG_INTERRUPT_STATUS);
1434 * Detect the TV connection.
1436 * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure
1437 * we have a pipe programmed in order to probe the TV.
1439 static enum drm_connector_status
1440 intel_tv_detect(struct drm_connector *connector)
1442 struct drm_crtc *crtc;
1443 struct drm_display_mode mode;
1444 struct intel_output *intel_output = to_intel_output(connector);
1445 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1446 struct drm_encoder *encoder = &intel_output->enc;
1448 int type = tv_priv->type;
1450 mode = reported_modes[0];
1451 drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1453 if (encoder->crtc) {
1454 type = intel_tv_detect_type(encoder->crtc, intel_output);
1456 crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
1458 type = intel_tv_detect_type(crtc, intel_output);
1459 intel_release_load_detect_pipe(intel_output, dpms_mode);
1465 if (type != tv_priv->type) {
1466 struct drm_property *connector_property =
1467 connector->dev->mode_config.connector_type_property;
1469 tv_priv->type = type;
1470 drm_connector_property_set_value(connector, connector_property,
1475 return connector_status_disconnected;
1477 return connector_status_connected;
1480 static struct input_res {
1483 } input_res_table[] =
1485 {"640x480", 640, 480},
1486 {"800x600", 800, 600},
1487 {"1024x768", 1024, 768},
1488 {"1280x1024", 1280, 1024},
1489 {"848x480", 848, 480},
1490 {"1280x720", 1280, 720},
1491 {"1920x1080", 1920, 1080},
1495 * Stub get_modes function.
1497 * This should probably return a set of fixed modes, unless we can figure out
1498 * how to probe modes off of TV connections.
1502 intel_tv_get_modes(struct drm_connector *connector)
1504 struct drm_display_mode *mode_ptr;
1505 struct intel_output *intel_output = to_intel_output(connector);
1506 const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
1509 for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
1511 struct input_res *input = &input_res_table[j];
1512 unsigned int hactive_s = input->w;
1513 unsigned int vactive_s = input->h;
1515 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1518 if (input->w > 1024 && (!tv_mode->progressive
1519 && !tv_mode->component_only))
1522 mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
1524 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1526 mode_ptr->hdisplay = hactive_s;
1527 mode_ptr->hsync_start = hactive_s + 1;
1528 mode_ptr->hsync_end = hactive_s + 64;
1529 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1530 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1531 mode_ptr->htotal = hactive_s + 96;
1533 mode_ptr->vdisplay = vactive_s;
1534 mode_ptr->vsync_start = vactive_s + 1;
1535 mode_ptr->vsync_end = vactive_s + 32;
1536 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1537 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1538 mode_ptr->vtotal = vactive_s + 33;
1540 mode_ptr->clock = (int) (tv_mode->refresh *
1542 mode_ptr->htotal / 1000) / 1000;
1544 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1545 drm_mode_probed_add(connector, mode_ptr);
1552 intel_tv_destroy (struct drm_connector *connector)
1554 struct intel_output *intel_output = to_intel_output(connector);
1556 drm_sysfs_connector_remove(connector);
1557 drm_connector_cleanup(connector);
1558 drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv),
1564 intel_tv_set_property(struct drm_connector *connector, struct drm_property *property,
1567 struct drm_device *dev = connector->dev;
1568 struct intel_output *intel_output = to_intel_output(connector);
1569 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1572 ret = drm_connector_property_set_value(connector, property, val);
1576 if (property == dev->mode_config.tv_left_margin_property)
1577 tv_priv->margin[TV_MARGIN_LEFT] = val;
1578 else if (property == dev->mode_config.tv_right_margin_property)
1579 tv_priv->margin[TV_MARGIN_RIGHT] = val;
1580 else if (property == dev->mode_config.tv_top_margin_property)
1581 tv_priv->margin[TV_MARGIN_TOP] = val;
1582 else if (property == dev->mode_config.tv_bottom_margin_property)
1583 tv_priv->margin[TV_MARGIN_BOTTOM] = val;
1584 else if (property == dev->mode_config.tv_mode_property) {
1585 if (val >= NUM_TV_MODES) {
1589 tv_priv->tv_format = tv_modes[val].name;
1590 intel_tv_mode_set(&intel_output->enc, NULL, NULL);
1596 intel_tv_mode_set(&intel_output->enc, NULL, NULL);
1601 static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = {
1602 .dpms = intel_tv_dpms,
1603 .mode_fixup = intel_tv_mode_fixup,
1604 .prepare = intel_encoder_prepare,
1605 .mode_set = intel_tv_mode_set,
1606 .commit = intel_encoder_commit,
1609 static const struct drm_connector_funcs intel_tv_connector_funcs = {
1610 .save = intel_tv_save,
1611 .restore = intel_tv_restore,
1612 .detect = intel_tv_detect,
1613 .destroy = intel_tv_destroy,
1614 .set_property = intel_tv_set_property,
1615 .fill_modes = drm_helper_probe_single_connector_modes,
1618 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1619 .mode_valid = intel_tv_mode_valid,
1620 .get_modes = intel_tv_get_modes,
1621 .best_encoder = intel_best_encoder,
1624 void intel_tv_enc_destroy(struct drm_encoder *encoder)
1626 drm_encoder_cleanup(encoder);
1629 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1630 .destroy = intel_tv_enc_destroy,
1635 intel_tv_init(struct drm_device *dev)
1637 struct drm_i915_private *dev_priv = dev->dev_private;
1638 struct drm_connector *connector;
1639 struct intel_output *intel_output;
1640 struct intel_tv_priv *tv_priv;
1641 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1642 char **tv_format_names;
1643 int i, initial_mode = 0;
1645 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1648 /* Even if we have an encoder we may not have a connector */
1649 if (!dev_priv->int_tv_support)
1653 * Sanity check the TV output by checking to see if the
1654 * DAC register holds a value
1656 save_tv_dac = I915_READ(TV_DAC);
1658 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1659 tv_dac_on = I915_READ(TV_DAC);
1661 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1662 tv_dac_off = I915_READ(TV_DAC);
1664 I915_WRITE(TV_DAC, save_tv_dac);
1667 * If the register does not hold the state change enable
1668 * bit, (either as a 0 or a 1), assume it doesn't really
1671 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1672 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1675 intel_output = drm_calloc(1, sizeof(struct intel_output) +
1676 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
1677 if (!intel_output) {
1680 connector = &intel_output->base;
1682 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1683 DRM_MODE_CONNECTOR_SVIDEO);
1685 drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs,
1686 DRM_MODE_ENCODER_TVDAC);
1688 drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
1689 tv_priv = (struct intel_tv_priv *)(intel_output + 1);
1690 intel_output->type = INTEL_OUTPUT_TVOUT;
1691 intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
1692 intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
1693 intel_output->dev_priv = tv_priv;
1694 tv_priv->type = DRM_MODE_CONNECTOR_Unknown;
1696 /* BIOS margin values */
1697 tv_priv->margin[TV_MARGIN_LEFT] = 54;
1698 tv_priv->margin[TV_MARGIN_TOP] = 36;
1699 tv_priv->margin[TV_MARGIN_RIGHT] = 46;
1700 tv_priv->margin[TV_MARGIN_BOTTOM] = 37;
1702 tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
1704 drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs);
1705 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1706 connector->interlace_allowed = FALSE;
1707 connector->doublescan_allowed = FALSE;
1709 /* Create TV properties then attach current values */
1710 tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES,
1712 if (!tv_format_names)
1714 for (i = 0; i < NUM_TV_MODES; i++)
1715 tv_format_names[i] = tv_modes[i].name;
1716 drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names);
1718 drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
1720 drm_connector_attach_property(connector,
1721 dev->mode_config.tv_left_margin_property,
1722 tv_priv->margin[TV_MARGIN_LEFT]);
1723 drm_connector_attach_property(connector,
1724 dev->mode_config.tv_top_margin_property,
1725 tv_priv->margin[TV_MARGIN_TOP]);
1726 drm_connector_attach_property(connector,
1727 dev->mode_config.tv_right_margin_property,
1728 tv_priv->margin[TV_MARGIN_RIGHT]);
1729 drm_connector_attach_property(connector,
1730 dev->mode_config.tv_bottom_margin_property,
1731 tv_priv->margin[TV_MARGIN_BOTTOM]);
1733 drm_sysfs_connector_add(connector);