OSDN Git Service

Merge branch 'master' of git+ssh://git.freedesktop.org/git/mesa/drm into modesetting-101
[android-x86/external-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_type {
41         TV_TYPE_NONE,
42         TV_TYPE_UNKNOWN,
43         TV_TYPE_COMPOSITE,
44         TV_TYPE_SVIDEO,
45         TV_TYPE_COMPONENT
46 };
47
48 enum tv_margin {
49         TV_MARGIN_LEFT, TV_MARGIN_TOP,
50         TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
51 };
52
53 /** Private structure for the integrated TV support */
54 struct intel_tv_priv {
55         int type;
56         char *tv_format;
57         int margin[4];
58         u32 save_TV_H_CTL_1;
59         u32 save_TV_H_CTL_2;
60         u32 save_TV_H_CTL_3;
61         u32 save_TV_V_CTL_1;
62         u32 save_TV_V_CTL_2;
63         u32 save_TV_V_CTL_3;
64         u32 save_TV_V_CTL_4;
65         u32 save_TV_V_CTL_5;
66         u32 save_TV_V_CTL_6;
67         u32 save_TV_V_CTL_7;
68         u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
69
70         u32 save_TV_CSC_Y;
71         u32 save_TV_CSC_Y2;
72         u32 save_TV_CSC_U;
73         u32 save_TV_CSC_U2;
74         u32 save_TV_CSC_V;
75         u32 save_TV_CSC_V2;
76         u32 save_TV_CLR_KNOBS;
77         u32 save_TV_CLR_LEVEL;
78         u32 save_TV_WIN_POS;
79         u32 save_TV_WIN_SIZE;
80         u32 save_TV_FILTER_CTL_1;
81         u32 save_TV_FILTER_CTL_2;
82         u32 save_TV_FILTER_CTL_3;
83
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];
88
89         u32 save_TV_DAC;
90         u32 save_TV_CTL;
91 };
92
93 struct video_levels {
94         int blank, black, burst;
95 };
96
97 struct color_conversion {
98         u16 ry, gy, by, ay;
99         u16 ru, gu, bu, au;
100         u16 rv, gv, bv, av;
101 };
102
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,
156 };
157
158 /*
159  * Color conversion values have 3 separate fixed point formats:
160  *
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)
179  *
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)
187  *
188  * Simple conversion function:
189  *
190  * static u32
191  * float_to_csc_11(float f)
192  * {
193  *     u32 exp;
194  *     u32 mant;
195  *     u32 ret;
196  * 
197  *     if (f < 0)
198  *         f = -f;
199  * 
200  *     if (f >= 1) {
201  *         exp = 0x7;
202  *         mant = 1 << 8;
203  *     } else {
204  *         for (exp = 0; exp < 3 && f < 0.5; exp++)
205  *             f *= 2.0;
206  *         mant = (f * (1 << 9) + 0.5);
207  *         if (mant >= (1 << 9))
208  *             mant = (1 << 9) - 1;
209  *     }
210  *     ret = (exp << 9) | mant;
211  *     return ret;
212  * }
213  */
214
215 /*
216  * Behold, magic numbers!  If we plant them they might grow a big
217  * s-video cable to the sky... or something.
218  *
219  * Pre-converted to appropriate hex value.
220  */
221
222 /*
223  * PAL & NTSC values for composite & s-video connections
224  */
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,
229 };
230
231 static const struct video_levels ntsc_m_levels_composite = {
232         .blank = 225, .black = 267, .burst = 113,
233 };
234
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,
239 };
240
241 static const struct video_levels ntsc_m_levels_svideo = {
242         .blank = 266, .black = 316, .burst = 133,
243 };
244
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,
249 };
250
251 static const struct video_levels ntsc_j_levels_composite = {
252         .blank = 225, .black = 225, .burst = 113,
253 };
254
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,
259 };
260
261 static const struct video_levels ntsc_j_levels_svideo = {
262         .blank = 266, .black = 266, .burst = 133,
263 };
264
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,
269 };
270         
271 static const struct video_levels pal_levels_composite = {
272         .blank = 237, .black = 237, .burst = 118,
273 };
274
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,
279 };
280
281 static const struct video_levels pal_levels_svideo = {
282         .blank = 280, .black = 280, .burst = 139,
283 };
284
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,
289 };
290
291 static const struct video_levels pal_m_levels_composite = {
292         .blank = 225, .black = 267, .burst = 113,
293 };
294
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,
299 };
300
301 static const struct video_levels pal_m_levels_svideo = {
302         .blank = 266, .black = 316, .burst = 133,
303 };
304
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,
309 };
310
311 static const struct video_levels pal_n_levels_composite = {
312         .blank = 225, .black = 267, .burst = 118,
313 };
314
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,
319 };
320
321 static const struct video_levels pal_n_levels_svideo = {
322         .blank = 266, .black = 316, .burst = 139,
323 };
324
325 /*
326  * Component connections
327  */
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,
332 };
333
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,
338 };
339
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,
344 };
345
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,
350 };
351
352 static const struct video_levels component_levels = {
353         .blank = 279, .black = 279, .burst = 0,
354 };
355
356
357 struct tv_mode {
358         char *name;
359         int clock;
360         int refresh; /* in millihertz (for precision) */
361         u32 oversample;
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;
365         bool veq_ena;
366         int veq_start_f1, veq_start_f2, veq_len;
367         int vi_end_f1, vi_end_f2, nbr_end;
368         bool burst_ena;
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;
374         /*
375          * subcarrier programming
376          */
377         int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
378         u32 sc_reset;
379         bool pal_burst;
380         /*
381          * blank/black levels
382          */
383         const struct video_levels *composite_levels, *svideo_levels;
384         const struct color_conversion *composite_color, *svideo_color;
385         const u32 *filter_table;
386         int max_srcw;
387 };
388
389
390 /*
391  * Sub carrier DDA
392  *
393  *  I think this works as follows:
394  *
395  *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
396  *
397  * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
398  *
399  * So,
400  *  dda1_ideal = subcarrier/pixel * 4096
401  *  dda1_inc = floor (dda1_ideal)
402  *  dda2 = dda1_ideal - dda1_inc
403  *
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
407  *
408  * To invert this,
409  *
410  *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
411  *
412  * The constants below were all computed using a 107.520MHz clock
413  */
414  
415 /**
416  * Register programming values for TV modes.
417  *
418  * These values account for -1s required.
419  */
420
421 const static struct tv_mode tv_modes[] = {
422         {
423                 .name           = "NTSC-M",
424                 .clock          = 107520,       
425                 .refresh        = 29970,
426                 .oversample     = TV_OVERSAMPLE_8X,
427                 .component_only = 0,
428                 /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
429
430                 .hsync_end      = 64,               .hblank_end         = 124,
431                 .hblank_start   = 836,              .htotal             = 857,
432
433                 .progressive    = FALSE,            .trilevel_sync = FALSE,
434
435                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
436                 .vsync_len      = 6,
437
438                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
439                 .veq_start_f2   = 1,                .veq_len            = 18,
440
441                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
442                 .nbr_end        = 240,
443
444                 .burst_ena      = TRUE,
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,
450
451                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
452                 .dda1_inc       =    136,
453                 .dda2_inc       =   7624,           .dda2_size          =  20013,
454                 .dda3_inc       =      0,           .dda3_size          =      0,
455                 .sc_reset       = TV_SC_RESET_EVERY_4,
456                 .pal_burst      = FALSE,
457
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,
462
463                 .filter_table = filter_table,
464         },
465         {
466                 .name           = "NTSC-443",
467                 .clock          = 107520,       
468                 .refresh        = 29970,
469                 .oversample     = TV_OVERSAMPLE_8X,
470                 .component_only = 0,
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,
474
475                 .progressive    = FALSE,            .trilevel_sync = FALSE,
476
477                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
478                 .vsync_len      = 6,
479
480                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
481                 .veq_start_f2   = 1,                .veq_len            = 18,
482
483                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
484                 .nbr_end        = 240,
485
486                 .burst_ena      = 8,
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,
492
493                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
494                 .dda1_inc       =    168,
495                 .dda2_inc       =  18557,       .dda2_size      =  20625,
496                 .dda3_inc       =      0,       .dda3_size      =      0,
497                 .sc_reset   = TV_SC_RESET_EVERY_8,
498                 .pal_burst  = TRUE,
499
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,
504
505                 .filter_table = filter_table,
506         },
507         {
508                 .name           = "NTSC-J",
509                 .clock          = 107520,       
510                 .refresh        = 29970,
511                 .oversample     = TV_OVERSAMPLE_8X,
512                 .component_only = 0,
513
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,
517
518                 .progressive    = FALSE,    .trilevel_sync = FALSE,
519
520                 .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
521                 .vsync_len      = 6,
522
523                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
524                 .veq_start_f2 = 1,          .veq_len            = 18,
525
526                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
527                 .nbr_end        = 240,
528
529                 .burst_ena      = TRUE,
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,
535
536                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
537                 .dda1_inc       =    136,
538                 .dda2_inc       =   7624,           .dda2_size          =  20013,
539                 .dda3_inc       =      0,           .dda3_size          =      0,
540                 .sc_reset       = TV_SC_RESET_EVERY_4,
541                 .pal_burst      = FALSE,
542
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,
547
548                 .filter_table = filter_table,
549         },
550         {
551                 .name           = "PAL-M",
552                 .clock          = 107520,       
553                 .refresh        = 29970,
554                 .oversample     = TV_OVERSAMPLE_8X,
555                 .component_only = 0,
556
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,
560
561                 .progressive    = FALSE,            .trilevel_sync = FALSE,
562
563                 .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
564                 .vsync_len      = 6,
565
566                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
567                 .veq_start_f2   = 1,                .veq_len            = 18,
568
569                 .vi_end_f1      = 20,               .vi_end_f2          = 21,
570                 .nbr_end        = 240,
571
572                 .burst_ena      = TRUE,
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,
578
579                 /* desired 3.5800000 actual 3.5800000 clock 107.52 */
580                 .dda1_inc       =    136,
581                 .dda2_inc       =    7624,          .dda2_size          =  20013,
582                 .dda3_inc       =      0,           .dda3_size          =      0,
583                 .sc_reset       = TV_SC_RESET_EVERY_4,
584                 .pal_burst  = FALSE,
585
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,
590
591                 .filter_table = filter_table,
592         },
593         {
594                 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
595                 .name       = "PAL-N",
596                 .clock          = 107520,       
597                 .refresh        = 25000,
598                 .oversample     = TV_OVERSAMPLE_8X,
599                 .component_only = 0,
600
601                 .hsync_end      = 64,               .hblank_end         = 128,
602                 .hblank_start = 844,        .htotal             = 863,
603
604                 .progressive  = FALSE,    .trilevel_sync = FALSE,
605
606
607                 .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
608                 .vsync_len      = 6,
609
610                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
611                 .veq_start_f2   = 1,                .veq_len            = 18,
612
613                 .vi_end_f1      = 24,               .vi_end_f2          = 25,
614                 .nbr_end        = 286,
615
616                 .burst_ena      = TRUE,
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,
622
623
624                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
625                 .dda1_inc       =    168,
626                 .dda2_inc       =  18557,       .dda2_size      =  20625,
627                 .dda3_inc       =      0,       .dda3_size      =      0,
628                 .sc_reset   = TV_SC_RESET_EVERY_8,
629                 .pal_burst  = TRUE,
630
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,
635
636                 .filter_table = filter_table,
637         },
638         {
639                 /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
640                 .name       = "PAL",
641                 .clock          = 107520,       
642                 .refresh        = 25000,
643                 .oversample     = TV_OVERSAMPLE_8X,
644                 .component_only = 0,
645
646                 .hsync_end      = 64,               .hblank_end         = 128,
647                 .hblank_start   = 844,      .htotal             = 863,
648
649                 .progressive    = FALSE,    .trilevel_sync = FALSE,
650
651                 .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
652                 .vsync_len      = 5,
653
654                 .veq_ena        = TRUE,             .veq_start_f1       = 0,
655                 .veq_start_f2   = 1,        .veq_len            = 15,
656
657                 .vi_end_f1      = 24,               .vi_end_f2          = 25,
658                 .nbr_end        = 286,
659
660                 .burst_ena      = TRUE,
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,
666
667                 /* desired 4.4336180 actual 4.4336180 clock 107.52 */
668                 .dda1_inc       =    168,
669                 .dda2_inc       =  18557,       .dda2_size      =  20625,
670                 .dda3_inc       =      0,       .dda3_size      =      0,
671                 .sc_reset   = TV_SC_RESET_EVERY_8,
672                 .pal_burst  = TRUE,
673
674                 .composite_levels = &pal_levels_composite,
675                 .composite_color = &pal_csc_composite,
676                 .svideo_levels  = &pal_levels_svideo,
677                 .svideo_color = &pal_csc_svideo,
678
679                 .filter_table = filter_table,
680         },
681         {
682                 .name       = "480p@59.94Hz",
683                 .clock  = 107520,       
684                 .refresh        = 59940,
685                 .oversample     = TV_OVERSAMPLE_4X,
686                 .component_only = 1,
687
688                 .hsync_end      = 64,               .hblank_end         = 122,
689                 .hblank_start   = 842,              .htotal             = 857,
690
691                 .progressive    = TRUE,.trilevel_sync = FALSE,
692
693                 .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
694                 .vsync_len      = 12,
695
696                 .veq_ena        = FALSE,
697
698                 .vi_end_f1      = 44,               .vi_end_f2          = 44,
699                 .nbr_end        = 496,
700
701                 .burst_ena      = FALSE,
702
703                 .filter_table = filter_table,
704         },
705         {
706                 .name       = "480p@60Hz",
707                 .clock  = 107520,       
708                 .refresh        = 60000,
709                 .oversample     = TV_OVERSAMPLE_4X,
710                 .component_only = 1,
711
712                 .hsync_end      = 64,               .hblank_end         = 122,
713                 .hblank_start   = 842,              .htotal             = 856,
714
715                 .progressive    = TRUE,.trilevel_sync = FALSE,
716
717                 .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
718                 .vsync_len      = 12,
719
720                 .veq_ena        = FALSE,
721
722                 .vi_end_f1      = 44,               .vi_end_f2          = 44,
723                 .nbr_end        = 496,
724
725                 .burst_ena      = FALSE,
726
727                 .filter_table = filter_table,
728         },
729         {
730                 .name       = "576p",
731                 .clock  = 107520,       
732                 .refresh        = 50000,
733                 .oversample     = TV_OVERSAMPLE_4X,
734                 .component_only = 1,
735
736                 .hsync_end      = 64,               .hblank_end         = 139,
737                 .hblank_start   = 859,              .htotal             = 863,
738
739                 .progressive    = TRUE,         .trilevel_sync = FALSE,
740
741                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
742                 .vsync_len      = 10,
743
744                 .veq_ena        = FALSE,
745
746                 .vi_end_f1      = 48,               .vi_end_f2          = 48,
747                 .nbr_end        = 575,
748
749                 .burst_ena      = FALSE,
750
751                 .filter_table = filter_table,
752         },
753         {
754                 .name       = "720p@60Hz",
755                 .clock          = 148800,       
756                 .refresh        = 60000,
757                 .oversample     = TV_OVERSAMPLE_2X,
758                 .component_only = 1,
759
760                 .hsync_end      = 80,               .hblank_end         = 300,
761                 .hblank_start   = 1580,             .htotal             = 1649,
762
763                 .progressive    = TRUE,             .trilevel_sync = TRUE,
764
765                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
766                 .vsync_len      = 10,
767
768                 .veq_ena        = FALSE,
769
770                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
771                 .nbr_end        = 719,
772
773                 .burst_ena      = FALSE,
774
775                 .filter_table = filter_table,
776         },
777         {
778                 .name       = "720p@59.94Hz",
779                 .clock          = 148800,       
780                 .refresh        = 59940,
781                 .oversample     = TV_OVERSAMPLE_2X,
782                 .component_only = 1,
783
784                 .hsync_end      = 80,               .hblank_end         = 300,
785                 .hblank_start   = 1580,             .htotal             = 1651,
786
787                 .progressive    = TRUE,             .trilevel_sync = TRUE,
788
789                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
790                 .vsync_len      = 10,
791
792                 .veq_ena        = FALSE,
793
794                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
795                 .nbr_end        = 719,
796
797                 .burst_ena      = FALSE,
798
799                 .filter_table = filter_table,
800         },
801         {
802                 .name       = "720p@50Hz",
803                 .clock          = 148800,       
804                 .refresh        = 50000,
805                 .oversample     = TV_OVERSAMPLE_2X,
806                 .component_only = 1,
807
808                 .hsync_end      = 80,               .hblank_end         = 300,
809                 .hblank_start   = 1580,             .htotal             = 1979,
810
811                 .progressive    = TRUE,                 .trilevel_sync = TRUE,
812
813                 .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
814                 .vsync_len      = 10,
815
816                 .veq_ena        = FALSE,
817
818                 .vi_end_f1      = 29,               .vi_end_f2          = 29,
819                 .nbr_end        = 719,
820
821                 .burst_ena      = FALSE,
822
823                 .filter_table = filter_table,
824                 .max_srcw = 800
825         },
826         {
827                 .name       = "1080i@50Hz",
828                 .clock          = 148800,       
829                 .refresh        = 25000,
830                 .oversample     = TV_OVERSAMPLE_2X,
831                 .component_only = 1,
832
833                 .hsync_end      = 88,               .hblank_end         = 235,
834                 .hblank_start   = 2155,             .htotal             = 2639,
835
836                 .progressive    = FALSE,            .trilevel_sync = TRUE,
837
838                 .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
839                 .vsync_len      = 10,
840
841                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
842                 .veq_start_f2   = 4,        .veq_len            = 10,
843
844
845                 .vi_end_f1      = 21,           .vi_end_f2          = 22,
846                 .nbr_end        = 539,
847
848                 .burst_ena      = FALSE,
849
850                 .filter_table = filter_table,
851         },
852         {
853                 .name       = "1080i@60Hz",
854                 .clock          = 148800,       
855                 .refresh        = 30000,
856                 .oversample     = TV_OVERSAMPLE_2X,
857                 .component_only = 1,
858
859                 .hsync_end      = 88,               .hblank_end         = 235,
860                 .hblank_start   = 2155,             .htotal             = 2199,
861
862                 .progressive    = FALSE,            .trilevel_sync = TRUE,
863
864                 .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
865                 .vsync_len      = 10,
866
867                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
868                 .veq_start_f2   = 4,                .veq_len            = 10,
869
870
871                 .vi_end_f1      = 21,               .vi_end_f2          = 22,
872                 .nbr_end        = 539,
873
874                 .burst_ena      = FALSE,
875
876                 .filter_table = filter_table,
877         },
878         {
879                 .name       = "1080i@59.94Hz",
880                 .clock          = 148800,       
881                 .refresh        = 29970,
882                 .oversample     = TV_OVERSAMPLE_2X,
883                 .component_only = 1,
884
885                 .hsync_end      = 88,               .hblank_end         = 235,
886                 .hblank_start   = 2155,             .htotal             = 2200,
887
888                 .progressive    = FALSE,            .trilevel_sync = TRUE,
889
890                 .vsync_start_f1 = 4,            .vsync_start_f2    = 5,
891                 .vsync_len      = 10,
892
893                 .veq_ena        = TRUE,             .veq_start_f1       = 4,
894                 .veq_start_f2 = 4,                  .veq_len = 10,
895
896
897                 .vi_end_f1      = 21,           .vi_end_f2              = 22,
898                 .nbr_end        = 539,
899
900                 .burst_ena      = FALSE,
901
902                 .filter_table = filter_table,
903         },
904 };
905
906 #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
907
908 static void
909 intel_tv_dpms(struct drm_output *output, int mode)
910 {
911         struct drm_device *dev = output->dev;
912         struct drm_i915_private *dev_priv = dev->dev_private;
913
914         switch(mode) {
915         case DPMSModeOn:
916                 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
917                 break;
918         case DPMSModeStandby:
919         case DPMSModeSuspend:
920         case DPMSModeOff:
921                 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
922                 break;
923         }
924 }
925
926 static void
927 intel_tv_save(struct drm_output *output)
928 {
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;
933         int i;
934
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);
948
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);
962
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));
971
972         tv_priv->save_TV_DAC = I915_READ(TV_DAC);
973         tv_priv->save_TV_CTL = I915_READ(TV_CTL);
974 }
975
976 static void
977 intel_tv_restore(struct drm_output *output)
978 {
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;
985         int i;
986
987         /* FIXME: No CRTC? */
988         if (!crtc)
989                 return;
990
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);
1005
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);
1014
1015         {
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));
1028
1029                 if (!IS_I9XX(dev)) {
1030                         /* Wait for vblank for the disable to take effect */
1031                         intel_wait_for_vblank(dev);
1032                 }
1033
1034                 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1035                 /* Wait for vblank for the disable to take effect. */
1036                 intel_wait_for_vblank(dev);
1037
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));
1048         }
1049
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]);
1058
1059         I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
1060         I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
1061 }
1062
1063 static const struct tv_mode *
1064 intel_tv_mode_lookup (char *tv_format)
1065 {
1066         int i;
1067     
1068         for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
1069                 const struct tv_mode *tv_mode = &tv_modes[i];
1070
1071                 if (!strcmp(tv_format, tv_mode->name))
1072                         return tv_mode;
1073         }
1074         return NULL;
1075 }
1076
1077 static const struct tv_mode *
1078 intel_tv_mode_find (struct drm_output *output)
1079 {
1080         struct intel_output *intel_output = output->driver_private;
1081         struct intel_tv_priv *tv_priv = intel_output->dev_priv;
1082
1083         return intel_tv_mode_lookup(tv_priv->tv_format);
1084 }
1085
1086 static enum drm_mode_status
1087 intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode)
1088 {
1089         const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1090
1091         /* Ensure TV refresh is close to desired refresh */
1092         if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
1093                 return MODE_OK;
1094         return MODE_CLOCK_RANGE;
1095 }
1096
1097
1098 static bool
1099 intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode,
1100                     struct drm_display_mode *adjusted_mode)
1101 {
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;
1106
1107         if (!tv_mode)
1108                 return FALSE;
1109     
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)
1114                         return FALSE;
1115         }
1116
1117         adjusted_mode->clock = tv_mode->clock;
1118         return TRUE;
1119 }
1120
1121 static void
1122 intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,
1123                   struct drm_display_mode *adjusted_mode)
1124 {
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);
1132         u32 tv_ctl;
1133         u32 hctl1, hctl2, hctl3;
1134         u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1135         u32 scctl1, scctl2, scctl3;
1136         int i, j;
1137         const struct video_levels *video_levels;
1138         const struct color_conversion *color_conversion;
1139         bool burst_ena;
1140     
1141         if (!tv_mode)
1142                 return; /* can't happen (mode_prepare prevents this) */
1143     
1144         tv_ctl = 0;
1145
1146         switch (tv_priv->type) {
1147         default:
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;
1154                 break;
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;
1160                 else
1161                         color_conversion = &hdtv_csc_yprpb;
1162                 burst_ena = FALSE;
1163                 break;
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;
1169                 break;
1170         }
1171         hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1172                 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1173
1174         hctl2 = (tv_mode->hburst_start << 16) |
1175                 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1176
1177         if (burst_ena)
1178                 hctl2 |= TV_BURST_ENA;
1179
1180         hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1181                 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1182
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);
1186
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);
1190
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);
1194
1195         if (tv_mode->veq_ena)
1196                 vctl3 |= TV_EQUAL_ENA;
1197
1198         vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1199                 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1200
1201         vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1202                 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1203
1204         vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1205                 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1206
1207         vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1208                 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1209
1210         if (intel_crtc->pipe == 1)
1211                 tv_ctl |= TV_ENC_PIPEB_SELECT;
1212         tv_ctl |= tv_mode->oversample;
1213
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;
1220         scctl1 = 0;
1221         if (tv_mode->dda1_inc)
1222                 scctl1 |= TV_SC_DDA1_EN;
1223
1224         if (tv_mode->dda2_inc)
1225                 scctl1 |= TV_SC_DDA2_EN;
1226
1227         if (tv_mode->dda3_inc)
1228                 scctl1 |= TV_SC_DDA3_EN;
1229
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;
1233
1234         scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1235                 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1236
1237         scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1238                 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1239
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;
1243
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);
1257
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);
1270
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)));
1274         {
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));
1289
1290                 /* Wait for vblank for the disable to take effect */
1291                 if (!IS_I9XX(dev))
1292                         intel_wait_for_vblank(dev);
1293
1294                 I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
1295                 /* Wait for vblank for the disable to take effect. */
1296                 intel_wait_for_vblank(dev);
1297
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;
1303                 else
1304                         ysize = 2*tv_mode->nbr_end + 1;
1305
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);
1314
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));
1319         }       
1320
1321         j = 0;
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);
1332 }
1333
1334 static const struct drm_display_mode reported_modes[] = {
1335         {
1336                 .name = "NTSC 480i",
1337                 .clock = 107520,
1338                 .hdisplay = 1280,
1339                 .hsync_start = 1368,
1340                 .hsync_end = 1496,
1341                 .htotal = 1712,
1342
1343                 .vdisplay = 1024,
1344                 .vsync_start = 1027,
1345                 .vsync_end = 1034,
1346                 .vtotal = 1104,
1347                 .type = DRM_MODE_TYPE_DRIVER,
1348         },
1349 };
1350
1351 /**
1352  * Detects TV presence by checking for load.
1353  *
1354  * Requires that the current pipe's DPLL is active.
1355
1356  * \return TRUE if TV is connected.
1357  * \return FALSE if TV is disconnected.
1358  */
1359 static int
1360 intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
1361 {
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;
1368
1369         tv_dac = I915_READ(TV_DAC);
1370         /*
1371          * Detect TV by polling)
1372          */
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 |
1383                            TVDAC_A_SENSE_CTL |
1384                            TVDAC_B_SENSE_CTL |
1385                            TVDAC_C_SENSE_CTL |
1386                            DAC_CTL_OVERRIDE |
1387                            DAC_A_0_7_V |
1388                            DAC_B_0_7_V |
1389                            DAC_C_0_7_V);
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);
1396         }
1397         /*
1398          *  A B C
1399          *  0 1 1 Composite
1400          *  1 0 X svideo
1401          *  0 0 0 Component
1402          */
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;
1412         } else {
1413                 DRM_DEBUG("No TV connection detected\n");
1414                 type = TV_TYPE_NONE;
1415         }
1416
1417         return type;
1418 }
1419
1420 static int
1421 intel_tv_format_configure_property (struct drm_output *output);
1422
1423 /**
1424  * Detect the TV connection.
1425  *
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.
1428  */
1429 static enum drm_output_status
1430 intel_tv_detect(struct drm_output *output)
1431 {
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;
1436         int dpms_mode;
1437         int type = tv_priv->type;
1438
1439         mode = reported_modes[0];
1440         drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
1441 #if 0
1442         /* FIXME: pipe allocation for load detection */
1443         crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode);
1444         if (crtc) {
1445                 type = intel_tv_detect_type(crtc, output);
1446                 i830ReleaseLoadDetectPipe (output, dpms_mode);
1447         }
1448 #endif
1449         if (type != tv_priv->type) {
1450                 tv_priv->type = type;
1451                 intel_tv_format_configure_property (output);
1452         }
1453         
1454         switch (type) {
1455         case TV_TYPE_NONE:
1456                 return output_status_disconnected;
1457         case TV_TYPE_UNKNOWN:
1458                 return output_status_unknown;
1459         default:
1460                 return output_status_connected;
1461         }
1462 }
1463
1464 static struct input_res {
1465         char *name;
1466         int w, h;       
1467 } input_res_table[] = 
1468 {
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},
1476 };
1477
1478 /**
1479  * Stub get_modes function.
1480  *
1481  * This should probably return a set of fixed modes, unless we can figure out
1482  * how to probe modes off of TV connections.
1483  */
1484
1485 static int
1486 intel_tv_get_modes(struct drm_output *output)
1487 {
1488         struct drm_display_mode *mode_ptr;
1489         const struct tv_mode *tv_mode = intel_tv_mode_find(output);
1490         int j;
1491
1492         for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
1493              j++) {
1494                 struct input_res *input = &input_res_table[j];
1495                 unsigned int hactive_s = input->w;
1496                 unsigned int vactive_s = input->h;
1497         
1498                 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1499                         continue;
1500
1501                 if (input->w > 1024 && (!tv_mode->progressive 
1502                                         && !tv_mode->component_only))
1503                         continue;
1504
1505                 mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
1506                                       DRM_MEM_DRIVER);
1507                 strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1508
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;
1515
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;
1522
1523                 mode_ptr->clock = (int) (tv_mode->refresh * 
1524                                          mode_ptr->vtotal * 
1525                                          mode_ptr->htotal / 1000) / 1000;
1526         
1527                 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1528                 drm_mode_probed_add(output, mode_ptr);
1529         } 
1530
1531         return 0;
1532 }
1533
1534 static void
1535 intel_tv_destroy (struct drm_output *output)
1536 {
1537         if (output->driver_private)
1538                 drm_free(output->driver_private, sizeof(struct intel_tv_priv),
1539                          DRM_MEM_DRIVER);
1540 }
1541
1542 static bool
1543 intel_tv_format_set_property(struct drm_output *output,
1544                              struct drm_property *prop, uint64_t val)
1545 {
1546 #if 0
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);
1551         int                         err;
1552
1553         if (!tv_mode)
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],
1558                                       FALSE, TRUE);
1559         return err == Success;
1560 #endif
1561         return 0;
1562 }
1563
1564     
1565 /**
1566  * Configure the TV_FORMAT property to list only supported formats
1567  *
1568  * Unless the connector is component, list only the formats supported by
1569  * svideo and composite
1570  */
1571
1572 static int
1573 intel_tv_format_configure_property(struct drm_output *output)
1574 {
1575 #if 0
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];
1579         int                         num_atoms = 0;
1580         int                         i;
1581     
1582         if (!output->randr_output)
1583                 return Success;
1584
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];
1589     
1590         return RRConfigureOutputProperty(output->randr_output, tv_format_atom,
1591                                          TRUE, FALSE, FALSE, 
1592                                          num_atoms, (INT32 *) current_atoms);
1593 #endif
1594         return 0;
1595 }
1596
1597 static void
1598 intel_tv_create_resources(struct drm_output *output)
1599 {
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;
1603         int i, err;
1604
1605 #if 0
1606         /* Set up the tv_format property, which takes effect on mode set
1607          * and accepts strings that match exactly
1608          */
1609         tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1,
1610                                   TRUE);
1611
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),
1615                                                     TRUE);
1616
1617         err = intel_tv_format_configure_property (output);
1618
1619         if (err != 0) {
1620                 xf86DrvMsg(dev->scrnIndex, X_ERROR,
1621                            "RRConfigureOutputProperty error, %d\n", err);
1622         }
1623
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);
1628
1629         for (i = 0; i < 4; i++)
1630         {
1631                 INT32   range[2];
1632                 margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]),
1633                                            TRUE);
1634
1635                 range[0] = 0;
1636                 range[1] = 100;
1637                 err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i],
1638                                                 TRUE, TRUE, FALSE, 2, range);
1639     
1640                 if (err != 0)
1641                         xf86DrvMsg(dev->scrnIndex, X_ERROR,
1642                                    "RRConfigureOutputProperty error, %d\n", err);
1643
1644                 err = RRChangeOutputProperty(output->randr_output, margin_atoms[i],
1645                                              XA_INTEGER, 32, PropModeReplace,
1646                                              1, &tv_priv->margin[i],
1647                                              FALSE, TRUE);
1648                 if (err != 0)
1649                         xf86DrvMsg(dev->scrnIndex, X_ERROR,
1650                                    "RRChangeOutputProperty error, %d\n", err);
1651         }
1652 #endif
1653 }
1654
1655 static bool
1656 intel_tv_set_property(struct drm_output *output, struct drm_property *property,
1657                       uint64_t val)
1658 {
1659         struct drm_device *dev = output->dev;
1660         int ret = 0;
1661     
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);
1667         } else {
1668                 /* TV mode handling here */
1669         }
1670
1671         return ret;
1672 }
1673
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,
1687 };
1688
1689 void
1690 intel_tv_init(struct drm_device *dev)
1691 {
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;
1697
1698         /* FIXME: better TV detection and/or quirks */
1699 #if 0
1700         if (tv_priv->quirk_flag & QUIRK_IGNORE_TV)
1701                 return;
1702 #endif
1703         if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1704                 return;
1705
1706         /*
1707          * Sanity check the TV output by checking to see if the
1708          * DAC register holds a value
1709          */
1710         save_tv_dac = I915_READ(TV_DAC);
1711
1712         I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1713         tv_dac_on = I915_READ(TV_DAC);
1714
1715         I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1716         tv_dac_off = I915_READ(TV_DAC);
1717
1718         I915_WRITE(TV_DAC, save_tv_dac);
1719
1720         /*
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
1723          * exist
1724          */
1725         if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || 
1726             (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1727                 return;
1728
1729         output = drm_output_create(dev, &intel_tv_output_funcs,
1730                                    DRM_MODE_OUTPUT_TVDAC);
1731
1732         if (!output)
1733                 return;
1734
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);
1739                 return;
1740         }
1741
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;
1748
1749         tv_priv->tv_format = NULL;
1750     
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;
1756     
1757         if (!tv_priv->tv_format)
1758                 tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL);
1759     
1760         output->driver_private = intel_output;
1761         output->interlace_allowed = FALSE;
1762         output->doublescan_allowed = FALSE;
1763 }