1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <drm/drmP.h>
34#include <drm/drm_atomic_helper.h>
35#include <drm/drm_crtc.h>
36#include <drm/drm_edid.h>
37#include "intel_drv.h"
38#include <drm/i915_drm.h>
39#include "i915_drv.h"
40
41enum tv_margin {
42 TV_MARGIN_LEFT, TV_MARGIN_TOP,
43 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
44};
45
46struct intel_tv {
47 struct intel_encoder base;
48
49 int type;
50};
51
52struct video_levels {
53 u16 blank, black;
54 u8 burst;
55};
56
57struct color_conversion {
58 u16 ry, gy, by, ay;
59 u16 ru, gu, bu, au;
60 u16 rv, gv, bv, av;
61};
62
63static const u32 filter_table[] = {
64 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
65 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
66 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
67 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
68 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
69 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
70 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
71 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
72 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
73 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
74 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
75 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
76 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
77 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
78 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
79 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
80 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
81 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
82 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
83 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
84 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
85 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
86 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
87 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
88 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
89 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
90 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
91 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
92 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
93 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
94 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
95 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
96 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
97 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
98 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
99 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
100 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
101 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
102 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
103 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
104 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
105 0x2D002CC0, 0x30003640, 0x2D0036C0,
106 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
107 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
108 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
109 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
110 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
111 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
112 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
113 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
114 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
115 0x28003100, 0x28002F00, 0x00003100,
116};
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185static const struct color_conversion ntsc_m_csc_composite = {
186 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
187 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
188 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
189};
190
191static const struct video_levels ntsc_m_levels_composite = {
192 .blank = 225, .black = 267, .burst = 113,
193};
194
195static const struct color_conversion ntsc_m_csc_svideo = {
196 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
197 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
198 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
199};
200
201static const struct video_levels ntsc_m_levels_svideo = {
202 .blank = 266, .black = 316, .burst = 133,
203};
204
205static const struct color_conversion ntsc_j_csc_composite = {
206 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
207 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
208 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
209};
210
211static const struct video_levels ntsc_j_levels_composite = {
212 .blank = 225, .black = 225, .burst = 113,
213};
214
215static const struct color_conversion ntsc_j_csc_svideo = {
216 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
217 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
218 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
219};
220
221static const struct video_levels ntsc_j_levels_svideo = {
222 .blank = 266, .black = 266, .burst = 133,
223};
224
225static const struct color_conversion pal_csc_composite = {
226 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
227 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
228 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
229};
230
231static const struct video_levels pal_levels_composite = {
232 .blank = 237, .black = 237, .burst = 118,
233};
234
235static const struct color_conversion pal_csc_svideo = {
236 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
237 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
238 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
239};
240
241static const struct video_levels pal_levels_svideo = {
242 .blank = 280, .black = 280, .burst = 139,
243};
244
245static const struct color_conversion pal_m_csc_composite = {
246 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
247 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
248 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
249};
250
251static const struct video_levels pal_m_levels_composite = {
252 .blank = 225, .black = 267, .burst = 113,
253};
254
255static const struct color_conversion pal_m_csc_svideo = {
256 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
257 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
258 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
259};
260
261static const struct video_levels pal_m_levels_svideo = {
262 .blank = 266, .black = 316, .burst = 133,
263};
264
265static const struct color_conversion pal_n_csc_composite = {
266 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
267 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
268 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
269};
270
271static const struct video_levels pal_n_levels_composite = {
272 .blank = 225, .black = 267, .burst = 118,
273};
274
275static const struct color_conversion pal_n_csc_svideo = {
276 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
277 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
278 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
279};
280
281static const struct video_levels pal_n_levels_svideo = {
282 .blank = 266, .black = 316, .burst = 139,
283};
284
285
286
287
288static const struct color_conversion sdtv_csc_yprpb = {
289 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
290 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
291 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
292};
293
294static const struct color_conversion hdtv_csc_yprpb = {
295 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
296 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
297 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
298};
299
300static const struct video_levels component_levels = {
301 .blank = 279, .black = 279, .burst = 0,
302};
303
304
305struct tv_mode {
306 const char *name;
307
308 u32 clock;
309 u16 refresh;
310 u32 oversample;
311 u8 hsync_end;
312 u16 hblank_start, hblank_end, htotal;
313 bool progressive : 1, trilevel_sync : 1, component_only : 1;
314 u8 vsync_start_f1, vsync_start_f2, vsync_len;
315 bool veq_ena : 1;
316 u8 veq_start_f1, veq_start_f2, veq_len;
317 u8 vi_end_f1, vi_end_f2;
318 u16 nbr_end;
319 bool burst_ena : 1;
320 u8 hburst_start, hburst_len;
321 u8 vburst_start_f1;
322 u16 vburst_end_f1;
323 u8 vburst_start_f2;
324 u16 vburst_end_f2;
325 u8 vburst_start_f3;
326 u16 vburst_end_f3;
327 u8 vburst_start_f4;
328 u16 vburst_end_f4;
329
330
331
332 u16 dda2_size, dda3_size;
333 u8 dda1_inc;
334 u16 dda2_inc, dda3_inc;
335 u32 sc_reset;
336 bool pal_burst : 1;
337
338
339
340 const struct video_levels *composite_levels, *svideo_levels;
341 const struct color_conversion *composite_color, *svideo_color;
342 const u32 *filter_table;
343 u16 max_srcw;
344};
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377static const struct tv_mode tv_modes[] = {
378 {
379 .name = "NTSC-M",
380 .clock = 108000,
381 .refresh = 59940,
382 .oversample = TV_OVERSAMPLE_8X,
383 .component_only = 0,
384
385
386 .hsync_end = 64, .hblank_end = 124,
387 .hblank_start = 836, .htotal = 857,
388
389 .progressive = false, .trilevel_sync = false,
390
391 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
392 .vsync_len = 6,
393
394 .veq_ena = true, .veq_start_f1 = 0,
395 .veq_start_f2 = 1, .veq_len = 18,
396
397 .vi_end_f1 = 20, .vi_end_f2 = 21,
398 .nbr_end = 240,
399
400 .burst_ena = true,
401 .hburst_start = 72, .hburst_len = 34,
402 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
403 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
404 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
405 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
406
407
408 .dda1_inc = 135,
409 .dda2_inc = 20800, .dda2_size = 27456,
410 .dda3_inc = 0, .dda3_size = 0,
411 .sc_reset = TV_SC_RESET_EVERY_4,
412 .pal_burst = false,
413
414 .composite_levels = &ntsc_m_levels_composite,
415 .composite_color = &ntsc_m_csc_composite,
416 .svideo_levels = &ntsc_m_levels_svideo,
417 .svideo_color = &ntsc_m_csc_svideo,
418
419 .filter_table = filter_table,
420 },
421 {
422 .name = "NTSC-443",
423 .clock = 108000,
424 .refresh = 59940,
425 .oversample = TV_OVERSAMPLE_8X,
426 .component_only = 0,
427
428 .hsync_end = 64, .hblank_end = 124,
429 .hblank_start = 836, .htotal = 857,
430
431 .progressive = false, .trilevel_sync = false,
432
433 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
434 .vsync_len = 6,
435
436 .veq_ena = true, .veq_start_f1 = 0,
437 .veq_start_f2 = 1, .veq_len = 18,
438
439 .vi_end_f1 = 20, .vi_end_f2 = 21,
440 .nbr_end = 240,
441
442 .burst_ena = true,
443 .hburst_start = 72, .hburst_len = 34,
444 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
445 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
446 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
447 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
448
449
450 .dda1_inc = 168,
451 .dda2_inc = 4093, .dda2_size = 27456,
452 .dda3_inc = 310, .dda3_size = 525,
453 .sc_reset = TV_SC_RESET_NEVER,
454 .pal_burst = false,
455
456 .composite_levels = &ntsc_m_levels_composite,
457 .composite_color = &ntsc_m_csc_composite,
458 .svideo_levels = &ntsc_m_levels_svideo,
459 .svideo_color = &ntsc_m_csc_svideo,
460
461 .filter_table = filter_table,
462 },
463 {
464 .name = "NTSC-J",
465 .clock = 108000,
466 .refresh = 59940,
467 .oversample = TV_OVERSAMPLE_8X,
468 .component_only = 0,
469
470
471 .hsync_end = 64, .hblank_end = 124,
472 .hblank_start = 836, .htotal = 857,
473
474 .progressive = false, .trilevel_sync = false,
475
476 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
477 .vsync_len = 6,
478
479 .veq_ena = true, .veq_start_f1 = 0,
480 .veq_start_f2 = 1, .veq_len = 18,
481
482 .vi_end_f1 = 20, .vi_end_f2 = 21,
483 .nbr_end = 240,
484
485 .burst_ena = true,
486 .hburst_start = 72, .hburst_len = 34,
487 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
488 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
489 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
490 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
491
492
493 .dda1_inc = 135,
494 .dda2_inc = 20800, .dda2_size = 27456,
495 .dda3_inc = 0, .dda3_size = 0,
496 .sc_reset = TV_SC_RESET_EVERY_4,
497 .pal_burst = false,
498
499 .composite_levels = &ntsc_j_levels_composite,
500 .composite_color = &ntsc_j_csc_composite,
501 .svideo_levels = &ntsc_j_levels_svideo,
502 .svideo_color = &ntsc_j_csc_svideo,
503
504 .filter_table = filter_table,
505 },
506 {
507 .name = "PAL-M",
508 .clock = 108000,
509 .refresh = 59940,
510 .oversample = TV_OVERSAMPLE_8X,
511 .component_only = 0,
512
513
514 .hsync_end = 64, .hblank_end = 124,
515 .hblank_start = 836, .htotal = 857,
516
517 .progressive = false, .trilevel_sync = false,
518
519 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
520 .vsync_len = 6,
521
522 .veq_ena = true, .veq_start_f1 = 0,
523 .veq_start_f2 = 1, .veq_len = 18,
524
525 .vi_end_f1 = 20, .vi_end_f2 = 21,
526 .nbr_end = 240,
527
528 .burst_ena = true,
529 .hburst_start = 72, .hburst_len = 34,
530 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
531 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
532 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
533 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
534
535
536 .dda1_inc = 135,
537 .dda2_inc = 16704, .dda2_size = 27456,
538 .dda3_inc = 0, .dda3_size = 0,
539 .sc_reset = TV_SC_RESET_EVERY_8,
540 .pal_burst = true,
541
542 .composite_levels = &pal_m_levels_composite,
543 .composite_color = &pal_m_csc_composite,
544 .svideo_levels = &pal_m_levels_svideo,
545 .svideo_color = &pal_m_csc_svideo,
546
547 .filter_table = filter_table,
548 },
549 {
550
551 .name = "PAL-N",
552 .clock = 108000,
553 .refresh = 50000,
554 .oversample = TV_OVERSAMPLE_8X,
555 .component_only = 0,
556
557 .hsync_end = 64, .hblank_end = 128,
558 .hblank_start = 844, .htotal = 863,
559
560 .progressive = false, .trilevel_sync = false,
561
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 = 24, .vi_end_f2 = 25,
570 .nbr_end = 286,
571
572 .burst_ena = true,
573 .hburst_start = 73, .hburst_len = 34,
574 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
575 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
576 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
577 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
578
579
580
581 .dda1_inc = 135,
582 .dda2_inc = 23578, .dda2_size = 27648,
583 .dda3_inc = 134, .dda3_size = 625,
584 .sc_reset = TV_SC_RESET_EVERY_8,
585 .pal_burst = true,
586
587 .composite_levels = &pal_n_levels_composite,
588 .composite_color = &pal_n_csc_composite,
589 .svideo_levels = &pal_n_levels_svideo,
590 .svideo_color = &pal_n_csc_svideo,
591
592 .filter_table = filter_table,
593 },
594 {
595
596 .name = "PAL",
597 .clock = 108000,
598 .refresh = 50000,
599 .oversample = TV_OVERSAMPLE_8X,
600 .component_only = 0,
601
602 .hsync_end = 64, .hblank_end = 142,
603 .hblank_start = 844, .htotal = 863,
604
605 .progressive = false, .trilevel_sync = false,
606
607 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
608 .vsync_len = 5,
609
610 .veq_ena = true, .veq_start_f1 = 0,
611 .veq_start_f2 = 1, .veq_len = 15,
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 = 32,
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 .dda1_inc = 168,
625 .dda2_inc = 4122, .dda2_size = 27648,
626 .dda3_inc = 67, .dda3_size = 625,
627 .sc_reset = TV_SC_RESET_EVERY_8,
628 .pal_burst = true,
629
630 .composite_levels = &pal_levels_composite,
631 .composite_color = &pal_csc_composite,
632 .svideo_levels = &pal_levels_svideo,
633 .svideo_color = &pal_csc_svideo,
634
635 .filter_table = filter_table,
636 },
637 {
638 .name = "480p",
639 .clock = 107520,
640 .refresh = 59940,
641 .oversample = TV_OVERSAMPLE_4X,
642 .component_only = 1,
643
644 .hsync_end = 64, .hblank_end = 122,
645 .hblank_start = 842, .htotal = 857,
646
647 .progressive = true, .trilevel_sync = false,
648
649 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
650 .vsync_len = 12,
651
652 .veq_ena = false,
653
654 .vi_end_f1 = 44, .vi_end_f2 = 44,
655 .nbr_end = 479,
656
657 .burst_ena = false,
658
659 .filter_table = filter_table,
660 },
661 {
662 .name = "576p",
663 .clock = 107520,
664 .refresh = 50000,
665 .oversample = TV_OVERSAMPLE_4X,
666 .component_only = 1,
667
668 .hsync_end = 64, .hblank_end = 139,
669 .hblank_start = 859, .htotal = 863,
670
671 .progressive = true, .trilevel_sync = false,
672
673 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
674 .vsync_len = 10,
675
676 .veq_ena = false,
677
678 .vi_end_f1 = 48, .vi_end_f2 = 48,
679 .nbr_end = 575,
680
681 .burst_ena = false,
682
683 .filter_table = filter_table,
684 },
685 {
686 .name = "720p@60Hz",
687 .clock = 148800,
688 .refresh = 60000,
689 .oversample = TV_OVERSAMPLE_2X,
690 .component_only = 1,
691
692 .hsync_end = 80, .hblank_end = 300,
693 .hblank_start = 1580, .htotal = 1649,
694
695 .progressive = true, .trilevel_sync = true,
696
697 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
698 .vsync_len = 10,
699
700 .veq_ena = false,
701
702 .vi_end_f1 = 29, .vi_end_f2 = 29,
703 .nbr_end = 719,
704
705 .burst_ena = false,
706
707 .filter_table = filter_table,
708 },
709 {
710 .name = "720p@50Hz",
711 .clock = 148800,
712 .refresh = 50000,
713 .oversample = TV_OVERSAMPLE_2X,
714 .component_only = 1,
715
716 .hsync_end = 80, .hblank_end = 300,
717 .hblank_start = 1580, .htotal = 1979,
718
719 .progressive = true, .trilevel_sync = true,
720
721 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
722 .vsync_len = 10,
723
724 .veq_ena = false,
725
726 .vi_end_f1 = 29, .vi_end_f2 = 29,
727 .nbr_end = 719,
728
729 .burst_ena = false,
730
731 .filter_table = filter_table,
732 .max_srcw = 800
733 },
734 {
735 .name = "1080i@50Hz",
736 .clock = 148800,
737 .refresh = 50000,
738 .oversample = TV_OVERSAMPLE_2X,
739 .component_only = 1,
740
741 .hsync_end = 88, .hblank_end = 235,
742 .hblank_start = 2155, .htotal = 2639,
743
744 .progressive = false, .trilevel_sync = true,
745
746 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
747 .vsync_len = 10,
748
749 .veq_ena = true, .veq_start_f1 = 4,
750 .veq_start_f2 = 4, .veq_len = 10,
751
752
753 .vi_end_f1 = 21, .vi_end_f2 = 22,
754 .nbr_end = 539,
755
756 .burst_ena = false,
757
758 .filter_table = filter_table,
759 },
760 {
761 .name = "1080i@60Hz",
762 .clock = 148800,
763 .refresh = 60000,
764 .oversample = TV_OVERSAMPLE_2X,
765 .component_only = 1,
766
767 .hsync_end = 88, .hblank_end = 235,
768 .hblank_start = 2155, .htotal = 2199,
769
770 .progressive = false, .trilevel_sync = true,
771
772 .vsync_start_f1 = 4, .vsync_start_f2 = 5,
773 .vsync_len = 10,
774
775 .veq_ena = true, .veq_start_f1 = 4,
776 .veq_start_f2 = 4, .veq_len = 10,
777
778
779 .vi_end_f1 = 21, .vi_end_f2 = 22,
780 .nbr_end = 539,
781
782 .burst_ena = false,
783
784 .filter_table = filter_table,
785 },
786};
787
788static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
789{
790 return container_of(encoder, struct intel_tv, base);
791}
792
793static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
794{
795 return enc_to_tv(intel_attached_encoder(connector));
796}
797
798static bool
799intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
800{
801 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
802 u32 tmp = I915_READ(TV_CTL);
803
804 *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
805
806 return tmp & TV_ENC_ENABLE;
807}
808
809static void
810intel_enable_tv(struct intel_encoder *encoder,
811 const struct intel_crtc_state *pipe_config,
812 const struct drm_connector_state *conn_state)
813{
814 struct drm_device *dev = encoder->base.dev;
815 struct drm_i915_private *dev_priv = to_i915(dev);
816
817
818 intel_wait_for_vblank(dev_priv,
819 to_intel_crtc(pipe_config->base.crtc)->pipe);
820
821 I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
822}
823
824static void
825intel_disable_tv(struct intel_encoder *encoder,
826 const struct intel_crtc_state *old_crtc_state,
827 const struct drm_connector_state *old_conn_state)
828{
829 struct drm_device *dev = encoder->base.dev;
830 struct drm_i915_private *dev_priv = to_i915(dev);
831
832 I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
833}
834
835static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
836{
837 int format = conn_state->tv.mode;
838
839 return &tv_modes[format];
840}
841
842static enum drm_mode_status
843intel_tv_mode_valid(struct drm_connector *connector,
844 struct drm_display_mode *mode)
845{
846 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
847 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
848
849 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
850 return MODE_NO_DBLESCAN;
851
852 if (mode->clock > max_dotclk)
853 return MODE_CLOCK_HIGH;
854
855
856 if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
857 < 1000)
858 return MODE_OK;
859
860 return MODE_CLOCK_RANGE;
861}
862
863
864static void
865intel_tv_get_config(struct intel_encoder *encoder,
866 struct intel_crtc_state *pipe_config)
867{
868 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
869
870 pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
871}
872
873static bool
874intel_tv_compute_config(struct intel_encoder *encoder,
875 struct intel_crtc_state *pipe_config,
876 struct drm_connector_state *conn_state)
877{
878 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
879 struct drm_display_mode *adjusted_mode =
880 &pipe_config->base.adjusted_mode;
881
882 if (!tv_mode)
883 return false;
884
885 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
886 return false;
887
888 pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
889 adjusted_mode->crtc_clock = tv_mode->clock;
890 DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
891 pipe_config->pipe_bpp = 8*3;
892
893
894 adjusted_mode->flags = 0;
895
896
897
898
899
900
901 return true;
902}
903
904static void
905set_tv_mode_timings(struct drm_i915_private *dev_priv,
906 const struct tv_mode *tv_mode,
907 bool burst_ena)
908{
909 u32 hctl1, hctl2, hctl3;
910 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
911
912 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
913 (tv_mode->htotal << TV_HTOTAL_SHIFT);
914
915 hctl2 = (tv_mode->hburst_start << 16) |
916 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
917
918 if (burst_ena)
919 hctl2 |= TV_BURST_ENA;
920
921 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
922 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
923
924 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
925 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
926 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
927
928 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
929 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
930 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
931
932 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
933 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
934 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
935
936 if (tv_mode->veq_ena)
937 vctl3 |= TV_EQUAL_ENA;
938
939 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
940 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
941
942 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
943 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
944
945 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
946 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
947
948 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
949 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
950
951 I915_WRITE(TV_H_CTL_1, hctl1);
952 I915_WRITE(TV_H_CTL_2, hctl2);
953 I915_WRITE(TV_H_CTL_3, hctl3);
954 I915_WRITE(TV_V_CTL_1, vctl1);
955 I915_WRITE(TV_V_CTL_2, vctl2);
956 I915_WRITE(TV_V_CTL_3, vctl3);
957 I915_WRITE(TV_V_CTL_4, vctl4);
958 I915_WRITE(TV_V_CTL_5, vctl5);
959 I915_WRITE(TV_V_CTL_6, vctl6);
960 I915_WRITE(TV_V_CTL_7, vctl7);
961}
962
963static void set_color_conversion(struct drm_i915_private *dev_priv,
964 const struct color_conversion *color_conversion)
965{
966 if (!color_conversion)
967 return;
968
969 I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
970 color_conversion->gy);
971 I915_WRITE(TV_CSC_Y2, (color_conversion->by << 16) |
972 color_conversion->ay);
973 I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
974 color_conversion->gu);
975 I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
976 color_conversion->au);
977 I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
978 color_conversion->gv);
979 I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
980 color_conversion->av);
981}
982
983static void intel_tv_pre_enable(struct intel_encoder *encoder,
984 const struct intel_crtc_state *pipe_config,
985 const struct drm_connector_state *conn_state)
986{
987 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
988 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
989 struct intel_tv *intel_tv = enc_to_tv(encoder);
990 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
991 u32 tv_ctl;
992 u32 scctl1, scctl2, scctl3;
993 int i, j;
994 const struct video_levels *video_levels;
995 const struct color_conversion *color_conversion;
996 bool burst_ena;
997 int xpos = 0x0, ypos = 0x0;
998 unsigned int xsize, ysize;
999
1000 if (!tv_mode)
1001 return;
1002
1003 tv_ctl = I915_READ(TV_CTL);
1004 tv_ctl &= TV_CTL_SAVE;
1005
1006 switch (intel_tv->type) {
1007 default:
1008 case DRM_MODE_CONNECTOR_Unknown:
1009 case DRM_MODE_CONNECTOR_Composite:
1010 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1011 video_levels = tv_mode->composite_levels;
1012 color_conversion = tv_mode->composite_color;
1013 burst_ena = tv_mode->burst_ena;
1014 break;
1015 case DRM_MODE_CONNECTOR_Component:
1016 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1017 video_levels = &component_levels;
1018 if (tv_mode->burst_ena)
1019 color_conversion = &sdtv_csc_yprpb;
1020 else
1021 color_conversion = &hdtv_csc_yprpb;
1022 burst_ena = false;
1023 break;
1024 case DRM_MODE_CONNECTOR_SVIDEO:
1025 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1026 video_levels = tv_mode->svideo_levels;
1027 color_conversion = tv_mode->svideo_color;
1028 burst_ena = tv_mode->burst_ena;
1029 break;
1030 }
1031
1032 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1033 tv_ctl |= tv_mode->oversample;
1034
1035 if (tv_mode->progressive)
1036 tv_ctl |= TV_PROGRESSIVE;
1037 if (tv_mode->trilevel_sync)
1038 tv_ctl |= TV_TRILEVEL_SYNC;
1039 if (tv_mode->pal_burst)
1040 tv_ctl |= TV_PAL_BURST;
1041
1042 scctl1 = 0;
1043 if (tv_mode->dda1_inc)
1044 scctl1 |= TV_SC_DDA1_EN;
1045 if (tv_mode->dda2_inc)
1046 scctl1 |= TV_SC_DDA2_EN;
1047 if (tv_mode->dda3_inc)
1048 scctl1 |= TV_SC_DDA3_EN;
1049 scctl1 |= tv_mode->sc_reset;
1050 if (video_levels)
1051 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1052 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1053
1054 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1055 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1056
1057 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1058 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1059
1060
1061 if (IS_I915GM(dev_priv))
1062 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1063
1064 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1065
1066 I915_WRITE(TV_SC_CTL_1, scctl1);
1067 I915_WRITE(TV_SC_CTL_2, scctl2);
1068 I915_WRITE(TV_SC_CTL_3, scctl3);
1069
1070 set_color_conversion(dev_priv, color_conversion);
1071
1072 if (INTEL_GEN(dev_priv) >= 4)
1073 I915_WRITE(TV_CLR_KNOBS, 0x00404000);
1074 else
1075 I915_WRITE(TV_CLR_KNOBS, 0x00606000);
1076
1077 if (video_levels)
1078 I915_WRITE(TV_CLR_LEVEL,
1079 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
1080 (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1081
1082 assert_pipe_disabled(dev_priv, intel_crtc->pipe);
1083
1084
1085 I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
1086 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1087 if (tv_mode->progressive)
1088 ysize = tv_mode->nbr_end + 1;
1089 else
1090 ysize = 2*tv_mode->nbr_end + 1;
1091
1092 xpos += conn_state->tv.margins.left;
1093 ypos += conn_state->tv.margins.top;
1094 xsize -= (conn_state->tv.margins.left +
1095 conn_state->tv.margins.right);
1096 ysize -= (conn_state->tv.margins.top +
1097 conn_state->tv.margins.bottom);
1098 I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
1099 I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
1100
1101 j = 0;
1102 for (i = 0; i < 60; i++)
1103 I915_WRITE(TV_H_LUMA(i), tv_mode->filter_table[j++]);
1104 for (i = 0; i < 60; i++)
1105 I915_WRITE(TV_H_CHROMA(i), tv_mode->filter_table[j++]);
1106 for (i = 0; i < 43; i++)
1107 I915_WRITE(TV_V_LUMA(i), tv_mode->filter_table[j++]);
1108 for (i = 0; i < 43; i++)
1109 I915_WRITE(TV_V_CHROMA(i), tv_mode->filter_table[j++]);
1110 I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
1111 I915_WRITE(TV_CTL, tv_ctl);
1112}
1113
1114static const struct drm_display_mode reported_modes[] = {
1115 {
1116 .name = "NTSC 480i",
1117 .clock = 107520,
1118 .hdisplay = 1280,
1119 .hsync_start = 1368,
1120 .hsync_end = 1496,
1121 .htotal = 1712,
1122
1123 .vdisplay = 1024,
1124 .vsync_start = 1027,
1125 .vsync_end = 1034,
1126 .vtotal = 1104,
1127 .type = DRM_MODE_TYPE_DRIVER,
1128 },
1129};
1130
1131static int
1132intel_tv_detect_type(struct intel_tv *intel_tv,
1133 struct drm_connector *connector)
1134{
1135 struct drm_crtc *crtc = connector->state->crtc;
1136 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1137 struct drm_device *dev = connector->dev;
1138 struct drm_i915_private *dev_priv = to_i915(dev);
1139 u32 tv_ctl, save_tv_ctl;
1140 u32 tv_dac, save_tv_dac;
1141 int type;
1142
1143
1144 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1145 spin_lock_irq(&dev_priv->irq_lock);
1146 i915_disable_pipestat(dev_priv, 0,
1147 PIPE_HOTPLUG_INTERRUPT_STATUS |
1148 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1149 spin_unlock_irq(&dev_priv->irq_lock);
1150 }
1151
1152 save_tv_dac = tv_dac = I915_READ(TV_DAC);
1153 save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
1154
1155
1156 tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
1157 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1158 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1159
1160 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1161 tv_dac |= (TVDAC_STATE_CHG_EN |
1162 TVDAC_A_SENSE_CTL |
1163 TVDAC_B_SENSE_CTL |
1164 TVDAC_C_SENSE_CTL |
1165 DAC_CTL_OVERRIDE |
1166 DAC_A_0_7_V |
1167 DAC_B_0_7_V |
1168 DAC_C_0_7_V);
1169
1170
1171
1172
1173
1174
1175 if (IS_GM45(dev_priv))
1176 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1177 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1178
1179 I915_WRITE(TV_CTL, tv_ctl);
1180 I915_WRITE(TV_DAC, tv_dac);
1181 POSTING_READ(TV_DAC);
1182
1183 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1184
1185 type = -1;
1186 tv_dac = I915_READ(TV_DAC);
1187 DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
1188
1189
1190
1191
1192
1193
1194 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1195 DRM_DEBUG_KMS("Detected Composite TV connection\n");
1196 type = DRM_MODE_CONNECTOR_Composite;
1197 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1198 DRM_DEBUG_KMS("Detected S-Video TV connection\n");
1199 type = DRM_MODE_CONNECTOR_SVIDEO;
1200 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1201 DRM_DEBUG_KMS("Detected Component TV connection\n");
1202 type = DRM_MODE_CONNECTOR_Component;
1203 } else {
1204 DRM_DEBUG_KMS("Unrecognised TV connection\n");
1205 type = -1;
1206 }
1207
1208 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1209 I915_WRITE(TV_CTL, save_tv_ctl);
1210 POSTING_READ(TV_CTL);
1211
1212
1213 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1214
1215
1216 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1217 spin_lock_irq(&dev_priv->irq_lock);
1218 i915_enable_pipestat(dev_priv, 0,
1219 PIPE_HOTPLUG_INTERRUPT_STATUS |
1220 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1221 spin_unlock_irq(&dev_priv->irq_lock);
1222 }
1223
1224 return type;
1225}
1226
1227
1228
1229
1230
1231static void intel_tv_find_better_format(struct drm_connector *connector)
1232{
1233 struct intel_tv *intel_tv = intel_attached_tv(connector);
1234 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1235 int i;
1236
1237 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1238 tv_mode->component_only)
1239 return;
1240
1241
1242 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1243 tv_mode = tv_modes + i;
1244
1245 if ((intel_tv->type == DRM_MODE_CONNECTOR_Component) ==
1246 tv_mode->component_only)
1247 break;
1248 }
1249
1250 connector->state->tv.mode = i;
1251}
1252
1253static int
1254intel_tv_detect(struct drm_connector *connector,
1255 struct drm_modeset_acquire_ctx *ctx,
1256 bool force)
1257{
1258 struct drm_display_mode mode;
1259 struct intel_tv *intel_tv = intel_attached_tv(connector);
1260 enum drm_connector_status status;
1261 int type;
1262
1263 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
1264 connector->base.id, connector->name,
1265 force);
1266
1267 mode = reported_modes[0];
1268
1269 if (force) {
1270 struct intel_load_detect_pipe tmp;
1271 int ret;
1272
1273 ret = intel_get_load_detect_pipe(connector, &mode, &tmp, ctx);
1274 if (ret < 0)
1275 return ret;
1276
1277 if (ret > 0) {
1278 type = intel_tv_detect_type(intel_tv, connector);
1279 intel_release_load_detect_pipe(connector, &tmp, ctx);
1280 status = type < 0 ?
1281 connector_status_disconnected :
1282 connector_status_connected;
1283 } else
1284 status = connector_status_unknown;
1285
1286 if (status == connector_status_connected) {
1287 intel_tv->type = type;
1288 intel_tv_find_better_format(connector);
1289 }
1290
1291 return status;
1292 } else
1293 return connector->status;
1294}
1295
1296static const struct input_res {
1297 const char *name;
1298 int w, h;
1299} input_res_table[] = {
1300 {"640x480", 640, 480},
1301 {"800x600", 800, 600},
1302 {"1024x768", 1024, 768},
1303 {"1280x1024", 1280, 1024},
1304 {"848x480", 848, 480},
1305 {"1280x720", 1280, 720},
1306 {"1920x1080", 1920, 1080},
1307};
1308
1309
1310
1311
1312static void
1313intel_tv_choose_preferred_modes(const struct tv_mode *tv_mode,
1314 struct drm_display_mode *mode_ptr)
1315{
1316 if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
1317 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1318 else if (tv_mode->nbr_end > 480) {
1319 if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
1320 if (mode_ptr->vdisplay == 720)
1321 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1322 } else if (mode_ptr->vdisplay == 1080)
1323 mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
1324 }
1325}
1326
1327static int
1328intel_tv_get_modes(struct drm_connector *connector)
1329{
1330 struct drm_display_mode *mode_ptr;
1331 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1332 int j, count = 0;
1333 u64 tmp;
1334
1335 for (j = 0; j < ARRAY_SIZE(input_res_table);
1336 j++) {
1337 const struct input_res *input = &input_res_table[j];
1338 unsigned int hactive_s = input->w;
1339 unsigned int vactive_s = input->h;
1340
1341 if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
1342 continue;
1343
1344 if (input->w > 1024 && (!tv_mode->progressive
1345 && !tv_mode->component_only))
1346 continue;
1347
1348 mode_ptr = drm_mode_create(connector->dev);
1349 if (!mode_ptr)
1350 continue;
1351 strlcpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
1352
1353 mode_ptr->hdisplay = hactive_s;
1354 mode_ptr->hsync_start = hactive_s + 1;
1355 mode_ptr->hsync_end = hactive_s + 64;
1356 if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
1357 mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
1358 mode_ptr->htotal = hactive_s + 96;
1359
1360 mode_ptr->vdisplay = vactive_s;
1361 mode_ptr->vsync_start = vactive_s + 1;
1362 mode_ptr->vsync_end = vactive_s + 32;
1363 if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
1364 mode_ptr->vsync_end = mode_ptr->vsync_start + 1;
1365 mode_ptr->vtotal = vactive_s + 33;
1366
1367 tmp = mul_u32_u32(tv_mode->refresh, mode_ptr->vtotal);
1368 tmp *= mode_ptr->htotal;
1369 tmp = div_u64(tmp, 1000000);
1370 mode_ptr->clock = (int) tmp;
1371
1372 mode_ptr->type = DRM_MODE_TYPE_DRIVER;
1373 intel_tv_choose_preferred_modes(tv_mode, mode_ptr);
1374 drm_mode_probed_add(connector, mode_ptr);
1375 count++;
1376 }
1377
1378 return count;
1379}
1380
1381static const struct drm_connector_funcs intel_tv_connector_funcs = {
1382 .late_register = intel_connector_register,
1383 .early_unregister = intel_connector_unregister,
1384 .destroy = intel_connector_destroy,
1385 .fill_modes = drm_helper_probe_single_connector_modes,
1386 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1387 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
1388};
1389
1390static int intel_tv_atomic_check(struct drm_connector *connector,
1391 struct drm_connector_state *new_state)
1392{
1393 struct drm_crtc_state *new_crtc_state;
1394 struct drm_connector_state *old_state;
1395
1396 if (!new_state->crtc)
1397 return 0;
1398
1399 old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
1400 new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
1401
1402 if (old_state->tv.mode != new_state->tv.mode ||
1403 old_state->tv.margins.left != new_state->tv.margins.left ||
1404 old_state->tv.margins.right != new_state->tv.margins.right ||
1405 old_state->tv.margins.top != new_state->tv.margins.top ||
1406 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1407
1408
1409 new_crtc_state->connectors_changed = true;
1410 }
1411
1412 return 0;
1413}
1414
1415static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1416 .detect_ctx = intel_tv_detect,
1417 .mode_valid = intel_tv_mode_valid,
1418 .get_modes = intel_tv_get_modes,
1419 .atomic_check = intel_tv_atomic_check,
1420};
1421
1422static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1423 .destroy = intel_encoder_destroy,
1424};
1425
1426void
1427intel_tv_init(struct drm_i915_private *dev_priv)
1428{
1429 struct drm_device *dev = &dev_priv->drm;
1430 struct drm_connector *connector;
1431 struct intel_tv *intel_tv;
1432 struct intel_encoder *intel_encoder;
1433 struct intel_connector *intel_connector;
1434 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1435 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
1436 int i, initial_mode = 0;
1437 struct drm_connector_state *state;
1438
1439 if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1440 return;
1441
1442 if (!intel_bios_is_tv_present(dev_priv)) {
1443 DRM_DEBUG_KMS("Integrated TV is not present.\n");
1444 return;
1445 }
1446
1447
1448
1449
1450
1451 save_tv_dac = I915_READ(TV_DAC);
1452
1453 I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1454 tv_dac_on = I915_READ(TV_DAC);
1455
1456 I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1457 tv_dac_off = I915_READ(TV_DAC);
1458
1459 I915_WRITE(TV_DAC, save_tv_dac);
1460
1461
1462
1463
1464
1465
1466 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1467 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1468 return;
1469
1470 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
1471 if (!intel_tv) {
1472 return;
1473 }
1474
1475 intel_connector = intel_connector_alloc();
1476 if (!intel_connector) {
1477 kfree(intel_tv);
1478 return;
1479 }
1480
1481 intel_encoder = &intel_tv->base;
1482 connector = &intel_connector->base;
1483 state = connector->state;
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1496
1497 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1498 DRM_MODE_CONNECTOR_SVIDEO);
1499
1500 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1501 DRM_MODE_ENCODER_TVDAC, "TV");
1502
1503 intel_encoder->compute_config = intel_tv_compute_config;
1504 intel_encoder->get_config = intel_tv_get_config;
1505 intel_encoder->pre_enable = intel_tv_pre_enable;
1506 intel_encoder->enable = intel_enable_tv;
1507 intel_encoder->disable = intel_disable_tv;
1508 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1509 intel_connector->get_hw_state = intel_connector_get_hw_state;
1510
1511 intel_connector_attach_encoder(intel_connector, intel_encoder);
1512
1513 intel_encoder->type = INTEL_OUTPUT_TVOUT;
1514 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
1515 intel_encoder->port = PORT_NONE;
1516 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
1517 intel_encoder->cloneable = 0;
1518 intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
1519 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1520
1521
1522 state->tv.margins.left = 54;
1523 state->tv.margins.top = 36;
1524 state->tv.margins.right = 46;
1525 state->tv.margins.bottom = 37;
1526
1527 state->tv.mode = initial_mode;
1528
1529 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1530 connector->interlace_allowed = false;
1531 connector->doublescan_allowed = false;
1532
1533
1534 for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
1535 tv_format_names[i] = tv_modes[i].name;
1536 drm_mode_create_tv_properties(dev,
1537 ARRAY_SIZE(tv_modes),
1538 tv_format_names);
1539
1540 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
1541 state->tv.mode);
1542 drm_object_attach_property(&connector->base,
1543 dev->mode_config.tv_left_margin_property,
1544 state->tv.margins.left);
1545 drm_object_attach_property(&connector->base,
1546 dev->mode_config.tv_top_margin_property,
1547 state->tv.margins.top);
1548 drm_object_attach_property(&connector->base,
1549 dev->mode_config.tv_right_margin_property,
1550 state->tv.margins.right);
1551 drm_object_attach_property(&connector->base,
1552 dev->mode_config.tv_bottom_margin_property,
1553 state->tv.margins.bottom);
1554}
1555