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_output *output, int mode)
903 struct drm_device *dev = output->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_output *output)
921 struct drm_device *dev = output->dev;
922 struct drm_i915_private *dev_priv = dev->dev_private;
923 struct intel_output *intel_output = output->driver_private;
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_output *output)
971 struct drm_device *dev = output->dev;
972 struct drm_i915_private *dev_priv = dev->dev_private;
973 struct intel_output *intel_output = output->driver_private;
974 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
975 struct drm_crtc *crtc = output->crtc;
976 struct intel_crtc *intel_crtc;
979 /* FIXME: No CRTC? */
983 intel_crtc = crtc->driver_private;
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 drm_output *output)
1072 struct intel_output *intel_output = output->driver_private;
1073 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1075 return intel_tv_mode_lookup(tv_priv->tv_format);
1078 static enum drm_mode_status
1079 intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode)
1081 const struct tv_mode *tv_mode = intel_tv_mode_find(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_output *output, struct drm_display_mode *mode,
1092 struct drm_display_mode *adjusted_mode)
1094 struct drm_device *dev = output->dev;
1095 struct drm_mode_config *drm_config = &dev->mode_config;
1096 const struct tv_mode *tv_mode = intel_tv_mode_find (output);
1097 struct drm_output *other_output;
1102 /* FIXME: lock output list */
1103 list_for_each_entry(other_output, &drm_config->output_list, head) {
1104 if (other_output != output &&
1105 other_output->crtc == output->crtc)
1109 adjusted_mode->clock = tv_mode->clock;
1114 intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,
1115 struct drm_display_mode *adjusted_mode)
1117 struct drm_device *dev = output->dev;
1118 struct drm_i915_private *dev_priv = dev->dev_private;
1119 struct drm_crtc *crtc = output->crtc;
1120 struct intel_crtc *intel_crtc = crtc->driver_private;
1121 struct intel_output *intel_output = output->driver_private;
1122 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1123 const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1125 u32 hctl1, hctl2, hctl3;
1126 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1127 u32 scctl1, scctl2, scctl3;
1129 const struct video_levels *video_levels;
1130 const struct color_conversion *color_conversion;
1134 return; /* can't happen (mode_prepare prevents this) */
1138 switch (tv_priv->type) {
1140 case ConnectorUnknown:
1141 case ConnectorComposite:
1142 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1143 video_levels = tv_mode->composite_levels;
1144 color_conversion = tv_mode->composite_color;
1145 burst_ena = tv_mode->burst_ena;
1147 case ConnectorComponent:
1148 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1149 video_levels = &component_levels;
1150 if (tv_mode->burst_ena)
1151 color_conversion = &sdtv_csc_yprpb;
1153 color_conversion = &hdtv_csc_yprpb;
1156 case ConnectorSVIDEO:
1157 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1158 video_levels = tv_mode->svideo_levels;
1159 color_conversion = tv_mode->svideo_color;
1160 burst_ena = tv_mode->burst_ena;
1163 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1164 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1166 hctl2 = (tv_mode->hburst_start << 16) |
1167 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1170 hctl2 |= TV_BURST_ENA;
1172 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1173 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1175 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1176 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1177 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1179 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1180 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1181 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1183 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1184 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1185 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1187 if (tv_mode->veq_ena)
1188 vctl3 |= TV_EQUAL_ENA;
1190 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1191 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1193 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1194 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1196 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1197 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1199 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1200 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1202 if (intel_crtc->pipe == 1)
1203 tv_ctl |= TV_ENC_PIPEB_SELECT;
1204 tv_ctl |= tv_mode->oversample;
1206 if (tv_mode->progressive)
1207 tv_ctl |= TV_PROGRESSIVE;
1208 if (tv_mode->trilevel_sync)
1209 tv_ctl |= TV_TRILEVEL_SYNC;
1210 if (tv_mode->pal_burst)
1211 tv_ctl |= TV_PAL_BURST;
1213 /* dda1 implies valid video levels */
1214 if (tv_mode->dda1_inc) {
1215 scctl1 |= TV_SC_DDA1_EN;
1216 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1219 if (tv_mode->dda2_inc)
1220 scctl1 |= TV_SC_DDA2_EN;
1222 if (tv_mode->dda3_inc)
1223 scctl1 |= TV_SC_DDA3_EN;
1225 scctl1 |= tv_mode->sc_reset;
1226 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1228 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1229 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1231 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1232 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1234 /* Enable two fixes for the chips that need them. */
1235 if (dev->pci_device < 0x2772)
1236 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1238 I915_WRITE(TV_H_CTL_1, hctl1);
1239 I915_WRITE(TV_H_CTL_2, hctl2);
1240 I915_WRITE(TV_H_CTL_3, hctl3);
1241 I915_WRITE(TV_V_CTL_1, vctl1);
1242 I915_WRITE(TV_V_CTL_2, vctl2);
1243 I915_WRITE(TV_V_CTL_3, vctl3);
1244 I915_WRITE(TV_V_CTL_4, vctl4);
1245 I915_WRITE(TV_V_CTL_5, vctl5);
1246 I915_WRITE(TV_V_CTL_6, vctl6);
1247 I915_WRITE(TV_V_CTL_7, vctl7);
1248 I915_WRITE(TV_SC_CTL_1, scctl1);
1249 I915_WRITE(TV_SC_CTL_2, scctl2);
1250 I915_WRITE(TV_SC_CTL_3, scctl3);
1252 if (color_conversion) {
1253 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1254 color_conversion->gy);
1255 I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
1256 color_conversion->ay);
1257 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1258 color_conversion->gu);
1259 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1260 color_conversion->au);
1261 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1262 color_conversion->gv);
1263 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1264 color_conversion->av);
1267 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1269 I915_WRITE(TV_CLR_LEVEL,
1270 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1271 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1273 int pipeconf_reg = (intel_crtc->pipe == 0) ?
1274 PIPEACONF : PIPEBCONF;
1275 int dspcntr_reg = (intel_crtc->plane == 0) ?
1276 DSPACNTR : DSPBCNTR;
1277 int pipeconf = I915_READ(pipeconf_reg);
1278 int dspcntr = I915_READ(dspcntr_reg);
1279 int dspbase_reg = (intel_crtc->plane == 0) ?
1280 DSPAADDR : DSPBADDR;
1281 int xpos = 0x0, ypos = 0x0;
1282 unsigned int xsize, ysize;
1283 /* Pipe must be off here */
1284 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1285 /* Flush the plane changes */
1286 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1288 /* Wait for vblank for the disable to take effect */
1290 intel_wait_for_vblank(dev);
1292 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1293 /* Wait for vblank for the disable to take effect. */
1294 intel_wait_for_vblank(dev);
1296 /* Filter ctl must be set before TV_WIN_SIZE */
1297 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1298 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1299 if (tv_mode->progressive)
1300 ysize = tv_mode->nbr_end + 1;
1302 ysize = 2*tv_mode->nbr_end + 1;
1304 xpos += tv_priv->margin[TV_MARGIN_LEFT];
1305 ypos += tv_priv->margin[TV_MARGIN_TOP];
1306 xsize -= (tv_priv->margin[TV_MARGIN_LEFT] +
1307 tv_priv->margin[TV_MARGIN_RIGHT]);
1308 ysize -= (tv_priv->margin[TV_MARGIN_TOP] +
1309 tv_priv->margin[TV_MARGIN_BOTTOM]);
1310 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1311 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1313 I915_WRITE(pipeconf_reg, pipeconf);
1314 I915_WRITE(dspcntr_reg, dspcntr);
1315 /* Flush the plane changes */
1316 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1320 for (i = 0; i < 60; i++)
1321 I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1322 for (i = 0; i < 60; i++)
1323 I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1324 for (i = 0; i < 43; i++)
1325 I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1326 for (i = 0; i < 43; i++)
1327 I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1328 I915_WRITE(TV_DAC, 0);
1329 I915_WRITE(TV_CTL, tv_ctl);
1332 static const struct drm_display_mode reported_modes[] = {
1334 .name = "NTSC 480i",
1337 .hsync_start = 1368,
1342 .vsync_start = 1027,
1345 .type = DRM_MODE_TYPE_DRIVER,
1350 * Detects TV presence by checking for load.
1352 * Requires that the current pipe's DPLL is active.
1354 * \return TRUE if TV is connected.
1355 * \return FALSE if TV is disconnected.
1358 intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
1360 struct drm_device *dev = output->dev;
1361 struct drm_i915_private *dev_priv = dev->dev_private;
1362 struct intel_output *intel_output = output->driver_private;
1363 u32 pipeastat, pipeastat_save;
1364 u32 tv_ctl, save_tv_ctl;
1365 u32 tv_dac, save_tv_dac;
1366 int type = ConnectorUnknown;
1368 tv_dac = I915_READ(TV_DAC);
1370 /* Disable TV interrupts around load detect or we'll recurse */
1371 pipeastat = I915_READ(PIPEASTAT);
1372 pipeastat_save = pipeastat;
1373 pipeastat &= ~PIPE_HOTPLUG_INTERRUPT_ENABLE;
1374 pipeastat &= ~PIPE_HOTPLUG_TV_INTERRUPT_ENABLE;
1375 I915_WRITE(PIPEASTAT, pipeastat | PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
1376 PIPE_HOTPLUG_INTERRUPT_STATUS);
1379 * Detect TV by polling)
1381 if (intel_output->load_detect_temp) {
1382 /* TV not currently running, prod it with destructive detect */
1383 save_tv_dac = tv_dac;
1384 tv_ctl = I915_READ(TV_CTL);
1385 save_tv_ctl = tv_ctl;
1386 tv_ctl &= ~TV_ENC_ENABLE;
1387 tv_ctl &= ~TV_TEST_MODE_MASK;
1388 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1389 tv_dac &= ~TVDAC_SENSE_MASK;
1390 tv_dac |= (TVDAC_STATE_CHG_EN |
1398 I915_WRITE(TV_CTL, tv_ctl);
1399 I915_WRITE(TV_DAC, tv_dac);
1400 intel_wait_for_vblank(dev);
1401 tv_dac = I915_READ(TV_DAC);
1402 I915_WRITE(TV_DAC, save_tv_dac);
1403 I915_WRITE(TV_CTL, save_tv_ctl);
1411 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1412 DRM_DEBUG("Detected Composite TV connection\n");
1413 type = ConnectorComposite;
1414 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1415 DRM_DEBUG("Detected S-Video TV connection\n");
1416 type = ConnectorSVIDEO;
1417 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1418 DRM_DEBUG("Detected Component TV connection\n");
1419 type = ConnectorComponent;
1421 DRM_DEBUG("No TV connection detected\n");
1425 /* Restore interrupt config */
1426 I915_WRITE(PIPEASTAT, pipeastat_save | PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
1427 PIPE_HOTPLUG_INTERRUPT_STATUS);
1433 * Detect the TV connection.
1435 * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure
1436 * we have a pipe programmed in order to probe the TV.
1438 static enum drm_output_status
1439 intel_tv_detect(struct drm_output *output)
1441 struct drm_crtc *crtc;
1442 struct drm_display_mode mode;
1443 struct intel_output *intel_output = output->driver_private;
1444 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1446 int type = tv_priv->type;
1448 mode = reported_modes[0];
1449 drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1452 type = intel_tv_detect_type(output->crtc, output);
1454 crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode);
1456 type = intel_tv_detect_type(crtc, output);
1457 intel_release_load_detect_pipe(output, dpms_mode);
1462 if (type != tv_priv->type) {
1463 struct drm_property *connector_property =
1464 output->dev->mode_config.connector_type_property;
1466 tv_priv->type = type;
1467 drm_output_property_set_value(output, connector_property,
1472 return output_status_disconnected;
1474 return output_status_connected;
1477 static struct input_res {
1480 } input_res_table[] =
1482 {"640x480", 640, 480},
1483 {"800x600", 800, 600},
1484 {"1024x768", 1024, 768},
1485 {"1280x1024", 1280, 1024},
1486 {"848x480", 848, 480},
1487 {"1280x720", 1280, 720},
1488 {"1920x1080", 1920, 1080},
1492 * Stub get_modes function.
1494 * This should probably return a set of fixed modes, unless we can figure out
1495 * how to probe modes off of TV connections.
1499 intel_tv_get_modes(struct drm_output *output)
1501 struct drm_display_mode *mode_ptr;
1502 const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1505 for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
1507 struct input_res *input = &input_res_table[j];
1508 unsigned int hactive_s = input->w;
1509 unsigned int vactive_s = input->h;
1511 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1514 if (input->w > 1024 && (!tv_mode->progressive
1515 && !tv_mode->component_only))
1518 mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
1520 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1522 mode_ptr->hdisplay = hactive_s;
1523 mode_ptr->hsync_start = hactive_s + 1;
1524 mode_ptr->hsync_end = hactive_s + 64;
1525 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1526 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1527 mode_ptr->htotal = hactive_s + 96;
1529 mode_ptr->vdisplay = vactive_s;
1530 mode_ptr->vsync_start = vactive_s + 1;
1531 mode_ptr->vsync_end = vactive_s + 32;
1532 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1533 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1534 mode_ptr->vtotal = vactive_s + 33;
1536 mode_ptr->clock = (int) (tv_mode->refresh *
1538 mode_ptr->htotal / 1000) / 1000;
1540 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1541 drm_mode_probed_add(output, mode_ptr);
1548 intel_tv_destroy (struct drm_output *output)
1550 if (output->driver_private)
1551 drm_free(output->driver_private, sizeof(struct intel_tv_priv),
1556 intel_tv_set_property(struct drm_output *output, struct drm_property *property,
1559 struct drm_device *dev = output->dev;
1560 struct intel_output *intel_output = output->driver_private;
1561 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1564 ret = drm_output_property_set_value(output, property, val);
1568 if (property == dev->mode_config.tv_left_margin_property)
1569 tv_priv->margin[TV_MARGIN_LEFT] = val;
1570 else if (property == dev->mode_config.tv_right_margin_property)
1571 tv_priv->margin[TV_MARGIN_RIGHT] = val;
1572 else if (property == dev->mode_config.tv_top_margin_property)
1573 tv_priv->margin[TV_MARGIN_TOP] = val;
1574 else if (property == dev->mode_config.tv_bottom_margin_property)
1575 tv_priv->margin[TV_MARGIN_BOTTOM] = val;
1576 else if (property == dev->mode_config.tv_mode_property) {
1577 if (val >= NUM_TV_MODES) {
1581 tv_priv->tv_format = tv_modes[val].name;
1582 intel_tv_mode_set(output, NULL, NULL);
1588 intel_tv_mode_set(output, NULL, NULL);
1593 static const struct drm_output_funcs intel_tv_output_funcs = {
1594 .dpms = intel_tv_dpms,
1595 .save = intel_tv_save,
1596 .restore = intel_tv_restore,
1597 .mode_valid = intel_tv_mode_valid,
1598 .mode_fixup = intel_tv_mode_fixup,
1599 .prepare = intel_output_prepare,
1600 .mode_set = intel_tv_mode_set,
1601 .commit = intel_output_commit,
1602 .detect = intel_tv_detect,
1603 .get_modes = intel_tv_get_modes,
1604 .cleanup = intel_tv_destroy,
1605 .set_property = intel_tv_set_property,
1609 intel_tv_init(struct drm_device *dev)
1611 struct drm_i915_private *dev_priv = dev->dev_private;
1612 struct drm_output *output;
1613 struct intel_output *intel_output;
1614 struct intel_tv_priv *tv_priv;
1615 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1616 char **tv_format_names;
1617 int i, initial_mode = 0;
1619 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1622 /* Even if we have an encoder we may not have a connector */
1623 if (!dev_priv->int_tv_support)
1627 * Sanity check the TV output by checking to see if the
1628 * DAC register holds a value
1630 save_tv_dac = I915_READ(TV_DAC);
1632 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1633 tv_dac_on = I915_READ(TV_DAC);
1635 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1636 tv_dac_off = I915_READ(TV_DAC);
1638 I915_WRITE(TV_DAC, save_tv_dac);
1641 * If the register does not hold the state change enable
1642 * bit, (either as a 0 or a 1), assume it doesn't really
1645 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1646 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1649 output = drm_output_create(dev, &intel_tv_output_funcs,
1650 DRM_MODE_OUTPUT_TVDAC);
1655 intel_output = drm_calloc(1, sizeof(struct intel_output) +
1656 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
1657 if (!intel_output) {
1658 drm_output_destroy(output);
1662 tv_priv = (struct intel_tv_priv *)(intel_output + 1);
1663 intel_output->type = INTEL_OUTPUT_TVOUT;
1664 output->possible_crtcs = ((1 << 0) | (1 << 1));
1665 output->possible_clones = (1 << INTEL_OUTPUT_TVOUT);
1666 intel_output->dev_priv = tv_priv;
1667 tv_priv->type = ConnectorUnknown;
1669 /* BIOS margin values */
1670 tv_priv->margin[TV_MARGIN_LEFT] = 54;
1671 tv_priv->margin[TV_MARGIN_TOP] = 36;
1672 tv_priv->margin[TV_MARGIN_RIGHT] = 46;
1673 tv_priv->margin[TV_MARGIN_BOTTOM] = 37;
1675 tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
1677 output->driver_private = intel_output;
1678 output->interlace_allowed = FALSE;
1679 output->doublescan_allowed = FALSE;
1681 drm_output_attach_property(output,
1682 dev->mode_config.connector_type_property,
1685 /* Create TV properties then attach current values */
1686 tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES,
1688 if (!tv_format_names)
1690 for (i = 0; i < NUM_TV_MODES; i++)
1691 tv_format_names[i] = tv_modes[i].name;
1692 drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names);
1694 drm_output_attach_property(output, dev->mode_config.tv_mode_property,
1696 drm_output_attach_property(output,
1697 dev->mode_config.tv_left_margin_property,
1698 tv_priv->margin[TV_MARGIN_LEFT]);
1699 drm_output_attach_property(output,
1700 dev->mode_config.tv_top_margin_property,
1701 tv_priv->margin[TV_MARGIN_TOP]);
1702 drm_output_attach_property(output,
1703 dev->mode_config.tv_right_margin_property,
1704 tv_priv->margin[TV_MARGIN_RIGHT]);
1705 drm_output_attach_property(output,
1706 dev->mode_config.tv_bottom_margin_property,
1707 tv_priv->margin[TV_MARGIN_BOTTOM]);
1709 drm_sysfs_output_add(output);