650c46f75969af95f9125c0391089d56d312948e
[profile/ivi/libdrm.git] / linux-core / intel_tv.c
1 /*
2  * Copyright © 2006 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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.
22  *
23  * Authors:
24  *    Eric Anholt <eric@anholt.net>
25  *
26  */
27
28 /** @file
29  * Integrated TV-out support for the 915GM and 945GM.
30  */
31
32 #include "drmP.h"
33 #include "drm.h"
34 #include "drm_crtc.h"
35 #include "drm_edid.h"
36 #include "intel_drv.h"
37 #include "i915_drm.h"
38 #include "i915_drv.h"
39
40 enum tv_margin {
41         TV_MARGIN_LEFT, TV_MARGIN_TOP,
42         TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
43 };
44
45 /** Private structure for the integrated TV support */
46 struct intel_tv_priv {
47         int type;
48         char *tv_format;
49         int margin[4];
50         u32 save_TV_H_CTL_1;
51         u32 save_TV_H_CTL_2;
52         u32 save_TV_H_CTL_3;
53         u32 save_TV_V_CTL_1;
54         u32 save_TV_V_CTL_2;
55         u32 save_TV_V_CTL_3;
56         u32 save_TV_V_CTL_4;
57         u32 save_TV_V_CTL_5;
58         u32 save_TV_V_CTL_6;
59         u32 save_TV_V_CTL_7;
60         u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
61
62         u32 save_TV_CSC_Y;
63         u32 save_TV_CSC_Y2;
64         u32 save_TV_CSC_U;
65         u32 save_TV_CSC_U2;
66         u32 save_TV_CSC_V;
67         u32 save_TV_CSC_V2;
68         u32 save_TV_CLR_KNOBS;
69         u32 save_TV_CLR_LEVEL;
70         u32 save_TV_WIN_POS;
71         u32 save_TV_WIN_SIZE;
72         u32 save_TV_FILTER_CTL_1;
73         u32 save_TV_FILTER_CTL_2;
74         u32 save_TV_FILTER_CTL_3;
75
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];
80
81         u32 save_TV_DAC;
82         u32 save_TV_CTL;
83 };
84
85 struct video_levels {
86         int blank, black, burst;
87 };
88
89 struct color_conversion {
90         u16 ry, gy, by, ay;
91         u16 ru, gu, bu, au;
92         u16 rv, gv, bv, av;
93 };
94
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,
148 };
149
150 /*
151  * Color conversion values have 3 separate fixed point formats:
152  *
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)
171  *
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)
179  *
180  * Simple conversion function:
181  *
182  * static u32
183  * float_to_csc_11(float f)
184  * {
185  *     u32 exp;
186  *     u32 mant;
187  *     u32 ret;
188  * 
189  *     if (f < 0)
190  *         f = -f;
191  * 
192  *     if (f >= 1) {
193  *         exp = 0x7;
194  *         mant = 1 << 8;
195  *     } else {
196  *         for (exp = 0; exp < 3 && f < 0.5; exp++)
197  *             f *= 2.0;
198  *         mant = (f * (1 << 9) + 0.5);
199  *         if (mant >= (1 << 9))
200  *             mant = (1 << 9) - 1;
201  *     }
202  *     ret = (exp << 9) | mant;
203  *     return ret;
204  * }
205  */
206
207 /*
208  * Behold, magic numbers!  If we plant them they might grow a big
209  * s-video cable to the sky... or something.
210  *
211  * Pre-converted to appropriate hex value.
212  */
213
214 /*
215  * PAL & NTSC values for composite & s-video connections
216  */
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,
221 };
222
223 static const struct video_levels ntsc_m_levels_composite = {
224         .blank = 225, .black = 267, .burst = 113,
225 };
226
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,
231 };
232
233 static const struct video_levels ntsc_m_levels_svideo = {
234         .blank = 266, .black = 316, .burst = 133,
235 };
236
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,
241 };
242
243 static const struct video_levels ntsc_j_levels_composite = {
244         .blank = 225, .black = 225, .burst = 113,
245 };
246
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,
251 };
252
253 static const struct video_levels ntsc_j_levels_svideo = {
254         .blank = 266, .black = 266, .burst = 133,
255 };
256
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,
261 };
262         
263 static const struct video_levels pal_levels_composite = {
264         .blank = 237, .black = 237, .burst = 118,
265 };
266
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,
271 };
272
273 static const struct video_levels pal_levels_svideo = {
274         .blank = 280, .black = 280, .burst = 139,
275 };
276
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,
281 };
282
283 static const struct video_levels pal_m_levels_composite = {
284         .blank = 225, .black = 267, .burst = 113,
285 };
286
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,
291 };
292
293 static const struct video_levels pal_m_levels_svideo = {
294         .blank = 266, .black = 316, .burst = 133,
295 };
296
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,
301 };
302
303 static const struct video_levels pal_n_levels_composite = {
304         .blank = 225, .black = 267, .burst = 118,
305 };
306
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,
311 };
312
313 static const struct video_levels pal_n_levels_svideo = {
314         .blank = 266, .black = 316, .burst = 139,
315 };
316
317 /*
318  * Component connections
319  */
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,
324 };
325
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,
330 };
331
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,
336 };
337
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,
342 };
343
344 static const struct video_levels component_levels = {
345         .blank = 279, .black = 279, .burst = 0,
346 };
347
348
349 struct tv_mode {
350         char *name;
351         int clock;
352         int refresh; /* in millihertz (for precision) */
353         u32 oversample;
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;
357         bool veq_ena;
358         int veq_start_f1, veq_start_f2, veq_len;
359         int vi_end_f1, vi_end_f2, nbr_end;
360         bool burst_ena;
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;
366         /*
367          * subcarrier programming
368          */
369         int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
370         u32 sc_reset;
371         bool pal_burst;
372         /*
373          * blank/black levels
374          */
375         const struct video_levels *composite_levels, *svideo_levels;
376         const struct color_conversion *composite_color, *svideo_color;
377         const u32 *filter_table;
378         int max_srcw;
379 };
380
381
382 /*
383  * Sub carrier DDA
384  *
385  *  I think this works as follows:
386  *
387  *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
388  *
389  * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
390  *
391  * So,
392  *  dda1_ideal = subcarrier/pixel * 4096
393  *  dda1_inc = floor (dda1_ideal)
394  *  dda2 = dda1_ideal - dda1_inc
395  *
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
399  *
400  * To invert this,
401  *
402  *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
403  *
404  * The constants below were all computed using a 107.520MHz clock
405  */
406  
407 /**
408  * Register programming values for TV modes.
409  *
410  * These values account for -1s required.
411  */
412
413 const static struct tv_mode tv_modes[] = {
414         {
415                 .name           = "NTSC-M",
416                 .clock          = 107520,       
417                 .refresh        = 29970,
418                 .oversample     = TV_OVERSAMPLE_8X,
419                 .component_only = 0,
420                 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
421
422                 .hsync_end      = 64,               .hblank_end         = 124,
423                 .hblank_start   = 836,              .htotal             = 857,
424
425                 .progressive    = FALSE,            .trilevel_sync = FALSE,
426
427                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
428                 .vsync_len      = 6,
429
430                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
431                 .veq_start_f2   = 1,                .veq_len            = 18,
432
433                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
434                 .nbr_end        = 240,
435
436                 .burst_ena      = TRUE,
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,
442
443                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
444                 .dda1_inc       =    136,
445                 .dda2_inc       =   7624,           .dda2_size          =  20013,
446                 .dda3_inc       =      0,           .dda3_size          =      0,
447                 .sc_reset       = TV_SC_RESET_EVERY_4,
448                 .pal_burst      = FALSE,
449
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,
454
455                 .filter_table = filter_table,
456         },
457         {
458                 .name           = "NTSC-443",
459                 .clock          = 107520,       
460                 .refresh        = 29970,
461                 .oversample     = TV_OVERSAMPLE_8X,
462                 .component_only = 0,
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,
466
467                 .progressive    = FALSE,            .trilevel_sync = FALSE,
468
469                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
470                 .vsync_len      = 6,
471
472                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
473                 .veq_start_f2   = 1,                .veq_len            = 18,
474
475                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
476                 .nbr_end        = 240,
477
478                 .burst_ena      = 8,
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,
484
485                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
486                 .dda1_inc       =    168,
487                 .dda2_inc       =  18557,       .dda2_size      =  20625,
488                 .dda3_inc       =      0,       .dda3_size      =      0,
489                 .sc_reset   = TV_SC_RESET_EVERY_8,
490                 .pal_burst  = TRUE,
491
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,
496
497                 .filter_table = filter_table,
498         },
499         {
500                 .name           = "NTSC-J",
501                 .clock          = 107520,       
502                 .refresh        = 29970,
503                 .oversample     = TV_OVERSAMPLE_8X,
504                 .component_only = 0,
505
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,
509
510                 .progressive    = FALSE,    .trilevel_sync = FALSE,
511
512                 .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
513                 .vsync_len      = 6,
514
515                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
516                 .veq_start_f2 = 1,          .veq_len            = 18,
517
518                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
519                 .nbr_end        = 240,
520
521                 .burst_ena      = TRUE,
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,
527
528                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
529                 .dda1_inc       =    136,
530                 .dda2_inc       =   7624,           .dda2_size          =  20013,
531                 .dda3_inc       =      0,           .dda3_size          =      0,
532                 .sc_reset       = TV_SC_RESET_EVERY_4,
533                 .pal_burst      = FALSE,
534
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,
539
540                 .filter_table = filter_table,
541         },
542         {
543                 .name           = "PAL-M",
544                 .clock          = 107520,       
545                 .refresh        = 29970,
546                 .oversample     = TV_OVERSAMPLE_8X,
547                 .component_only = 0,
548
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,
552
553                 .progressive    = FALSE,            .trilevel_sync = FALSE,
554
555                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
556                 .vsync_len      = 6,
557
558                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
559                 .veq_start_f2   = 1,                .veq_len            = 18,
560
561                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
562                 .nbr_end        = 240,
563
564                 .burst_ena      = TRUE,
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,
570
571                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
572                 .dda1_inc       =    136,
573                 .dda2_inc       =    7624,          .dda2_size          =  20013,
574                 .dda3_inc       =      0,           .dda3_size          =      0,
575                 .sc_reset       = TV_SC_RESET_EVERY_4,
576                 .pal_burst  = FALSE,
577
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,
582
583                 .filter_table = filter_table,
584         },
585         {
586                 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
587                 .name       = "PAL-N",
588                 .clock          = 107520,       
589                 .refresh        = 25000,
590                 .oversample     = TV_OVERSAMPLE_8X,
591                 .component_only = 0,
592
593                 .hsync_end      = 64,               .hblank_end         = 128,
594                 .hblank_start = 844,        .htotal             = 863,
595
596                 .progressive  = FALSE,    .trilevel_sync = FALSE,
597
598
599                 .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
600                 .vsync_len      = 6,
601
602                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
603                 .veq_start_f2   = 1,                .veq_len            = 18,
604
605                 .vi_end_f1      = 24,               .vi_end_f2          = 25,
606                 .nbr_end        = 286,
607
608                 .burst_ena      = TRUE,
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,
614
615
616                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
617                 .dda1_inc       =    168,
618                 .dda2_inc       =  18557,       .dda2_size      =  20625,
619                 .dda3_inc       =      0,       .dda3_size      =      0,
620                 .sc_reset   = TV_SC_RESET_EVERY_8,
621                 .pal_burst  = TRUE,
622
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,
627
628                 .filter_table = filter_table,
629         },
630         {
631                 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
632                 .name       = "PAL",
633                 .clock          = 107520,       
634                 .refresh        = 25000,
635                 .oversample     = TV_OVERSAMPLE_8X,
636                 .component_only = 0,
637
638                 .hsync_end      = 64,               .hblank_end         = 128,
639                 .hblank_start   = 844,      .htotal             = 863,
640
641                 .progressive    = FALSE,    .trilevel_sync = FALSE,
642
643                 .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
644                 .vsync_len      = 5,
645
646                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
647                 .veq_start_f2   = 1,        .veq_len            = 15,
648
649                 .vi_end_f1      = 24,               .vi_end_f2          = 25,
650                 .nbr_end        = 286,
651
652                 .burst_ena      = TRUE,
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,
658
659                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
660                 .dda1_inc       =    168,
661                 .dda2_inc       =  18557,       .dda2_size      =  20625,
662                 .dda3_inc       =      0,       .dda3_size      =      0,
663                 .sc_reset   = TV_SC_RESET_EVERY_8,
664                 .pal_burst  = TRUE,
665
666                 .composite_levels = &pal_levels_composite,
667                 .composite_color = &pal_csc_composite,
668                 .svideo_levels  = &pal_levels_svideo,
669                 .svideo_color = &pal_csc_svideo,
670
671                 .filter_table = filter_table,
672         },
673         {
674                 .name       = "480p@59.94Hz",
675                 .clock  = 107520,       
676                 .refresh        = 59940,
677                 .oversample     = TV_OVERSAMPLE_4X,
678                 .component_only = 1,
679
680                 .hsync_end      = 64,               .hblank_end         = 122,
681                 .hblank_start   = 842,              .htotal             = 857,
682
683                 .progressive    = TRUE,.trilevel_sync = FALSE,
684
685                 .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
686                 .vsync_len      = 12,
687
688                 .veq_ena        = FALSE,
689
690                 .vi_end_f1      = 44,               .vi_end_f2          = 44,
691                 .nbr_end        = 496,
692
693                 .burst_ena      = FALSE,
694
695                 .filter_table = filter_table,
696         },
697         {
698                 .name       = "480p@60Hz",
699                 .clock  = 107520,       
700                 .refresh        = 60000,
701                 .oversample     = TV_OVERSAMPLE_4X,
702                 .component_only = 1,
703
704                 .hsync_end      = 64,               .hblank_end         = 122,
705                 .hblank_start   = 842,              .htotal             = 856,
706
707                 .progressive    = TRUE,.trilevel_sync = FALSE,
708
709                 .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
710                 .vsync_len      = 12,
711
712                 .veq_ena        = FALSE,
713
714                 .vi_end_f1      = 44,               .vi_end_f2          = 44,
715                 .nbr_end        = 496,
716
717                 .burst_ena      = FALSE,
718
719                 .filter_table = filter_table,
720         },
721         {
722                 .name       = "576p",
723                 .clock  = 107520,       
724                 .refresh        = 50000,
725                 .oversample     = TV_OVERSAMPLE_4X,
726                 .component_only = 1,
727
728                 .hsync_end      = 64,               .hblank_end         = 139,
729                 .hblank_start   = 859,              .htotal             = 863,
730
731                 .progressive    = TRUE,         .trilevel_sync = FALSE,
732
733                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
734                 .vsync_len      = 10,
735
736                 .veq_ena        = FALSE,
737
738                 .vi_end_f1      = 48,               .vi_end_f2          = 48,
739                 .nbr_end        = 575,
740
741                 .burst_ena      = FALSE,
742
743                 .filter_table = filter_table,
744         },
745         {
746                 .name       = "720p@60Hz",
747                 .clock          = 148800,       
748                 .refresh        = 60000,
749                 .oversample     = TV_OVERSAMPLE_2X,
750                 .component_only = 1,
751
752                 .hsync_end      = 80,               .hblank_end         = 300,
753                 .hblank_start   = 1580,             .htotal             = 1649,
754
755                 .progressive    = TRUE,             .trilevel_sync = TRUE,
756
757                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
758                 .vsync_len      = 10,
759
760                 .veq_ena        = FALSE,
761
762                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
763                 .nbr_end        = 719,
764
765                 .burst_ena      = FALSE,
766
767                 .filter_table = filter_table,
768         },
769         {
770                 .name       = "720p@59.94Hz",
771                 .clock          = 148800,       
772                 .refresh        = 59940,
773                 .oversample     = TV_OVERSAMPLE_2X,
774                 .component_only = 1,
775
776                 .hsync_end      = 80,               .hblank_end         = 300,
777                 .hblank_start   = 1580,             .htotal             = 1651,
778
779                 .progressive    = TRUE,             .trilevel_sync = TRUE,
780
781                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
782                 .vsync_len      = 10,
783
784                 .veq_ena        = FALSE,
785
786                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
787                 .nbr_end        = 719,
788
789                 .burst_ena      = FALSE,
790
791                 .filter_table = filter_table,
792         },
793         {
794                 .name       = "720p@50Hz",
795                 .clock          = 148800,       
796                 .refresh        = 50000,
797                 .oversample     = TV_OVERSAMPLE_2X,
798                 .component_only = 1,
799
800                 .hsync_end      = 80,               .hblank_end         = 300,
801                 .hblank_start   = 1580,             .htotal             = 1979,
802
803                 .progressive    = TRUE,                 .trilevel_sync = TRUE,
804
805                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
806                 .vsync_len      = 10,
807
808                 .veq_ena        = FALSE,
809
810                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
811                 .nbr_end        = 719,
812
813                 .burst_ena      = FALSE,
814
815                 .filter_table = filter_table,
816                 .max_srcw = 800
817         },
818         {
819                 .name       = "1080i@50Hz",
820                 .clock          = 148800,       
821                 .refresh        = 25000,
822                 .oversample     = TV_OVERSAMPLE_2X,
823                 .component_only = 1,
824
825                 .hsync_end      = 88,               .hblank_end         = 235,
826                 .hblank_start   = 2155,             .htotal             = 2639,
827
828                 .progressive    = FALSE,            .trilevel_sync = TRUE,
829
830                 .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
831                 .vsync_len      = 10,
832
833                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
834                 .veq_start_f2   = 4,        .veq_len            = 10,
835
836
837                 .vi_end_f1      = 21,           .vi_end_f2          = 22,
838                 .nbr_end        = 539,
839
840                 .burst_ena      = FALSE,
841
842                 .filter_table = filter_table,
843         },
844         {
845                 .name       = "1080i@60Hz",
846                 .clock          = 148800,       
847                 .refresh        = 30000,
848                 .oversample     = TV_OVERSAMPLE_2X,
849                 .component_only = 1,
850
851                 .hsync_end      = 88,               .hblank_end         = 235,
852                 .hblank_start   = 2155,             .htotal             = 2199,
853
854                 .progressive    = FALSE,            .trilevel_sync = TRUE,
855
856                 .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
857                 .vsync_len      = 10,
858
859                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
860                 .veq_start_f2   = 4,                .veq_len            = 10,
861
862
863                 .vi_end_f1      = 21,               .vi_end_f2          = 22,
864                 .nbr_end        = 539,
865
866                 .burst_ena      = FALSE,
867
868                 .filter_table = filter_table,
869         },
870         {
871                 .name       = "1080i@59.94Hz",
872                 .clock          = 148800,       
873                 .refresh        = 29970,
874                 .oversample     = TV_OVERSAMPLE_2X,
875                 .component_only = 1,
876
877                 .hsync_end      = 88,               .hblank_end         = 235,
878                 .hblank_start   = 2155,             .htotal             = 2200,
879
880                 .progressive    = FALSE,            .trilevel_sync = TRUE,
881
882                 .vsync_start_f1 = 4,            .vsync_start_f2    = 5,
883                 .vsync_len      = 10,
884
885                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
886                 .veq_start_f2 = 4,                  .veq_len = 10,
887
888
889                 .vi_end_f1      = 21,           .vi_end_f2              = 22,
890                 .nbr_end        = 539,
891
892                 .burst_ena      = FALSE,
893
894                 .filter_table = filter_table,
895         },
896 };
897
898 #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
899
900 static void
901 intel_tv_dpms(struct drm_output *output, int mode)
902 {
903         struct drm_device *dev = output->dev;
904         struct drm_i915_private *dev_priv = dev->dev_private;
905
906         switch(mode) {
907         case DPMSModeOn:
908                 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
909                 break;
910         case DPMSModeStandby:
911         case DPMSModeSuspend:
912         case DPMSModeOff:
913                 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
914                 break;
915         }
916 }
917
918 static void
919 intel_tv_save(struct drm_output *output)
920 {
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;
925         int i;
926
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);
940
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);
954
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));
963
964         tv_priv->save_TV_DAC = I915_READ(TV_DAC);
965         tv_priv->save_TV_CTL = I915_READ(TV_CTL);
966 }
967
968 static void
969 intel_tv_restore(struct drm_output *output)
970 {
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;
977         int i;
978
979         /* FIXME: No CRTC? */
980         if (!crtc)
981                 return;
982
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);
997
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);
1006
1007         {
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));
1020
1021                 if (!IS_I9XX(dev)) {
1022                         /* Wait for vblank for the disable to take effect */
1023                         intel_wait_for_vblank(dev);
1024                 }
1025
1026                 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1027                 /* Wait for vblank for the disable to take effect. */
1028                 intel_wait_for_vblank(dev);
1029
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));
1040         }
1041
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]);
1050
1051         I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
1052         I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
1053 }
1054
1055 static const struct tv_mode *
1056 intel_tv_mode_lookup (char *tv_format)
1057 {
1058         int i;
1059     
1060         for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
1061                 const struct tv_mode *tv_mode = &tv_modes[i];
1062
1063                 if (!strcmp(tv_format, tv_mode->name))
1064                         return tv_mode;
1065         }
1066         return NULL;
1067 }
1068
1069 static const struct tv_mode *
1070 intel_tv_mode_find (struct drm_output *output)
1071 {
1072         struct intel_output *intel_output = output->driver_private;
1073         struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1074
1075         return intel_tv_mode_lookup(tv_priv->tv_format);
1076 }
1077
1078 static enum drm_mode_status
1079 intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode)
1080 {
1081         const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1082
1083         /* Ensure TV refresh is close to desired refresh */
1084         if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
1085                 return MODE_OK;
1086         return MODE_CLOCK_RANGE;
1087 }
1088
1089
1090 static bool
1091 intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode,
1092                     struct drm_display_mode *adjusted_mode)
1093 {
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;
1098
1099         if (!tv_mode)
1100                 return FALSE;
1101     
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)
1106                         return FALSE;
1107         }
1108
1109         adjusted_mode->clock = tv_mode->clock;
1110         return TRUE;
1111 }
1112
1113 static void
1114 intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,
1115                   struct drm_display_mode *adjusted_mode)
1116 {
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);
1124         u32 tv_ctl;
1125         u32 hctl1, hctl2, hctl3;
1126         u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1127         u32 scctl1, scctl2, scctl3;
1128         int i, j;
1129         const struct video_levels *video_levels;
1130         const struct color_conversion *color_conversion;
1131         bool burst_ena;
1132     
1133         if (!tv_mode)
1134                 return; /* can't happen (mode_prepare prevents this) */
1135     
1136         tv_ctl = 0;
1137
1138         switch (tv_priv->type) {
1139         default:
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;
1146                 break;
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;
1152                 else
1153                         color_conversion = &hdtv_csc_yprpb;
1154                 burst_ena = FALSE;
1155                 break;
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;
1161                 break;
1162         }
1163         hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1164                 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1165
1166         hctl2 = (tv_mode->hburst_start << 16) |
1167                 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1168
1169         if (burst_ena)
1170                 hctl2 |= TV_BURST_ENA;
1171
1172         hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1173                 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1174
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);
1178
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);
1182
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);
1186
1187         if (tv_mode->veq_ena)
1188                 vctl3 |= TV_EQUAL_ENA;
1189
1190         vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1191                 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1192
1193         vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1194                 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1195
1196         vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1197                 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1198
1199         vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1200                 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1201
1202         if (intel_crtc->pipe == 1)
1203                 tv_ctl |= TV_ENC_PIPEB_SELECT;
1204         tv_ctl |= tv_mode->oversample;
1205
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;
1212         scctl1 = 0;
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;
1217         }
1218
1219         if (tv_mode->dda2_inc)
1220                 scctl1 |= TV_SC_DDA2_EN;
1221
1222         if (tv_mode->dda3_inc)
1223                 scctl1 |= TV_SC_DDA3_EN;
1224
1225         scctl1 |= tv_mode->sc_reset;
1226         scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1227
1228         scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1229                 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1230
1231         scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1232                 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1233
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;
1237
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);
1251
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);
1265         }
1266
1267         I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1268         if (video_levels)
1269                 I915_WRITE(TV_CLR_LEVEL,
1270                            ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1271                             (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1272         {
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));
1287
1288                 /* Wait for vblank for the disable to take effect */
1289                 if (!IS_I9XX(dev))
1290                         intel_wait_for_vblank(dev);
1291
1292                 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1293                 /* Wait for vblank for the disable to take effect. */
1294                 intel_wait_for_vblank(dev);
1295
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;
1301                 else
1302                         ysize = 2*tv_mode->nbr_end + 1;
1303
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);
1312
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));
1317         }       
1318
1319         j = 0;
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);
1330 }
1331
1332 static const struct drm_display_mode reported_modes[] = {
1333         {
1334                 .name = "NTSC 480i",
1335                 .clock = 107520,
1336                 .hdisplay = 1280,
1337                 .hsync_start = 1368,
1338                 .hsync_end = 1496,
1339                 .htotal = 1712,
1340
1341                 .vdisplay = 1024,
1342                 .vsync_start = 1027,
1343                 .vsync_end = 1034,
1344                 .vtotal = 1104,
1345                 .type = DRM_MODE_TYPE_DRIVER,
1346         },
1347 };
1348
1349 /**
1350  * Detects TV presence by checking for load.
1351  *
1352  * Requires that the current pipe's DPLL is active.
1353
1354  * \return TRUE if TV is connected.
1355  * \return FALSE if TV is disconnected.
1356  */
1357 static int
1358 intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
1359 {
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;
1367
1368         tv_dac = I915_READ(TV_DAC);
1369
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);
1377
1378         /*
1379          * Detect TV by polling)
1380          */
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 |
1391                            TVDAC_A_SENSE_CTL |
1392                            TVDAC_B_SENSE_CTL |
1393                            TVDAC_C_SENSE_CTL |
1394                            DAC_CTL_OVERRIDE |
1395                            DAC_A_0_7_V |
1396                            DAC_B_0_7_V |
1397                            DAC_C_0_7_V);
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);
1404         }
1405         /*
1406          *  A B C
1407          *  0 1 1 Composite
1408          *  1 0 X svideo
1409          *  0 0 0 Component
1410          */
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;
1420         } else {
1421                 DRM_DEBUG("No TV connection detected\n");
1422                 type = -1;
1423         }
1424
1425         /* Restore interrupt config */
1426         I915_WRITE(PIPEASTAT, pipeastat_save | PIPE_HOTPLUG_TV_INTERRUPT_STATUS |
1427                    PIPE_HOTPLUG_INTERRUPT_STATUS);
1428
1429         return type;
1430 }
1431
1432 /**
1433  * Detect the TV connection.
1434  *
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.
1437  */
1438 static enum drm_output_status
1439 intel_tv_detect(struct drm_output *output)
1440 {
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;
1445         int dpms_mode;
1446         int type = tv_priv->type;
1447
1448         mode = reported_modes[0];
1449         drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1450
1451         if (output->crtc) {
1452                 type = intel_tv_detect_type(output->crtc, output);
1453         } else {
1454                 crtc = intel_get_load_detect_pipe(output, &mode, &dpms_mode);
1455                 if (crtc) {
1456                         type = intel_tv_detect_type(crtc, output);
1457                         intel_release_load_detect_pipe(output, dpms_mode);
1458                 } else
1459                         type = -1;
1460         }
1461
1462         if (type != tv_priv->type) {
1463                 struct drm_property *connector_property =
1464                         output->dev->mode_config.connector_type_property;
1465
1466                 tv_priv->type = type;
1467                 drm_output_property_set_value(output, connector_property,
1468                                               type);
1469         }
1470         
1471         if (type < 0)
1472                 return output_status_disconnected;
1473
1474         return output_status_connected;
1475 }
1476
1477 static struct input_res {
1478         char *name;
1479         int w, h;       
1480 } input_res_table[] = 
1481 {
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},
1489 };
1490
1491 /**
1492  * Stub get_modes function.
1493  *
1494  * This should probably return a set of fixed modes, unless we can figure out
1495  * how to probe modes off of TV connections.
1496  */
1497
1498 static int
1499 intel_tv_get_modes(struct drm_output *output)
1500 {
1501         struct drm_display_mode *mode_ptr;
1502         const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1503         int j;
1504
1505         for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
1506              j++) {
1507                 struct input_res *input = &input_res_table[j];
1508                 unsigned int hactive_s = input->w;
1509                 unsigned int vactive_s = input->h;
1510         
1511                 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1512                         continue;
1513
1514                 if (input->w > 1024 && (!tv_mode->progressive 
1515                                         && !tv_mode->component_only))
1516                         continue;
1517
1518                 mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
1519                                       DRM_MEM_DRIVER);
1520                 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1521
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;
1528
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;
1535
1536                 mode_ptr->clock = (int) (tv_mode->refresh * 
1537                                          mode_ptr->vtotal * 
1538                                          mode_ptr->htotal / 1000) / 1000;
1539         
1540                 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1541                 drm_mode_probed_add(output, mode_ptr);
1542         } 
1543
1544         return 0;
1545 }
1546
1547 static void
1548 intel_tv_destroy (struct drm_output *output)
1549 {
1550         if (output->driver_private)
1551                 drm_free(output->driver_private, sizeof(struct intel_tv_priv),
1552                          DRM_MEM_DRIVER);
1553 }
1554
1555 static bool
1556 intel_tv_set_property(struct drm_output *output, struct drm_property *property,
1557                       uint64_t val)
1558 {
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;
1562         int ret = 0;
1563
1564         ret = drm_output_property_set_value(output, property, val);
1565         if (ret < 0)
1566                 goto out;
1567
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) {
1578                         ret = -EINVAL;
1579                         goto out;
1580                 }
1581                 tv_priv->tv_format = tv_modes[val].name;
1582                 intel_tv_mode_set(output, NULL, NULL);
1583         } else {
1584                 ret = -EINVAL;
1585                 goto out;
1586         }
1587
1588         intel_tv_mode_set(output, NULL, NULL);
1589 out:
1590         return ret;
1591 }
1592
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,
1606 };
1607
1608 void
1609 intel_tv_init(struct drm_device *dev)
1610 {
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;
1618
1619         if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1620                 return;
1621
1622         /* Even if we have an encoder we may not have a connector */
1623         if (!dev_priv->int_tv_support)
1624                 return;
1625
1626         /*
1627          * Sanity check the TV output by checking to see if the
1628          * DAC register holds a value
1629          */
1630         save_tv_dac = I915_READ(TV_DAC);
1631
1632         I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1633         tv_dac_on = I915_READ(TV_DAC);
1634
1635         I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1636         tv_dac_off = I915_READ(TV_DAC);
1637
1638         I915_WRITE(TV_DAC, save_tv_dac);
1639
1640         /*
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
1643          * exist
1644          */
1645         if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || 
1646             (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1647                 return;
1648
1649         output = drm_output_create(dev, &intel_tv_output_funcs,
1650                                    DRM_MODE_OUTPUT_TVDAC);
1651
1652         if (!output)
1653                 return;
1654
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);
1659                 return;
1660         }
1661
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;
1668
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;
1674     
1675         tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
1676     
1677         output->driver_private = intel_output;
1678         output->interlace_allowed = FALSE;
1679         output->doublescan_allowed = FALSE;
1680
1681         drm_output_attach_property(output,
1682                                    dev->mode_config.connector_type_property,
1683                                    ConnectorUnknown);
1684
1685         /* Create TV properties then attach current values */
1686         tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES,
1687                                     DRM_MEM_DRIVER);
1688         if (!tv_format_names)
1689                 goto out;
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);
1693
1694         drm_output_attach_property(output, dev->mode_config.tv_mode_property,
1695                                    initial_mode);
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]);
1708 out:
1709         drm_sysfs_output_add(output);
1710 }