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"
49 TV_MARGIN_LEFT, TV_MARGIN_TOP,
50 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
53 /** Private structure for the integrated TV support */
54 struct intel_tv_priv {
68 u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
76 u32 save_TV_CLR_KNOBS;
77 u32 save_TV_CLR_LEVEL;
80 u32 save_TV_FILTER_CTL_1;
81 u32 save_TV_FILTER_CTL_2;
82 u32 save_TV_FILTER_CTL_3;
84 u32 save_TV_H_LUMA[60];
85 u32 save_TV_H_CHROMA[60];
86 u32 save_TV_V_LUMA[43];
87 u32 save_TV_V_CHROMA[43];
94 int blank, black, burst;
97 struct color_conversion {
103 static const u32 filter_table[] = {
104 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
105 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
106 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
107 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
108 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
109 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
110 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
111 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
112 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
113 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
114 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
115 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
116 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
117 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
118 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
119 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
120 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
121 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
122 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
123 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
124 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
125 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
126 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
127 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
128 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
129 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
130 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
131 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
132 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
133 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
134 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
135 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
136 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
137 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
138 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
139 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
140 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
141 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
142 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
143 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
144 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
145 0x2D002CC0, 0x30003640, 0x2D0036C0,
146 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
147 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
148 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
149 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
150 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
151 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
152 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
153 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
154 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
155 0x28003100, 0x28002F00, 0x00003100,
159 * Color conversion values have 3 separate fixed point formats:
161 * 10 bit fields (ay, au)
162 * 1.9 fixed point (b.bbbbbbbbb)
163 * 11 bit fields (ry, by, ru, gu, gv)
164 * exp.mantissa (ee.mmmmmmmmm)
165 * ee = 00 = 10^-1 (0.mmmmmmmmm)
166 * ee = 01 = 10^-2 (0.0mmmmmmmmm)
167 * ee = 10 = 10^-3 (0.00mmmmmmmmm)
168 * ee = 11 = 10^-4 (0.000mmmmmmmmm)
169 * 12 bit fields (gy, rv, bu)
170 * exp.mantissa (eee.mmmmmmmmm)
171 * eee = 000 = 10^-1 (0.mmmmmmmmm)
172 * eee = 001 = 10^-2 (0.0mmmmmmmmm)
173 * eee = 010 = 10^-3 (0.00mmmmmmmmm)
174 * eee = 011 = 10^-4 (0.000mmmmmmmmm)
175 * eee = 100 = reserved
176 * eee = 101 = reserved
177 * eee = 110 = reserved
178 * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
180 * Saturation and contrast are 8 bits, with their own representation:
181 * 8 bit field (saturation, contrast)
182 * exp.mantissa (ee.mmmmmm)
183 * ee = 00 = 10^-1 (0.mmmmmm)
184 * ee = 01 = 10^0 (m.mmmmm)
185 * ee = 10 = 10^1 (mm.mmmm)
186 * ee = 11 = 10^2 (mmm.mmm)
188 * Simple conversion function:
191 * float_to_csc_11(float f)
204 * for (exp = 0; exp < 3 && f < 0.5; exp++)
206 * mant = (f * (1 << 9) + 0.5);
207 * if (mant >= (1 << 9))
208 * mant = (1 << 9) - 1;
210 * ret = (exp << 9) | mant;
216 * Behold, magic numbers! If we plant them they might grow a big
217 * s-video cable to the sky... or something.
219 * Pre-converted to appropriate hex value.
223 * PAL & NTSC values for composite & s-video connections
225 static const struct color_conversion ntsc_m_csc_composite = {
226 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
227 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
228 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
231 static const struct video_levels ntsc_m_levels_composite = {
232 .blank = 225, .black = 267, .burst = 113,
235 static const struct color_conversion ntsc_m_csc_svideo = {
236 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
237 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
238 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
241 static const struct video_levels ntsc_m_levels_svideo = {
242 .blank = 266, .black = 316, .burst = 133,
245 static const struct color_conversion ntsc_j_csc_composite = {
246 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
247 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
248 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
251 static const struct video_levels ntsc_j_levels_composite = {
252 .blank = 225, .black = 225, .burst = 113,
255 static const struct color_conversion ntsc_j_csc_svideo = {
256 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
257 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
258 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
261 static const struct video_levels ntsc_j_levels_svideo = {
262 .blank = 266, .black = 266, .burst = 133,
265 static const struct color_conversion pal_csc_composite = {
266 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
267 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
268 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
271 static const struct video_levels pal_levels_composite = {
272 .blank = 237, .black = 237, .burst = 118,
275 static const struct color_conversion pal_csc_svideo = {
276 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
277 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
278 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
281 static const struct video_levels pal_levels_svideo = {
282 .blank = 280, .black = 280, .burst = 139,
285 static const struct color_conversion pal_m_csc_composite = {
286 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
287 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
288 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
291 static const struct video_levels pal_m_levels_composite = {
292 .blank = 225, .black = 267, .burst = 113,
295 static const struct color_conversion pal_m_csc_svideo = {
296 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
297 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
298 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
301 static const struct video_levels pal_m_levels_svideo = {
302 .blank = 266, .black = 316, .burst = 133,
305 static const struct color_conversion pal_n_csc_composite = {
306 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
307 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
308 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
311 static const struct video_levels pal_n_levels_composite = {
312 .blank = 225, .black = 267, .burst = 118,
315 static const struct color_conversion pal_n_csc_svideo = {
316 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
317 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
318 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
321 static const struct video_levels pal_n_levels_svideo = {
322 .blank = 266, .black = 316, .burst = 139,
326 * Component connections
328 static const struct color_conversion sdtv_csc_yprpb = {
329 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
330 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
331 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
334 static const struct color_conversion sdtv_csc_rgb = {
335 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
336 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
337 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
340 static const struct color_conversion hdtv_csc_yprpb = {
341 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
342 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
343 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
346 static const struct color_conversion hdtv_csc_rgb = {
347 .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
348 .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
349 .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
352 static const struct video_levels component_levels = {
353 .blank = 279, .black = 279, .burst = 0,
360 int refresh; /* in millihertz (for precision) */
362 int hsync_end, hblank_start, hblank_end, htotal;
363 bool progressive, trilevel_sync, component_only;
364 int vsync_start_f1, vsync_start_f2, vsync_len;
366 int veq_start_f1, veq_start_f2, veq_len;
367 int vi_end_f1, vi_end_f2, nbr_end;
369 int hburst_start, hburst_len;
370 int vburst_start_f1, vburst_end_f1;
371 int vburst_start_f2, vburst_end_f2;
372 int vburst_start_f3, vburst_end_f3;
373 int vburst_start_f4, vburst_end_f4;
375 * subcarrier programming
377 int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
383 const struct video_levels *composite_levels, *svideo_levels;
384 const struct color_conversion *composite_color, *svideo_color;
385 const u32 *filter_table;
393 * I think this works as follows:
395 * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
397 * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
400 * dda1_ideal = subcarrier/pixel * 4096
401 * dda1_inc = floor (dda1_ideal)
402 * dda2 = dda1_ideal - dda1_inc
404 * then pick a ratio for dda2 that gives the closest approximation. If
405 * you can't get close enough, you can play with dda3 as well. This
406 * seems likely to happen when dda2 is small as the jumps would be larger
410 * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
412 * The constants below were all computed using a 107.520MHz clock
416 * Register programming values for TV modes.
418 * These values account for -1s required.
421 const static struct tv_mode tv_modes[] = {
426 .oversample = TV_OVERSAMPLE_8X,
428 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
430 .hsync_end = 64, .hblank_end = 124,
431 .hblank_start = 836, .htotal = 857,
433 .progressive = FALSE, .trilevel_sync = FALSE,
435 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
438 .veq_ena = TRUE, .veq_start_f1 = 0,
439 .veq_start_f2 = 1, .veq_len = 18,
441 .vi_end_f1 = 20, .vi_end_f2 = 21,
445 .hburst_start = 72, .hburst_len = 34,
446 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
447 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
448 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
449 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
451 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
453 .dda2_inc = 7624, .dda2_size = 20013,
454 .dda3_inc = 0, .dda3_size = 0,
455 .sc_reset = TV_SC_RESET_EVERY_4,
458 .composite_levels = &ntsc_m_levels_composite,
459 .composite_color = &ntsc_m_csc_composite,
460 .svideo_levels = &ntsc_m_levels_svideo,
461 .svideo_color = &ntsc_m_csc_svideo,
463 .filter_table = filter_table,
469 .oversample = TV_OVERSAMPLE_8X,
471 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
472 .hsync_end = 64, .hblank_end = 124,
473 .hblank_start = 836, .htotal = 857,
475 .progressive = FALSE, .trilevel_sync = FALSE,
477 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
480 .veq_ena = TRUE, .veq_start_f1 = 0,
481 .veq_start_f2 = 1, .veq_len = 18,
483 .vi_end_f1 = 20, .vi_end_f2 = 21,
487 .hburst_start = 72, .hburst_len = 34,
488 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
489 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
490 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
491 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
493 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
495 .dda2_inc = 18557, .dda2_size = 20625,
496 .dda3_inc = 0, .dda3_size = 0,
497 .sc_reset = TV_SC_RESET_EVERY_8,
500 .composite_levels = &ntsc_m_levels_composite,
501 .composite_color = &ntsc_m_csc_composite,
502 .svideo_levels = &ntsc_m_levels_svideo,
503 .svideo_color = &ntsc_m_csc_svideo,
505 .filter_table = filter_table,
511 .oversample = TV_OVERSAMPLE_8X,
514 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
515 .hsync_end = 64, .hblank_end = 124,
516 .hblank_start = 836, .htotal = 857,
518 .progressive = FALSE, .trilevel_sync = FALSE,
520 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
523 .veq_ena = TRUE, .veq_start_f1 = 0,
524 .veq_start_f2 = 1, .veq_len = 18,
526 .vi_end_f1 = 20, .vi_end_f2 = 21,
530 .hburst_start = 72, .hburst_len = 34,
531 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
532 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
533 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
534 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
536 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
538 .dda2_inc = 7624, .dda2_size = 20013,
539 .dda3_inc = 0, .dda3_size = 0,
540 .sc_reset = TV_SC_RESET_EVERY_4,
543 .composite_levels = &ntsc_j_levels_composite,
544 .composite_color = &ntsc_j_csc_composite,
545 .svideo_levels = &ntsc_j_levels_svideo,
546 .svideo_color = &ntsc_j_csc_svideo,
548 .filter_table = filter_table,
554 .oversample = TV_OVERSAMPLE_8X,
557 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
558 .hsync_end = 64, .hblank_end = 124,
559 .hblank_start = 836, .htotal = 857,
561 .progressive = FALSE, .trilevel_sync = FALSE,
563 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
566 .veq_ena = TRUE, .veq_start_f1 = 0,
567 .veq_start_f2 = 1, .veq_len = 18,
569 .vi_end_f1 = 20, .vi_end_f2 = 21,
573 .hburst_start = 72, .hburst_len = 34,
574 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
575 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
576 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
577 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
579 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
581 .dda2_inc = 7624, .dda2_size = 20013,
582 .dda3_inc = 0, .dda3_size = 0,
583 .sc_reset = TV_SC_RESET_EVERY_4,
586 .composite_levels = &pal_m_levels_composite,
587 .composite_color = &pal_m_csc_composite,
588 .svideo_levels = &pal_m_levels_svideo,
589 .svideo_color = &pal_m_csc_svideo,
591 .filter_table = filter_table,
594 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
598 .oversample = TV_OVERSAMPLE_8X,
601 .hsync_end = 64, .hblank_end = 128,
602 .hblank_start = 844, .htotal = 863,
604 .progressive = FALSE, .trilevel_sync = FALSE,
607 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
610 .veq_ena = TRUE, .veq_start_f1 = 0,
611 .veq_start_f2 = 1, .veq_len = 18,
613 .vi_end_f1 = 24, .vi_end_f2 = 25,
617 .hburst_start = 73, .hburst_len = 34,
618 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
619 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
620 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
621 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
624 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
626 .dda2_inc = 18557, .dda2_size = 20625,
627 .dda3_inc = 0, .dda3_size = 0,
628 .sc_reset = TV_SC_RESET_EVERY_8,
631 .composite_levels = &pal_n_levels_composite,
632 .composite_color = &pal_n_csc_composite,
633 .svideo_levels = &pal_n_levels_svideo,
634 .svideo_color = &pal_n_csc_svideo,
636 .filter_table = filter_table,
639 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
643 .oversample = TV_OVERSAMPLE_8X,
646 .hsync_end = 64, .hblank_end = 128,
647 .hblank_start = 844, .htotal = 863,
649 .progressive = FALSE, .trilevel_sync = FALSE,
651 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
654 .veq_ena = TRUE, .veq_start_f1 = 0,
655 .veq_start_f2 = 1, .veq_len = 15,
657 .vi_end_f1 = 24, .vi_end_f2 = 25,
661 .hburst_start = 73, .hburst_len = 32,
662 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
663 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
664 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
665 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
667 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
669 .dda2_inc = 18557, .dda2_size = 20625,
670 .dda3_inc = 0, .dda3_size = 0,
671 .sc_reset = TV_SC_RESET_EVERY_8,
674 .composite_levels = &pal_levels_composite,
675 .composite_color = &pal_csc_composite,
676 .svideo_levels = &pal_levels_svideo,
677 .svideo_color = &pal_csc_svideo,
679 .filter_table = filter_table,
682 .name = "480p@59.94Hz",
685 .oversample = TV_OVERSAMPLE_4X,
688 .hsync_end = 64, .hblank_end = 122,
689 .hblank_start = 842, .htotal = 857,
691 .progressive = TRUE,.trilevel_sync = FALSE,
693 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
698 .vi_end_f1 = 44, .vi_end_f2 = 44,
703 .filter_table = filter_table,
709 .oversample = TV_OVERSAMPLE_4X,
712 .hsync_end = 64, .hblank_end = 122,
713 .hblank_start = 842, .htotal = 856,
715 .progressive = TRUE,.trilevel_sync = FALSE,
717 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
722 .vi_end_f1 = 44, .vi_end_f2 = 44,
727 .filter_table = filter_table,
733 .oversample = TV_OVERSAMPLE_4X,
736 .hsync_end = 64, .hblank_end = 139,
737 .hblank_start = 859, .htotal = 863,
739 .progressive = TRUE, .trilevel_sync = FALSE,
741 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
746 .vi_end_f1 = 48, .vi_end_f2 = 48,
751 .filter_table = filter_table,
757 .oversample = TV_OVERSAMPLE_2X,
760 .hsync_end = 80, .hblank_end = 300,
761 .hblank_start = 1580, .htotal = 1649,
763 .progressive = TRUE, .trilevel_sync = TRUE,
765 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
770 .vi_end_f1 = 29, .vi_end_f2 = 29,
775 .filter_table = filter_table,
778 .name = "720p@59.94Hz",
781 .oversample = TV_OVERSAMPLE_2X,
784 .hsync_end = 80, .hblank_end = 300,
785 .hblank_start = 1580, .htotal = 1651,
787 .progressive = TRUE, .trilevel_sync = TRUE,
789 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
794 .vi_end_f1 = 29, .vi_end_f2 = 29,
799 .filter_table = filter_table,
805 .oversample = TV_OVERSAMPLE_2X,
808 .hsync_end = 80, .hblank_end = 300,
809 .hblank_start = 1580, .htotal = 1979,
811 .progressive = TRUE, .trilevel_sync = TRUE,
813 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
818 .vi_end_f1 = 29, .vi_end_f2 = 29,
823 .filter_table = filter_table,
827 .name = "1080i@50Hz",
830 .oversample = TV_OVERSAMPLE_2X,
833 .hsync_end = 88, .hblank_end = 235,
834 .hblank_start = 2155, .htotal = 2639,
836 .progressive = FALSE, .trilevel_sync = TRUE,
838 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
841 .veq_ena = TRUE, .veq_start_f1 = 4,
842 .veq_start_f2 = 4, .veq_len = 10,
845 .vi_end_f1 = 21, .vi_end_f2 = 22,
850 .filter_table = filter_table,
853 .name = "1080i@60Hz",
856 .oversample = TV_OVERSAMPLE_2X,
859 .hsync_end = 88, .hblank_end = 235,
860 .hblank_start = 2155, .htotal = 2199,
862 .progressive = FALSE, .trilevel_sync = TRUE,
864 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
867 .veq_ena = TRUE, .veq_start_f1 = 4,
868 .veq_start_f2 = 4, .veq_len = 10,
871 .vi_end_f1 = 21, .vi_end_f2 = 22,
876 .filter_table = filter_table,
879 .name = "1080i@59.94Hz",
882 .oversample = TV_OVERSAMPLE_2X,
885 .hsync_end = 88, .hblank_end = 235,
886 .hblank_start = 2155, .htotal = 2200,
888 .progressive = FALSE, .trilevel_sync = TRUE,
890 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
893 .veq_ena = TRUE, .veq_start_f1 = 4,
894 .veq_start_f2 = 4, .veq_len = 10,
897 .vi_end_f1 = 21, .vi_end_f2 = 22,
902 .filter_table = filter_table,
906 #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
909 intel_tv_dpms(struct drm_output *output, int mode)
911 struct drm_device *dev = output->dev;
912 struct drm_i915_private *dev_priv = dev->dev_private;
916 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
918 case DPMSModeStandby:
919 case DPMSModeSuspend:
921 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
927 intel_tv_save(struct drm_output *output)
929 struct drm_device *dev = output->dev;
930 struct drm_i915_private *dev_priv = dev->dev_private;
931 struct intel_output *intel_output = output->driver_private;
932 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
935 tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
936 tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2);
937 tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3);
938 tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1);
939 tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2);
940 tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3);
941 tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4);
942 tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5);
943 tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6);
944 tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7);
945 tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1);
946 tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2);
947 tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3);
949 tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y);
950 tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2);
951 tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U);
952 tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2);
953 tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V);
954 tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2);
955 tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS);
956 tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL);
957 tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS);
958 tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE);
959 tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1);
960 tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2);
961 tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3);
963 for (i = 0; i < 60; i++)
964 tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2));
965 for (i = 0; i < 60; i++)
966 tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2));
967 for (i = 0; i < 43; i++)
968 tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2));
969 for (i = 0; i < 43; i++)
970 tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2));
972 tv_priv->save_TV_DAC = I915_READ(TV_DAC);
973 tv_priv->save_TV_CTL = I915_READ(TV_CTL);
977 intel_tv_restore(struct drm_output *output)
979 struct drm_device *dev = output->dev;
980 struct drm_i915_private *dev_priv = dev->dev_private;
981 struct intel_output *intel_output = output->driver_private;
982 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
983 struct drm_crtc *crtc = output->crtc;
984 struct intel_crtc *intel_crtc;
987 /* FIXME: No CRTC? */
991 intel_crtc = crtc->driver_private;
992 I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1);
993 I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2);
994 I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3);
995 I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1);
996 I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2);
997 I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3);
998 I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4);
999 I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5);
1000 I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6);
1001 I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7);
1002 I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1);
1003 I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2);
1004 I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3);
1006 I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y);
1007 I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2);
1008 I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U);
1009 I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2);
1010 I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V);
1011 I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2);
1012 I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS);
1013 I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL);
1016 int pipeconf_reg = (intel_crtc->pipe == 0) ?
1017 PIPEACONF : PIPEBCONF;
1018 int dspcntr_reg = (intel_crtc->plane == 0) ?
1019 DSPACNTR : DSPBCNTR;
1020 int pipeconf = I915_READ(pipeconf_reg);
1021 int dspcntr = I915_READ(dspcntr_reg);
1022 int dspbase_reg = (intel_crtc->plane == 0) ?
1023 DSPABASE : DSPBBASE;
1024 /* Pipe must be off here */
1025 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1026 /* Flush the plane changes */
1027 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1029 if (!IS_I9XX(dev)) {
1030 /* Wait for vblank for the disable to take effect */
1031 intel_wait_for_vblank(dev);
1034 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1035 /* Wait for vblank for the disable to take effect. */
1036 intel_wait_for_vblank(dev);
1038 /* Filter ctl must be set before TV_WIN_SIZE */
1039 I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1);
1040 I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2);
1041 I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3);
1042 I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS);
1043 I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE);
1044 I915_WRITE(pipeconf_reg, pipeconf);
1045 I915_WRITE(dspcntr_reg, dspcntr);
1046 /* Flush the plane changes */
1047 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1050 for (i = 0; i < 60; i++)
1051 I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]);
1052 for (i = 0; i < 60; i++)
1053 I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]);
1054 for (i = 0; i < 43; i++)
1055 I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]);
1056 for (i = 0; i < 43; i++)
1057 I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]);
1059 I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
1060 I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
1063 static const struct tv_mode *
1064 intel_tv_mode_lookup (char *tv_format)
1068 for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
1069 const struct tv_mode *tv_mode = &tv_modes[i];
1071 if (!strcmp(tv_format, tv_mode->name))
1077 static const struct tv_mode *
1078 intel_tv_mode_find (struct drm_output *output)
1080 struct intel_output *intel_output = output->driver_private;
1081 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1083 return intel_tv_mode_lookup(tv_priv->tv_format);
1086 static enum drm_mode_status
1087 intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode)
1089 const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1091 /* Ensure TV refresh is close to desired refresh */
1092 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
1094 return MODE_CLOCK_RANGE;
1099 intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode,
1100 struct drm_display_mode *adjusted_mode)
1102 struct drm_device *dev = output->dev;
1103 struct drm_mode_config *drm_config = &dev->mode_config;
1104 const struct tv_mode *tv_mode = intel_tv_mode_find (output);
1105 struct drm_output *other_output;
1110 /* FIXME: lock output list */
1111 list_for_each_entry(other_output, &drm_config->output_list, head) {
1112 if (other_output != output &&
1113 other_output->crtc == output->crtc)
1117 adjusted_mode->clock = tv_mode->clock;
1122 intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,
1123 struct drm_display_mode *adjusted_mode)
1125 struct drm_device *dev = output->dev;
1126 struct drm_i915_private *dev_priv = dev->dev_private;
1127 struct drm_crtc *crtc = output->crtc;
1128 struct intel_crtc *intel_crtc = crtc->driver_private;
1129 struct intel_output *intel_output = output->driver_private;
1130 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1131 const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1133 u32 hctl1, hctl2, hctl3;
1134 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1135 u32 scctl1, scctl2, scctl3;
1137 const struct video_levels *video_levels;
1138 const struct color_conversion *color_conversion;
1142 return; /* can't happen (mode_prepare prevents this) */
1146 switch (tv_priv->type) {
1148 case TV_TYPE_UNKNOWN:
1149 case TV_TYPE_COMPOSITE:
1150 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1151 video_levels = tv_mode->composite_levels;
1152 color_conversion = tv_mode->composite_color;
1153 burst_ena = tv_mode->burst_ena;
1155 case TV_TYPE_COMPONENT:
1156 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1157 video_levels = &component_levels;
1158 if (tv_mode->burst_ena)
1159 color_conversion = &sdtv_csc_yprpb;
1161 color_conversion = &hdtv_csc_yprpb;
1164 case TV_TYPE_SVIDEO:
1165 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1166 video_levels = tv_mode->svideo_levels;
1167 color_conversion = tv_mode->svideo_color;
1168 burst_ena = tv_mode->burst_ena;
1171 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1172 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1174 hctl2 = (tv_mode->hburst_start << 16) |
1175 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1178 hctl2 |= TV_BURST_ENA;
1180 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1181 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1183 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1184 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1185 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1187 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1188 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1189 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1191 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1192 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1193 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1195 if (tv_mode->veq_ena)
1196 vctl3 |= TV_EQUAL_ENA;
1198 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1199 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1201 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1202 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1204 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1205 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1207 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1208 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1210 if (intel_crtc->pipe == 1)
1211 tv_ctl |= TV_ENC_PIPEB_SELECT;
1212 tv_ctl |= tv_mode->oversample;
1214 if (tv_mode->progressive)
1215 tv_ctl |= TV_PROGRESSIVE;
1216 if (tv_mode->trilevel_sync)
1217 tv_ctl |= TV_TRILEVEL_SYNC;
1218 if (tv_mode->pal_burst)
1219 tv_ctl |= TV_PAL_BURST;
1221 if (tv_mode->dda1_inc)
1222 scctl1 |= TV_SC_DDA1_EN;
1224 if (tv_mode->dda2_inc)
1225 scctl1 |= TV_SC_DDA2_EN;
1227 if (tv_mode->dda3_inc)
1228 scctl1 |= TV_SC_DDA3_EN;
1230 scctl1 |= tv_mode->sc_reset;
1231 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1232 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1234 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1235 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1237 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1238 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1240 /* Enable two fixes for the chips that need them. */
1241 if (dev->pci_device < 0x2772)
1242 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1244 I915_WRITE(TV_H_CTL_1, hctl1);
1245 I915_WRITE(TV_H_CTL_2, hctl2);
1246 I915_WRITE(TV_H_CTL_3, hctl3);
1247 I915_WRITE(TV_V_CTL_1, vctl1);
1248 I915_WRITE(TV_V_CTL_2, vctl2);
1249 I915_WRITE(TV_V_CTL_3, vctl3);
1250 I915_WRITE(TV_V_CTL_4, vctl4);
1251 I915_WRITE(TV_V_CTL_5, vctl5);
1252 I915_WRITE(TV_V_CTL_6, vctl6);
1253 I915_WRITE(TV_V_CTL_7, vctl7);
1254 I915_WRITE(TV_SC_CTL_1, scctl1);
1255 I915_WRITE(TV_SC_CTL_2, scctl2);
1256 I915_WRITE(TV_SC_CTL_3, scctl3);
1258 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
1259 color_conversion->gy);
1260 I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
1261 color_conversion->ay);
1262 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
1263 color_conversion->gu);
1264 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
1265 color_conversion->au);
1266 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
1267 color_conversion->gv);
1268 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
1269 color_conversion->av);
1271 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1272 I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1273 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1275 int pipeconf_reg = (intel_crtc->pipe == 0) ?
1276 PIPEACONF : PIPEBCONF;
1277 int dspcntr_reg = (intel_crtc->plane == 0) ?
1278 DSPACNTR : DSPBCNTR;
1279 int pipeconf = I915_READ(pipeconf_reg);
1280 int dspcntr = I915_READ(dspcntr_reg);
1281 int dspbase_reg = (intel_crtc->plane == 0) ?
1282 DSPABASE : DSPBBASE;
1283 int xpos = 0x0, ypos = 0x0;
1284 unsigned int xsize, ysize;
1285 /* Pipe must be off here */
1286 I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
1287 /* Flush the plane changes */
1288 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1290 /* Wait for vblank for the disable to take effect */
1292 intel_wait_for_vblank(dev);
1294 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1295 /* Wait for vblank for the disable to take effect. */
1296 intel_wait_for_vblank(dev);
1298 /* Filter ctl must be set before TV_WIN_SIZE */
1299 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1300 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1301 if (tv_mode->progressive)
1302 ysize = tv_mode->nbr_end + 1;
1304 ysize = 2*tv_mode->nbr_end + 1;
1306 xpos += tv_priv->margin[TV_MARGIN_LEFT];
1307 ypos += tv_priv->margin[TV_MARGIN_TOP];
1308 xsize -= (tv_priv->margin[TV_MARGIN_LEFT] +
1309 tv_priv->margin[TV_MARGIN_RIGHT]);
1310 ysize -= (tv_priv->margin[TV_MARGIN_TOP] +
1311 tv_priv->margin[TV_MARGIN_BOTTOM]);
1312 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1313 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1315 I915_WRITE(pipeconf_reg, pipeconf);
1316 I915_WRITE(dspcntr_reg, dspcntr);
1317 /* Flush the plane changes */
1318 I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
1322 for (i = 0; i < 60; i++)
1323 I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1324 for (i = 0; i < 60; i++)
1325 I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1326 for (i = 0; i < 43; i++)
1327 I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
1328 for (i = 0; i < 43; i++)
1329 I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
1330 I915_WRITE(TV_DAC, 0);
1331 I915_WRITE(TV_CTL, tv_ctl);
1334 static const struct drm_display_mode reported_modes[] = {
1336 .name = "NTSC 480i",
1339 .hsync_start = 1368,
1344 .vsync_start = 1027,
1347 .type = DRM_MODE_TYPE_DRIVER,
1352 * Detects TV presence by checking for load.
1354 * Requires that the current pipe's DPLL is active.
1356 * \return TRUE if TV is connected.
1357 * \return FALSE if TV is disconnected.
1360 intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
1362 struct drm_device *dev = output->dev;
1363 struct drm_i915_private *dev_priv = dev->dev_private;
1364 struct intel_output *intel_output = output->driver_private;
1365 u32 tv_ctl, save_tv_ctl;
1366 u32 tv_dac, save_tv_dac;
1367 int type = TV_TYPE_UNKNOWN;
1369 tv_dac = I915_READ(TV_DAC);
1371 * Detect TV by polling)
1373 if (intel_output->load_detect_temp) {
1374 /* TV not currently running, prod it with destructive detect */
1375 save_tv_dac = tv_dac;
1376 tv_ctl = I915_READ(TV_CTL);
1377 save_tv_ctl = tv_ctl;
1378 tv_ctl &= ~TV_ENC_ENABLE;
1379 tv_ctl &= ~TV_TEST_MODE_MASK;
1380 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1381 tv_dac &= ~TVDAC_SENSE_MASK;
1382 tv_dac |= (TVDAC_STATE_CHG_EN |
1390 I915_WRITE(TV_CTL, tv_ctl);
1391 I915_WRITE(TV_DAC, tv_dac);
1392 intel_wait_for_vblank(dev);
1393 tv_dac = I915_READ(TV_DAC);
1394 I915_WRITE(TV_DAC, save_tv_dac);
1395 I915_WRITE(TV_CTL, save_tv_ctl);
1403 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1404 DRM_DEBUG("Detected Composite TV connection\n");
1405 type = TV_TYPE_COMPOSITE;
1406 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1407 DRM_DEBUG("Detected S-Video TV connection\n");
1408 type = TV_TYPE_SVIDEO;
1409 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1410 DRM_DEBUG("Detected Component TV connection\n");
1411 type = TV_TYPE_COMPONENT;
1413 DRM_DEBUG("No TV connection detected\n");
1414 type = TV_TYPE_NONE;
1421 intel_tv_format_configure_property (struct drm_output *output);
1424 * Detect the TV connection.
1426 * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure
1427 * we have a pipe programmed in order to probe the TV.
1429 static enum drm_output_status
1430 intel_tv_detect(struct drm_output *output)
1432 struct drm_crtc *crtc;
1433 struct drm_display_mode mode;
1434 struct intel_output *intel_output = output->driver_private;
1435 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1437 int type = tv_priv->type;
1439 mode = reported_modes[0];
1440 drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1442 /* FIXME: pipe allocation for load detection */
1443 crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode);
1445 type = intel_tv_detect_type(crtc, output);
1446 i830ReleaseLoadDetectPipe (output, dpms_mode);
1449 if (type != tv_priv->type) {
1450 tv_priv->type = type;
1451 intel_tv_format_configure_property (output);
1456 return output_status_disconnected;
1457 case TV_TYPE_UNKNOWN:
1458 return output_status_unknown;
1460 return output_status_connected;
1464 static struct input_res {
1467 } input_res_table[] =
1469 {"640x480", 640, 480},
1470 {"800x600", 800, 600},
1471 {"1024x768", 1024, 768},
1472 {"1280x1024", 1280, 1024},
1473 {"848x480", 848, 480},
1474 {"1280x720", 1280, 720},
1475 {"1920x1080", 1920, 1080},
1479 * Stub get_modes function.
1481 * This should probably return a set of fixed modes, unless we can figure out
1482 * how to probe modes off of TV connections.
1486 intel_tv_get_modes(struct drm_output *output)
1488 struct drm_display_mode *mode_ptr;
1489 const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1492 for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
1494 struct input_res *input = &input_res_table[j];
1495 unsigned int hactive_s = input->w;
1496 unsigned int vactive_s = input->h;
1498 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1501 if (input->w > 1024 && (!tv_mode->progressive
1502 && !tv_mode->component_only))
1505 mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
1507 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1509 mode_ptr->hdisplay = hactive_s;
1510 mode_ptr->hsync_start = hactive_s + 1;
1511 mode_ptr->hsync_end = hactive_s + 64;
1512 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1513 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1514 mode_ptr->htotal = hactive_s + 96;
1516 mode_ptr->vdisplay = vactive_s;
1517 mode_ptr->vsync_start = vactive_s + 1;
1518 mode_ptr->vsync_end = vactive_s + 32;
1519 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1520 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1521 mode_ptr->vtotal = vactive_s + 33;
1523 mode_ptr->clock = (int) (tv_mode->refresh *
1525 mode_ptr->htotal / 1000) / 1000;
1527 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1528 drm_mode_probed_add(output, mode_ptr);
1535 intel_tv_destroy (struct drm_output *output)
1537 if (output->driver_private)
1538 drm_free(output->driver_private, sizeof(struct intel_tv_priv),
1543 intel_tv_format_set_property(struct drm_output *output,
1544 struct drm_property *prop, uint64_t val)
1547 struct intel_output *intel_output = output->driver_private;
1548 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1549 const struct tv_mode *tv_mode =
1550 intel_tv_mode_lookup(tv_priv->tv_format);
1554 tv_mode = &tv_modes[0];
1555 err = RRChangeOutputProperty (output->randr_output, tv_format_atom,
1556 XA_ATOM, 32, PropModeReplace, 1,
1557 &tv_format_name_atoms[tv_mode - tv_modes],
1559 return err == Success;
1566 * Configure the TV_FORMAT property to list only supported formats
1568 * Unless the connector is component, list only the formats supported by
1569 * svideo and composite
1573 intel_tv_format_configure_property(struct drm_output *output)
1576 struct intel_output *intel_output = output->driver_private;
1577 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1578 Atom current_atoms[NUM_TV_MODES];
1582 if (!output->randr_output)
1585 for (i = 0; i < NUM_TV_MODES; i++)
1586 if (!tv_modes[i].component_only ||
1587 tv_priv->type == TV_TYPE_COMPONENT)
1588 current_atoms[num_atoms++] = tv_format_name_atoms[i];
1590 return RRConfigureOutputProperty(output->randr_output, tv_format_atom,
1592 num_atoms, (INT32 *) current_atoms);
1598 intel_tv_create_resources(struct drm_output *output)
1600 struct drm_device *dev = output->dev;
1601 struct intel_output *intel_output = output->driver_private;
1602 struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1606 /* Set up the tv_format property, which takes effect on mode set
1607 * and accepts strings that match exactly
1609 tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1,
1612 for (i = 0; i < NUM_TV_MODES; i++)
1613 tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name,
1614 strlen (tv_modes[i].name),
1617 err = intel_tv_format_configure_property (output);
1620 xf86DrvMsg(dev->scrnIndex, X_ERROR,
1621 "RRConfigureOutputProperty error, %d\n", err);
1624 /* Set the current value of the tv_format property */
1625 if (!intel_tv_format_set_property (output))
1626 xf86DrvMsg(dev->scrnIndex, X_ERROR,
1627 "RRChangeOutputProperty error, %d\n", err);
1629 for (i = 0; i < 4; i++)
1632 margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]),
1637 err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i],
1638 TRUE, TRUE, FALSE, 2, range);
1641 xf86DrvMsg(dev->scrnIndex, X_ERROR,
1642 "RRConfigureOutputProperty error, %d\n", err);
1644 err = RRChangeOutputProperty(output->randr_output, margin_atoms[i],
1645 XA_INTEGER, 32, PropModeReplace,
1646 1, &tv_priv->margin[i],
1649 xf86DrvMsg(dev->scrnIndex, X_ERROR,
1650 "RRChangeOutputProperty error, %d\n", err);
1656 intel_tv_set_property(struct drm_output *output, struct drm_property *property,
1659 struct drm_device *dev = output->dev;
1662 if (property == dev->mode_config.tv_left_margin_property ||
1663 property == dev->mode_config.tv_right_margin_property ||
1664 property == dev->mode_config.tv_top_margin_property ||
1665 property == dev->mode_config.tv_bottom_margin_property) {
1666 ret = drm_output_property_set_value(output, property, val);
1668 /* TV mode handling here */
1674 static const struct drm_output_funcs intel_tv_output_funcs = {
1675 .dpms = intel_tv_dpms,
1676 .save = intel_tv_save,
1677 .restore = intel_tv_restore,
1678 .mode_valid = intel_tv_mode_valid,
1679 .mode_fixup = intel_tv_mode_fixup,
1680 .prepare = intel_output_prepare,
1681 .mode_set = intel_tv_mode_set,
1682 .commit = intel_output_commit,
1683 .detect = intel_tv_detect,
1684 .get_modes = intel_tv_get_modes,
1685 .cleanup = intel_tv_destroy,
1686 .set_property = intel_tv_set_property,
1690 intel_tv_init(struct drm_device *dev)
1692 struct drm_i915_private *dev_priv = dev->dev_private;
1693 struct drm_output *output;
1694 struct intel_output *intel_output;
1695 struct intel_tv_priv *tv_priv;
1696 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1698 /* FIXME: better TV detection and/or quirks */
1700 if (tv_priv->quirk_flag & QUIRK_IGNORE_TV)
1703 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1707 * Sanity check the TV output by checking to see if the
1708 * DAC register holds a value
1710 save_tv_dac = I915_READ(TV_DAC);
1712 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1713 tv_dac_on = I915_READ(TV_DAC);
1715 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1716 tv_dac_off = I915_READ(TV_DAC);
1718 I915_WRITE(TV_DAC, save_tv_dac);
1721 * If the register does not hold the state change enable
1722 * bit, (either as a 0 or a 1), assume it doesn't really
1725 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1726 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1729 output = drm_output_create(dev, &intel_tv_output_funcs,
1730 DRM_MODE_OUTPUT_TVDAC);
1735 intel_output = drm_calloc(1, sizeof(struct intel_output) +
1736 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
1737 if (!intel_output) {
1738 drm_output_destroy(output);
1742 tv_priv = (struct intel_tv_priv *)(intel_output + 1);
1743 intel_output->type = INTEL_OUTPUT_TVOUT;
1744 output->possible_crtcs = ((1 << 0) | (1 << 1));
1745 output->possible_clones = (1 << INTEL_OUTPUT_TVOUT);
1746 intel_output->dev_priv = tv_priv;
1747 tv_priv->type = TV_TYPE_UNKNOWN;
1749 tv_priv->tv_format = NULL;
1751 /* BIOS margin values */
1752 tv_priv->margin[TV_MARGIN_LEFT] = 54;
1753 tv_priv->margin[TV_MARGIN_TOP] = 36;
1754 tv_priv->margin[TV_MARGIN_RIGHT] = 46;
1755 tv_priv->margin[TV_MARGIN_BOTTOM] = 37;
1757 if (!tv_priv->tv_format)
1758 tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL);
1760 output->driver_private = intel_output;
1761 output->interlace_allowed = FALSE;
1762 output->doublescan_allowed = FALSE;