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/drm_atomic_helper.h>
34#include <drm/drm_crtc.h>
35#include <drm/drm_edid.h>
36
37#include "i915_drv.h"
38#include "intel_connector.h"
39#include "intel_display_types.h"
40#include "intel_hotplug.h"
41#include "intel_tv.h"
42
43enum tv_margin {
44 TV_MARGIN_LEFT, TV_MARGIN_TOP,
45 TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
46};
47
48struct intel_tv {
49 struct intel_encoder base;
50
51 int type;
52};
53
54struct video_levels {
55 u16 blank, black;
56 u8 burst;
57};
58
59struct color_conversion {
60 u16 ry, gy, by, ay;
61 u16 ru, gu, bu, au;
62 u16 rv, gv, bv, av;
63};
64
65static const u32 filter_table[] = {
66 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
67 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
68 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
69 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
70 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
71 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
72 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
73 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
74 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
75 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
76 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
77 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
78 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
79 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
80 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
81 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
82 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
83 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
84 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
85 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
86 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
87 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
88 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
89 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
90 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
91 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
92 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
93 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
94 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
95 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
96 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
97 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
98 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
99 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
100 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
101 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
102 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
103 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
104 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
105 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
106 0x28003100, 0x28002F00, 0x00003100, 0x36403000,
107 0x2D002CC0, 0x30003640, 0x2D0036C0,
108 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
109 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
110 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
111 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
112 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
113 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
114 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
115 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
116 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
117 0x28003100, 0x28002F00, 0x00003100,
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
185
186
187static const struct color_conversion ntsc_m_csc_composite = {
188 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
189 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
190 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
191};
192
193static const struct video_levels ntsc_m_levels_composite = {
194 .blank = 225, .black = 267, .burst = 113,
195};
196
197static const struct color_conversion ntsc_m_csc_svideo = {
198 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
199 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
200 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
201};
202
203static const struct video_levels ntsc_m_levels_svideo = {
204 .blank = 266, .black = 316, .burst = 133,
205};
206
207static const struct color_conversion ntsc_j_csc_composite = {
208 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
209 .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0200,
210 .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0200,
211};
212
213static const struct video_levels ntsc_j_levels_composite = {
214 .blank = 225, .black = 225, .burst = 113,
215};
216
217static const struct color_conversion ntsc_j_csc_svideo = {
218 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
219 .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0200,
220 .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0200,
221};
222
223static const struct video_levels ntsc_j_levels_svideo = {
224 .blank = 266, .black = 266, .burst = 133,
225};
226
227static const struct color_conversion pal_csc_composite = {
228 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
229 .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0200,
230 .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0200,
231};
232
233static const struct video_levels pal_levels_composite = {
234 .blank = 237, .black = 237, .burst = 118,
235};
236
237static const struct color_conversion pal_csc_svideo = {
238 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
239 .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0200,
240 .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0200,
241};
242
243static const struct video_levels pal_levels_svideo = {
244 .blank = 280, .black = 280, .burst = 139,
245};
246
247static const struct color_conversion pal_m_csc_composite = {
248 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
249 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
250 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
251};
252
253static const struct video_levels pal_m_levels_composite = {
254 .blank = 225, .black = 267, .burst = 113,
255};
256
257static const struct color_conversion pal_m_csc_svideo = {
258 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
259 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
260 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
261};
262
263static const struct video_levels pal_m_levels_svideo = {
264 .blank = 266, .black = 316, .burst = 133,
265};
266
267static const struct color_conversion pal_n_csc_composite = {
268 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
269 .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0200,
270 .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0200,
271};
272
273static const struct video_levels pal_n_levels_composite = {
274 .blank = 225, .black = 267, .burst = 118,
275};
276
277static const struct color_conversion pal_n_csc_svideo = {
278 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0133,
279 .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0200,
280 .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0200,
281};
282
283static const struct video_levels pal_n_levels_svideo = {
284 .blank = 266, .black = 316, .burst = 139,
285};
286
287
288
289
290static const struct color_conversion sdtv_csc_yprpb = {
291 .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
292 .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0200,
293 .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0200,
294};
295
296static const struct color_conversion hdtv_csc_yprpb = {
297 .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0145,
298 .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0200,
299 .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0200,
300};
301
302static const struct video_levels component_levels = {
303 .blank = 279, .black = 279, .burst = 0,
304};
305
306
307struct tv_mode {
308 const char *name;
309
310 u32 clock;
311 u16 refresh;
312 u8 oversample;
313 u8 hsync_end;
314 u16 hblank_start, hblank_end, htotal;
315 bool progressive : 1, trilevel_sync : 1, component_only : 1;
316 u8 vsync_start_f1, vsync_start_f2, vsync_len;
317 bool veq_ena : 1;
318 u8 veq_start_f1, veq_start_f2, veq_len;
319 u8 vi_end_f1, vi_end_f2;
320 u16 nbr_end;
321 bool burst_ena : 1;
322 u8 hburst_start, hburst_len;
323 u8 vburst_start_f1;
324 u16 vburst_end_f1;
325 u8 vburst_start_f2;
326 u16 vburst_end_f2;
327 u8 vburst_start_f3;
328 u16 vburst_end_f3;
329 u8 vburst_start_f4;
330 u16 vburst_end_f4;
331
332
333
334 u16 dda2_size, dda3_size;
335 u8 dda1_inc;
336 u16 dda2_inc, dda3_inc;
337 u32 sc_reset;
338 bool pal_burst : 1;
339
340
341
342 const struct video_levels *composite_levels, *svideo_levels;
343 const struct color_conversion *composite_color, *svideo_color;
344 const u32 *filter_table;
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
377
378static const struct tv_mode tv_modes[] = {
379 {
380 .name = "NTSC-M",
381 .clock = 108000,
382 .refresh = 59940,
383 .oversample = 8,
384 .component_only = false,
385
386
387 .hsync_end = 64, .hblank_end = 124,
388 .hblank_start = 836, .htotal = 857,
389
390 .progressive = false, .trilevel_sync = false,
391
392 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
393 .vsync_len = 6,
394
395 .veq_ena = true, .veq_start_f1 = 0,
396 .veq_start_f2 = 1, .veq_len = 18,
397
398 .vi_end_f1 = 20, .vi_end_f2 = 21,
399 .nbr_end = 240,
400
401 .burst_ena = true,
402 .hburst_start = 72, .hburst_len = 34,
403 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
404 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
405 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
406 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
407
408
409 .dda1_inc = 135,
410 .dda2_inc = 20800, .dda2_size = 27456,
411 .dda3_inc = 0, .dda3_size = 0,
412 .sc_reset = TV_SC_RESET_EVERY_4,
413 .pal_burst = false,
414
415 .composite_levels = &ntsc_m_levels_composite,
416 .composite_color = &ntsc_m_csc_composite,
417 .svideo_levels = &ntsc_m_levels_svideo,
418 .svideo_color = &ntsc_m_csc_svideo,
419
420 .filter_table = filter_table,
421 },
422 {
423 .name = "NTSC-443",
424 .clock = 108000,
425 .refresh = 59940,
426 .oversample = 8,
427 .component_only = false,
428
429 .hsync_end = 64, .hblank_end = 124,
430 .hblank_start = 836, .htotal = 857,
431
432 .progressive = false, .trilevel_sync = false,
433
434 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
435 .vsync_len = 6,
436
437 .veq_ena = true, .veq_start_f1 = 0,
438 .veq_start_f2 = 1, .veq_len = 18,
439
440 .vi_end_f1 = 20, .vi_end_f2 = 21,
441 .nbr_end = 240,
442
443 .burst_ena = true,
444 .hburst_start = 72, .hburst_len = 34,
445 .vburst_start_f1 = 9, .vburst_end_f1 = 240,
446 .vburst_start_f2 = 10, .vburst_end_f2 = 240,
447 .vburst_start_f3 = 9, .vburst_end_f3 = 240,
448 .vburst_start_f4 = 10, .vburst_end_f4 = 240,
449
450
451 .dda1_inc = 168,
452 .dda2_inc = 4093, .dda2_size = 27456,
453 .dda3_inc = 310, .dda3_size = 525,
454 .sc_reset = TV_SC_RESET_NEVER,
455 .pal_burst = false,
456
457 .composite_levels = &ntsc_m_levels_composite,
458 .composite_color = &ntsc_m_csc_composite,
459 .svideo_levels = &ntsc_m_levels_svideo,
460 .svideo_color = &ntsc_m_csc_svideo,
461
462 .filter_table = filter_table,
463 },
464 {
465 .name = "NTSC-J",
466 .clock = 108000,
467 .refresh = 59940,
468 .oversample = 8,
469 .component_only = false,
470
471
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 = true,
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
494 .dda1_inc = 135,
495 .dda2_inc = 20800, .dda2_size = 27456,
496 .dda3_inc = 0, .dda3_size = 0,
497 .sc_reset = TV_SC_RESET_EVERY_4,
498 .pal_burst = false,
499
500 .composite_levels = &ntsc_j_levels_composite,
501 .composite_color = &ntsc_j_csc_composite,
502 .svideo_levels = &ntsc_j_levels_svideo,
503 .svideo_color = &ntsc_j_csc_svideo,
504
505 .filter_table = filter_table,
506 },
507 {
508 .name = "PAL-M",
509 .clock = 108000,
510 .refresh = 59940,
511 .oversample = 8,
512 .component_only = false,
513
514
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
537 .dda1_inc = 135,
538 .dda2_inc = 16704, .dda2_size = 27456,
539 .dda3_inc = 0, .dda3_size = 0,
540 .sc_reset = TV_SC_RESET_EVERY_8,
541 .pal_burst = true,
542
543 .composite_levels = &pal_m_levels_composite,
544 .composite_color = &pal_m_csc_composite,
545 .svideo_levels = &pal_m_levels_svideo,
546 .svideo_color = &pal_m_csc_svideo,
547
548 .filter_table = filter_table,
549 },
550 {
551
552 .name = "PAL-N",
553 .clock = 108000,
554 .refresh = 50000,
555 .oversample = 8,
556 .component_only = false,
557
558 .hsync_end = 64, .hblank_end = 128,
559 .hblank_start = 844, .htotal = 863,
560
561 .progressive = false, .trilevel_sync = false,
562
563
564 .vsync_start_f1 = 6, .vsync_start_f2 = 7,
565 .vsync_len = 6,
566
567 .veq_ena = true, .veq_start_f1 = 0,
568 .veq_start_f2 = 1, .veq_len = 18,
569
570 .vi_end_f1 = 24, .vi_end_f2 = 25,
571 .nbr_end = 286,
572
573 .burst_ena = true,
574 .hburst_start = 73, .hburst_len = 34,
575 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
576 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
577 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
578 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
579
580
581
582 .dda1_inc = 135,
583 .dda2_inc = 23578, .dda2_size = 27648,
584 .dda3_inc = 134, .dda3_size = 625,
585 .sc_reset = TV_SC_RESET_EVERY_8,
586 .pal_burst = true,
587
588 .composite_levels = &pal_n_levels_composite,
589 .composite_color = &pal_n_csc_composite,
590 .svideo_levels = &pal_n_levels_svideo,
591 .svideo_color = &pal_n_csc_svideo,
592
593 .filter_table = filter_table,
594 },
595 {
596
597 .name = "PAL",
598 .clock = 108000,
599 .refresh = 50000,
600 .oversample = 8,
601 .component_only = false,
602
603 .hsync_end = 64, .hblank_end = 142,
604 .hblank_start = 844, .htotal = 863,
605
606 .progressive = false, .trilevel_sync = false,
607
608 .vsync_start_f1 = 5, .vsync_start_f2 = 6,
609 .vsync_len = 5,
610
611 .veq_ena = true, .veq_start_f1 = 0,
612 .veq_start_f2 = 1, .veq_len = 15,
613
614 .vi_end_f1 = 24, .vi_end_f2 = 25,
615 .nbr_end = 286,
616
617 .burst_ena = true,
618 .hburst_start = 73, .hburst_len = 32,
619 .vburst_start_f1 = 8, .vburst_end_f1 = 285,
620 .vburst_start_f2 = 8, .vburst_end_f2 = 286,
621 .vburst_start_f3 = 9, .vburst_end_f3 = 286,
622 .vburst_start_f4 = 9, .vburst_end_f4 = 285,
623
624
625 .dda1_inc = 168,
626 .dda2_inc = 4122, .dda2_size = 27648,
627 .dda3_inc = 67, .dda3_size = 625,
628 .sc_reset = TV_SC_RESET_EVERY_8,
629 .pal_burst = true,
630
631 .composite_levels = &pal_levels_composite,
632 .composite_color = &pal_csc_composite,
633 .svideo_levels = &pal_levels_svideo,
634 .svideo_color = &pal_csc_svideo,
635
636 .filter_table = filter_table,
637 },
638 {
639 .name = "480p",
640 .clock = 108000,
641 .refresh = 59940,
642 .oversample = 4,
643 .component_only = true,
644
645 .hsync_end = 64, .hblank_end = 122,
646 .hblank_start = 842, .htotal = 857,
647
648 .progressive = true, .trilevel_sync = false,
649
650 .vsync_start_f1 = 12, .vsync_start_f2 = 12,
651 .vsync_len = 12,
652
653 .veq_ena = false,
654
655 .vi_end_f1 = 44, .vi_end_f2 = 44,
656 .nbr_end = 479,
657
658 .burst_ena = false,
659
660 .filter_table = filter_table,
661 },
662 {
663 .name = "576p",
664 .clock = 108000,
665 .refresh = 50000,
666 .oversample = 4,
667 .component_only = true,
668
669 .hsync_end = 64, .hblank_end = 139,
670 .hblank_start = 859, .htotal = 863,
671
672 .progressive = true, .trilevel_sync = false,
673
674 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
675 .vsync_len = 10,
676
677 .veq_ena = false,
678
679 .vi_end_f1 = 48, .vi_end_f2 = 48,
680 .nbr_end = 575,
681
682 .burst_ena = false,
683
684 .filter_table = filter_table,
685 },
686 {
687 .name = "720p@60Hz",
688 .clock = 148500,
689 .refresh = 60000,
690 .oversample = 2,
691 .component_only = true,
692
693 .hsync_end = 80, .hblank_end = 300,
694 .hblank_start = 1580, .htotal = 1649,
695
696 .progressive = true, .trilevel_sync = true,
697
698 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
699 .vsync_len = 10,
700
701 .veq_ena = false,
702
703 .vi_end_f1 = 29, .vi_end_f2 = 29,
704 .nbr_end = 719,
705
706 .burst_ena = false,
707
708 .filter_table = filter_table,
709 },
710 {
711 .name = "720p@50Hz",
712 .clock = 148500,
713 .refresh = 50000,
714 .oversample = 2,
715 .component_only = true,
716
717 .hsync_end = 80, .hblank_end = 300,
718 .hblank_start = 1580, .htotal = 1979,
719
720 .progressive = true, .trilevel_sync = true,
721
722 .vsync_start_f1 = 10, .vsync_start_f2 = 10,
723 .vsync_len = 10,
724
725 .veq_ena = false,
726
727 .vi_end_f1 = 29, .vi_end_f2 = 29,
728 .nbr_end = 719,
729
730 .burst_ena = false,
731
732 .filter_table = filter_table,
733 },
734 {
735 .name = "1080i@50Hz",
736 .clock = 148500,
737 .refresh = 50000,
738 .oversample = 2,
739 .component_only = true,
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 = 148500,
763 .refresh = 60000,
764 .oversample = 2,
765 .component_only = true,
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 {
788 .name = "1080p@30Hz",
789 .clock = 148500,
790 .refresh = 30000,
791 .oversample = 2,
792 .component_only = true,
793
794 .hsync_end = 88, .hblank_end = 235,
795 .hblank_start = 2155, .htotal = 2199,
796
797 .progressive = true, .trilevel_sync = true,
798
799 .vsync_start_f1 = 8, .vsync_start_f2 = 8,
800 .vsync_len = 10,
801
802 .veq_ena = false, .veq_start_f1 = 0,
803 .veq_start_f2 = 0, .veq_len = 0,
804
805 .vi_end_f1 = 44, .vi_end_f2 = 44,
806 .nbr_end = 1079,
807
808 .burst_ena = false,
809
810 .filter_table = filter_table,
811 },
812
813 {
814 .name = "1080p@50Hz",
815 .clock = 148500,
816 .refresh = 50000,
817 .oversample = 1,
818 .component_only = true,
819
820 .hsync_end = 88, .hblank_end = 235,
821 .hblank_start = 2155, .htotal = 2639,
822
823 .progressive = true, .trilevel_sync = true,
824
825 .vsync_start_f1 = 8, .vsync_start_f2 = 8,
826 .vsync_len = 10,
827
828 .veq_ena = false, .veq_start_f1 = 0,
829 .veq_start_f2 = 0, .veq_len = 0,
830
831 .vi_end_f1 = 44, .vi_end_f2 = 44,
832 .nbr_end = 1079,
833
834 .burst_ena = false,
835
836 .filter_table = filter_table,
837 },
838
839 {
840 .name = "1080p@60Hz",
841 .clock = 148500,
842 .refresh = 60000,
843 .oversample = 1,
844 .component_only = true,
845
846 .hsync_end = 88, .hblank_end = 235,
847 .hblank_start = 2155, .htotal = 2199,
848
849 .progressive = true, .trilevel_sync = true,
850
851 .vsync_start_f1 = 8, .vsync_start_f2 = 8,
852 .vsync_len = 10,
853
854 .veq_ena = false, .veq_start_f1 = 0,
855 .veq_start_f2 = 0, .veq_len = 0,
856
857 .vi_end_f1 = 44, .vi_end_f2 = 44,
858 .nbr_end = 1079,
859
860 .burst_ena = false,
861
862 .filter_table = filter_table,
863 },
864};
865
866struct intel_tv_connector_state {
867 struct drm_connector_state base;
868
869
870
871
872
873 struct {
874 u16 top, bottom;
875 } margins;
876
877 bool bypass_vfilter;
878};
879
880#define to_intel_tv_connector_state(x) container_of(x, struct intel_tv_connector_state, base)
881
882static struct drm_connector_state *
883intel_tv_connector_duplicate_state(struct drm_connector *connector)
884{
885 struct intel_tv_connector_state *state;
886
887 state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
888 if (!state)
889 return NULL;
890
891 __drm_atomic_helper_connector_duplicate_state(connector, &state->base);
892 return &state->base;
893}
894
895static struct intel_tv *enc_to_tv(struct intel_encoder *encoder)
896{
897 return container_of(encoder, struct intel_tv, base);
898}
899
900static struct intel_tv *intel_attached_tv(struct intel_connector *connector)
901{
902 return enc_to_tv(intel_attached_encoder(connector));
903}
904
905static bool
906intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
907{
908 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
909 u32 tmp = intel_de_read(dev_priv, TV_CTL);
910
911 *pipe = (tmp & TV_ENC_PIPE_SEL_MASK) >> TV_ENC_PIPE_SEL_SHIFT;
912
913 return tmp & TV_ENC_ENABLE;
914}
915
916static void
917intel_enable_tv(struct intel_atomic_state *state,
918 struct intel_encoder *encoder,
919 const struct intel_crtc_state *pipe_config,
920 const struct drm_connector_state *conn_state)
921{
922 struct drm_device *dev = encoder->base.dev;
923 struct drm_i915_private *dev_priv = to_i915(dev);
924
925
926 intel_wait_for_vblank(dev_priv,
927 to_intel_crtc(pipe_config->uapi.crtc)->pipe);
928
929 intel_de_write(dev_priv, TV_CTL,
930 intel_de_read(dev_priv, TV_CTL) | TV_ENC_ENABLE);
931}
932
933static void
934intel_disable_tv(struct intel_atomic_state *state,
935 struct intel_encoder *encoder,
936 const struct intel_crtc_state *old_crtc_state,
937 const struct drm_connector_state *old_conn_state)
938{
939 struct drm_device *dev = encoder->base.dev;
940 struct drm_i915_private *dev_priv = to_i915(dev);
941
942 intel_de_write(dev_priv, TV_CTL,
943 intel_de_read(dev_priv, TV_CTL) & ~TV_ENC_ENABLE);
944}
945
946static const struct tv_mode *intel_tv_mode_find(const struct drm_connector_state *conn_state)
947{
948 int format = conn_state->tv.mode;
949
950 return &tv_modes[format];
951}
952
953static enum drm_mode_status
954intel_tv_mode_valid(struct drm_connector *connector,
955 struct drm_display_mode *mode)
956{
957 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
958 int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
959
960 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
961 return MODE_NO_DBLESCAN;
962
963 if (mode->clock > max_dotclk)
964 return MODE_CLOCK_HIGH;
965
966
967 if (abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000) >= 1000)
968 return MODE_CLOCK_RANGE;
969
970 return MODE_OK;
971}
972
973static int
974intel_tv_mode_vdisplay(const struct tv_mode *tv_mode)
975{
976 if (tv_mode->progressive)
977 return tv_mode->nbr_end + 1;
978 else
979 return 2 * (tv_mode->nbr_end + 1);
980}
981
982static void
983intel_tv_mode_to_mode(struct drm_display_mode *mode,
984 const struct tv_mode *tv_mode)
985{
986 mode->clock = tv_mode->clock /
987 (tv_mode->oversample >> !tv_mode->progressive);
988
989
990
991
992
993
994
995
996
997
998
999
1000 mode->hdisplay =
1001 tv_mode->hblank_start - tv_mode->hblank_end;
1002 mode->hsync_start = mode->hdisplay +
1003 tv_mode->htotal - tv_mode->hblank_start;
1004 mode->hsync_end = mode->hsync_start +
1005 tv_mode->hsync_end;
1006 mode->htotal = tv_mode->htotal + 1;
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 mode->vdisplay = intel_tv_mode_vdisplay(tv_mode);
1020 if (tv_mode->progressive) {
1021 mode->vsync_start = mode->vdisplay +
1022 tv_mode->vsync_start_f1 + 1;
1023 mode->vsync_end = mode->vsync_start +
1024 tv_mode->vsync_len;
1025 mode->vtotal = mode->vdisplay +
1026 tv_mode->vi_end_f1 + 1;
1027 } else {
1028 mode->vsync_start = mode->vdisplay +
1029 tv_mode->vsync_start_f1 + 1 +
1030 tv_mode->vsync_start_f2 + 1;
1031 mode->vsync_end = mode->vsync_start +
1032 2 * tv_mode->vsync_len;
1033 mode->vtotal = mode->vdisplay +
1034 tv_mode->vi_end_f1 + 1 +
1035 tv_mode->vi_end_f2 + 1;
1036 }
1037
1038
1039 mode->flags = 0;
1040
1041 mode->vrefresh = 0;
1042 mode->vrefresh = drm_mode_vrefresh(mode);
1043
1044 snprintf(mode->name, sizeof(mode->name),
1045 "%dx%d%c (%s)",
1046 mode->hdisplay, mode->vdisplay,
1047 tv_mode->progressive ? 'p' : 'i',
1048 tv_mode->name);
1049}
1050
1051static void intel_tv_scale_mode_horiz(struct drm_display_mode *mode,
1052 int hdisplay, int left_margin,
1053 int right_margin)
1054{
1055 int hsync_start = mode->hsync_start - mode->hdisplay + right_margin;
1056 int hsync_end = mode->hsync_end - mode->hdisplay + right_margin;
1057 int new_htotal = mode->htotal * hdisplay /
1058 (mode->hdisplay - left_margin - right_margin);
1059
1060 mode->clock = mode->clock * new_htotal / mode->htotal;
1061
1062 mode->hdisplay = hdisplay;
1063 mode->hsync_start = hdisplay + hsync_start * new_htotal / mode->htotal;
1064 mode->hsync_end = hdisplay + hsync_end * new_htotal / mode->htotal;
1065 mode->htotal = new_htotal;
1066}
1067
1068static void intel_tv_scale_mode_vert(struct drm_display_mode *mode,
1069 int vdisplay, int top_margin,
1070 int bottom_margin)
1071{
1072 int vsync_start = mode->vsync_start - mode->vdisplay + bottom_margin;
1073 int vsync_end = mode->vsync_end - mode->vdisplay + bottom_margin;
1074 int new_vtotal = mode->vtotal * vdisplay /
1075 (mode->vdisplay - top_margin - bottom_margin);
1076
1077 mode->clock = mode->clock * new_vtotal / mode->vtotal;
1078
1079 mode->vdisplay = vdisplay;
1080 mode->vsync_start = vdisplay + vsync_start * new_vtotal / mode->vtotal;
1081 mode->vsync_end = vdisplay + vsync_end * new_vtotal / mode->vtotal;
1082 mode->vtotal = new_vtotal;
1083}
1084
1085static void
1086intel_tv_get_config(struct intel_encoder *encoder,
1087 struct intel_crtc_state *pipe_config)
1088{
1089 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1090 struct drm_display_mode *adjusted_mode =
1091 &pipe_config->hw.adjusted_mode;
1092 struct drm_display_mode mode = {};
1093 u32 tv_ctl, hctl1, hctl3, vctl1, vctl2, tmp;
1094 struct tv_mode tv_mode = {};
1095 int hdisplay = adjusted_mode->crtc_hdisplay;
1096 int vdisplay = adjusted_mode->crtc_vdisplay;
1097 int xsize, ysize, xpos, ypos;
1098
1099 pipe_config->output_types |= BIT(INTEL_OUTPUT_TVOUT);
1100
1101 tv_ctl = intel_de_read(dev_priv, TV_CTL);
1102 hctl1 = intel_de_read(dev_priv, TV_H_CTL_1);
1103 hctl3 = intel_de_read(dev_priv, TV_H_CTL_3);
1104 vctl1 = intel_de_read(dev_priv, TV_V_CTL_1);
1105 vctl2 = intel_de_read(dev_priv, TV_V_CTL_2);
1106
1107 tv_mode.htotal = (hctl1 & TV_HTOTAL_MASK) >> TV_HTOTAL_SHIFT;
1108 tv_mode.hsync_end = (hctl1 & TV_HSYNC_END_MASK) >> TV_HSYNC_END_SHIFT;
1109
1110 tv_mode.hblank_start = (hctl3 & TV_HBLANK_START_MASK) >> TV_HBLANK_START_SHIFT;
1111 tv_mode.hblank_end = (hctl3 & TV_HSYNC_END_MASK) >> TV_HBLANK_END_SHIFT;
1112
1113 tv_mode.nbr_end = (vctl1 & TV_NBR_END_MASK) >> TV_NBR_END_SHIFT;
1114 tv_mode.vi_end_f1 = (vctl1 & TV_VI_END_F1_MASK) >> TV_VI_END_F1_SHIFT;
1115 tv_mode.vi_end_f2 = (vctl1 & TV_VI_END_F2_MASK) >> TV_VI_END_F2_SHIFT;
1116
1117 tv_mode.vsync_len = (vctl2 & TV_VSYNC_LEN_MASK) >> TV_VSYNC_LEN_SHIFT;
1118 tv_mode.vsync_start_f1 = (vctl2 & TV_VSYNC_START_F1_MASK) >> TV_VSYNC_START_F1_SHIFT;
1119 tv_mode.vsync_start_f2 = (vctl2 & TV_VSYNC_START_F2_MASK) >> TV_VSYNC_START_F2_SHIFT;
1120
1121 tv_mode.clock = pipe_config->port_clock;
1122
1123 tv_mode.progressive = tv_ctl & TV_PROGRESSIVE;
1124
1125 switch (tv_ctl & TV_OVERSAMPLE_MASK) {
1126 case TV_OVERSAMPLE_8X:
1127 tv_mode.oversample = 8;
1128 break;
1129 case TV_OVERSAMPLE_4X:
1130 tv_mode.oversample = 4;
1131 break;
1132 case TV_OVERSAMPLE_2X:
1133 tv_mode.oversample = 2;
1134 break;
1135 default:
1136 tv_mode.oversample = 1;
1137 break;
1138 }
1139
1140 tmp = intel_de_read(dev_priv, TV_WIN_POS);
1141 xpos = tmp >> 16;
1142 ypos = tmp & 0xffff;
1143
1144 tmp = intel_de_read(dev_priv, TV_WIN_SIZE);
1145 xsize = tmp >> 16;
1146 ysize = tmp & 0xffff;
1147
1148 intel_tv_mode_to_mode(&mode, &tv_mode);
1149
1150 drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
1151 drm_mode_debug_printmodeline(&mode);
1152
1153 intel_tv_scale_mode_horiz(&mode, hdisplay,
1154 xpos, mode.hdisplay - xsize - xpos);
1155 intel_tv_scale_mode_vert(&mode, vdisplay,
1156 ypos, mode.vdisplay - ysize - ypos);
1157
1158 adjusted_mode->crtc_clock = mode.clock;
1159 if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
1160 adjusted_mode->crtc_clock /= 2;
1161
1162
1163 if (IS_I965GM(dev_priv))
1164 adjusted_mode->private_flags |=
1165 I915_MODE_FLAG_USE_SCANLINE_COUNTER;
1166}
1167
1168static bool intel_tv_source_too_wide(struct drm_i915_private *dev_priv,
1169 int hdisplay)
1170{
1171 return IS_GEN(dev_priv, 3) && hdisplay > 1024;
1172}
1173
1174static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode,
1175 const struct drm_connector_state *conn_state,
1176 int vdisplay)
1177{
1178 return tv_mode->crtc_vdisplay -
1179 conn_state->tv.margins.top -
1180 conn_state->tv.margins.bottom !=
1181 vdisplay;
1182}
1183
1184static int
1185intel_tv_compute_config(struct intel_encoder *encoder,
1186 struct intel_crtc_state *pipe_config,
1187 struct drm_connector_state *conn_state)
1188{
1189 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1190 struct intel_tv_connector_state *tv_conn_state =
1191 to_intel_tv_connector_state(conn_state);
1192 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
1193 struct drm_display_mode *adjusted_mode =
1194 &pipe_config->hw.adjusted_mode;
1195 int hdisplay = adjusted_mode->crtc_hdisplay;
1196 int vdisplay = adjusted_mode->crtc_vdisplay;
1197
1198 if (!tv_mode)
1199 return -EINVAL;
1200
1201 if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
1202 return -EINVAL;
1203
1204 pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB;
1205
1206 drm_dbg_kms(&dev_priv->drm, "forcing bpc to 8 for TV\n");
1207 pipe_config->pipe_bpp = 8*3;
1208
1209 pipe_config->port_clock = tv_mode->clock;
1210
1211 intel_tv_mode_to_mode(adjusted_mode, tv_mode);
1212 drm_mode_set_crtcinfo(adjusted_mode, 0);
1213
1214 if (intel_tv_source_too_wide(dev_priv, hdisplay) ||
1215 !intel_tv_vert_scaling(adjusted_mode, conn_state, vdisplay)) {
1216 int extra, top, bottom;
1217
1218 extra = adjusted_mode->crtc_vdisplay - vdisplay;
1219
1220 if (extra < 0) {
1221 drm_dbg_kms(&dev_priv->drm,
1222 "No vertical scaling for >1024 pixel wide modes\n");
1223 return -EINVAL;
1224 }
1225
1226
1227
1228
1229 top = conn_state->tv.margins.top;
1230 bottom = conn_state->tv.margins.bottom;
1231
1232 if (top + bottom)
1233 top = extra * top / (top + bottom);
1234 else
1235 top = extra / 2;
1236 bottom = extra - top;
1237
1238 tv_conn_state->margins.top = top;
1239 tv_conn_state->margins.bottom = bottom;
1240
1241 tv_conn_state->bypass_vfilter = true;
1242
1243 if (!tv_mode->progressive) {
1244 adjusted_mode->clock /= 2;
1245 adjusted_mode->crtc_clock /= 2;
1246 adjusted_mode->flags |= DRM_MODE_FLAG_INTERLACE;
1247 }
1248 } else {
1249 tv_conn_state->margins.top = conn_state->tv.margins.top;
1250 tv_conn_state->margins.bottom = conn_state->tv.margins.bottom;
1251
1252 tv_conn_state->bypass_vfilter = false;
1253 }
1254
1255 drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
1256 drm_mode_debug_printmodeline(adjusted_mode);
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323 intel_tv_scale_mode_horiz(adjusted_mode, hdisplay,
1324 conn_state->tv.margins.left,
1325 conn_state->tv.margins.right);
1326 intel_tv_scale_mode_vert(adjusted_mode, vdisplay,
1327 tv_conn_state->margins.top,
1328 tv_conn_state->margins.bottom);
1329 drm_mode_set_crtcinfo(adjusted_mode, 0);
1330 adjusted_mode->name[0] = '\0';
1331
1332
1333 if (IS_I965GM(dev_priv))
1334 adjusted_mode->private_flags |=
1335 I915_MODE_FLAG_USE_SCANLINE_COUNTER;
1336
1337 return 0;
1338}
1339
1340static void
1341set_tv_mode_timings(struct drm_i915_private *dev_priv,
1342 const struct tv_mode *tv_mode,
1343 bool burst_ena)
1344{
1345 u32 hctl1, hctl2, hctl3;
1346 u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
1347
1348 hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
1349 (tv_mode->htotal << TV_HTOTAL_SHIFT);
1350
1351 hctl2 = (tv_mode->hburst_start << 16) |
1352 (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
1353
1354 if (burst_ena)
1355 hctl2 |= TV_BURST_ENA;
1356
1357 hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
1358 (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
1359
1360 vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
1361 (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
1362 (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
1363
1364 vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
1365 (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
1366 (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
1367
1368 vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
1369 (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
1370 (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
1371
1372 if (tv_mode->veq_ena)
1373 vctl3 |= TV_EQUAL_ENA;
1374
1375 vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
1376 (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
1377
1378 vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
1379 (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
1380
1381 vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
1382 (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
1383
1384 vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
1385 (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
1386
1387 intel_de_write(dev_priv, TV_H_CTL_1, hctl1);
1388 intel_de_write(dev_priv, TV_H_CTL_2, hctl2);
1389 intel_de_write(dev_priv, TV_H_CTL_3, hctl3);
1390 intel_de_write(dev_priv, TV_V_CTL_1, vctl1);
1391 intel_de_write(dev_priv, TV_V_CTL_2, vctl2);
1392 intel_de_write(dev_priv, TV_V_CTL_3, vctl3);
1393 intel_de_write(dev_priv, TV_V_CTL_4, vctl4);
1394 intel_de_write(dev_priv, TV_V_CTL_5, vctl5);
1395 intel_de_write(dev_priv, TV_V_CTL_6, vctl6);
1396 intel_de_write(dev_priv, TV_V_CTL_7, vctl7);
1397}
1398
1399static void set_color_conversion(struct drm_i915_private *dev_priv,
1400 const struct color_conversion *color_conversion)
1401{
1402 if (!color_conversion)
1403 return;
1404
1405 intel_de_write(dev_priv, TV_CSC_Y,
1406 (color_conversion->ry << 16) | color_conversion->gy);
1407 intel_de_write(dev_priv, TV_CSC_Y2,
1408 (color_conversion->by << 16) | color_conversion->ay);
1409 intel_de_write(dev_priv, TV_CSC_U,
1410 (color_conversion->ru << 16) | color_conversion->gu);
1411 intel_de_write(dev_priv, TV_CSC_U2,
1412 (color_conversion->bu << 16) | color_conversion->au);
1413 intel_de_write(dev_priv, TV_CSC_V,
1414 (color_conversion->rv << 16) | color_conversion->gv);
1415 intel_de_write(dev_priv, TV_CSC_V2,
1416 (color_conversion->bv << 16) | color_conversion->av);
1417}
1418
1419static void intel_tv_pre_enable(struct intel_atomic_state *state,
1420 struct intel_encoder *encoder,
1421 const struct intel_crtc_state *pipe_config,
1422 const struct drm_connector_state *conn_state)
1423{
1424 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
1425 struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->uapi.crtc);
1426 struct intel_tv *intel_tv = enc_to_tv(encoder);
1427 const struct intel_tv_connector_state *tv_conn_state =
1428 to_intel_tv_connector_state(conn_state);
1429 const struct tv_mode *tv_mode = intel_tv_mode_find(conn_state);
1430 u32 tv_ctl, tv_filter_ctl;
1431 u32 scctl1, scctl2, scctl3;
1432 int i, j;
1433 const struct video_levels *video_levels;
1434 const struct color_conversion *color_conversion;
1435 bool burst_ena;
1436 int xpos, ypos;
1437 unsigned int xsize, ysize;
1438
1439 if (!tv_mode)
1440 return;
1441
1442 tv_ctl = intel_de_read(dev_priv, TV_CTL);
1443 tv_ctl &= TV_CTL_SAVE;
1444
1445 switch (intel_tv->type) {
1446 default:
1447 case DRM_MODE_CONNECTOR_Unknown:
1448 case DRM_MODE_CONNECTOR_Composite:
1449 tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
1450 video_levels = tv_mode->composite_levels;
1451 color_conversion = tv_mode->composite_color;
1452 burst_ena = tv_mode->burst_ena;
1453 break;
1454 case DRM_MODE_CONNECTOR_Component:
1455 tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
1456 video_levels = &component_levels;
1457 if (tv_mode->burst_ena)
1458 color_conversion = &sdtv_csc_yprpb;
1459 else
1460 color_conversion = &hdtv_csc_yprpb;
1461 burst_ena = false;
1462 break;
1463 case DRM_MODE_CONNECTOR_SVIDEO:
1464 tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
1465 video_levels = tv_mode->svideo_levels;
1466 color_conversion = tv_mode->svideo_color;
1467 burst_ena = tv_mode->burst_ena;
1468 break;
1469 }
1470
1471 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1472
1473 switch (tv_mode->oversample) {
1474 case 8:
1475 tv_ctl |= TV_OVERSAMPLE_8X;
1476 break;
1477 case 4:
1478 tv_ctl |= TV_OVERSAMPLE_4X;
1479 break;
1480 case 2:
1481 tv_ctl |= TV_OVERSAMPLE_2X;
1482 break;
1483 default:
1484 tv_ctl |= TV_OVERSAMPLE_NONE;
1485 break;
1486 }
1487
1488 if (tv_mode->progressive)
1489 tv_ctl |= TV_PROGRESSIVE;
1490 if (tv_mode->trilevel_sync)
1491 tv_ctl |= TV_TRILEVEL_SYNC;
1492 if (tv_mode->pal_burst)
1493 tv_ctl |= TV_PAL_BURST;
1494
1495 scctl1 = 0;
1496 if (tv_mode->dda1_inc)
1497 scctl1 |= TV_SC_DDA1_EN;
1498 if (tv_mode->dda2_inc)
1499 scctl1 |= TV_SC_DDA2_EN;
1500 if (tv_mode->dda3_inc)
1501 scctl1 |= TV_SC_DDA3_EN;
1502 scctl1 |= tv_mode->sc_reset;
1503 if (video_levels)
1504 scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
1505 scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
1506
1507 scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
1508 tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
1509
1510 scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
1511 tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
1512
1513
1514 if (IS_I915GM(dev_priv))
1515 tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
1516
1517 set_tv_mode_timings(dev_priv, tv_mode, burst_ena);
1518
1519 intel_de_write(dev_priv, TV_SC_CTL_1, scctl1);
1520 intel_de_write(dev_priv, TV_SC_CTL_2, scctl2);
1521 intel_de_write(dev_priv, TV_SC_CTL_3, scctl3);
1522
1523 set_color_conversion(dev_priv, color_conversion);
1524
1525 if (INTEL_GEN(dev_priv) >= 4)
1526 intel_de_write(dev_priv, TV_CLR_KNOBS, 0x00404000);
1527 else
1528 intel_de_write(dev_priv, TV_CLR_KNOBS, 0x00606000);
1529
1530 if (video_levels)
1531 intel_de_write(dev_priv, TV_CLR_LEVEL,
1532 ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
1533
1534 assert_pipe_disabled(dev_priv, pipe_config->cpu_transcoder);
1535
1536
1537 tv_filter_ctl = TV_AUTO_SCALE;
1538 if (tv_conn_state->bypass_vfilter)
1539 tv_filter_ctl |= TV_V_FILTER_BYPASS;
1540 intel_de_write(dev_priv, TV_FILTER_CTL_1, tv_filter_ctl);
1541
1542 xsize = tv_mode->hblank_start - tv_mode->hblank_end;
1543 ysize = intel_tv_mode_vdisplay(tv_mode);
1544
1545 xpos = conn_state->tv.margins.left;
1546 ypos = tv_conn_state->margins.top;
1547 xsize -= (conn_state->tv.margins.left +
1548 conn_state->tv.margins.right);
1549 ysize -= (tv_conn_state->margins.top +
1550 tv_conn_state->margins.bottom);
1551 intel_de_write(dev_priv, TV_WIN_POS, (xpos << 16) | ypos);
1552 intel_de_write(dev_priv, TV_WIN_SIZE, (xsize << 16) | ysize);
1553
1554 j = 0;
1555 for (i = 0; i < 60; i++)
1556 intel_de_write(dev_priv, TV_H_LUMA(i),
1557 tv_mode->filter_table[j++]);
1558 for (i = 0; i < 60; i++)
1559 intel_de_write(dev_priv, TV_H_CHROMA(i),
1560 tv_mode->filter_table[j++]);
1561 for (i = 0; i < 43; i++)
1562 intel_de_write(dev_priv, TV_V_LUMA(i),
1563 tv_mode->filter_table[j++]);
1564 for (i = 0; i < 43; i++)
1565 intel_de_write(dev_priv, TV_V_CHROMA(i),
1566 tv_mode->filter_table[j++]);
1567 intel_de_write(dev_priv, TV_DAC,
1568 intel_de_read(dev_priv, TV_DAC) & TV_DAC_SAVE);
1569 intel_de_write(dev_priv, TV_CTL, tv_ctl);
1570}
1571
1572static int
1573intel_tv_detect_type(struct intel_tv *intel_tv,
1574 struct drm_connector *connector)
1575{
1576 struct drm_crtc *crtc = connector->state->crtc;
1577 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1578 struct drm_device *dev = connector->dev;
1579 struct drm_i915_private *dev_priv = to_i915(dev);
1580 u32 tv_ctl, save_tv_ctl;
1581 u32 tv_dac, save_tv_dac;
1582 int type;
1583
1584
1585 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1586 spin_lock_irq(&dev_priv->irq_lock);
1587 i915_disable_pipestat(dev_priv, 0,
1588 PIPE_HOTPLUG_INTERRUPT_STATUS |
1589 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1590 spin_unlock_irq(&dev_priv->irq_lock);
1591 }
1592
1593 save_tv_dac = tv_dac = intel_de_read(dev_priv, TV_DAC);
1594 save_tv_ctl = tv_ctl = intel_de_read(dev_priv, TV_CTL);
1595
1596
1597 tv_ctl &= ~(TV_ENC_ENABLE | TV_ENC_PIPE_SEL_MASK | TV_TEST_MODE_MASK);
1598 tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
1599 tv_ctl |= TV_ENC_PIPE_SEL(intel_crtc->pipe);
1600
1601 tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
1602 tv_dac |= (TVDAC_STATE_CHG_EN |
1603 TVDAC_A_SENSE_CTL |
1604 TVDAC_B_SENSE_CTL |
1605 TVDAC_C_SENSE_CTL |
1606 DAC_CTL_OVERRIDE |
1607 DAC_A_0_7_V |
1608 DAC_B_0_7_V |
1609 DAC_C_0_7_V);
1610
1611
1612
1613
1614
1615
1616 if (IS_GM45(dev_priv))
1617 tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
1618 TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
1619
1620 intel_de_write(dev_priv, TV_CTL, tv_ctl);
1621 intel_de_write(dev_priv, TV_DAC, tv_dac);
1622 intel_de_posting_read(dev_priv, TV_DAC);
1623
1624 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1625
1626 type = -1;
1627 tv_dac = intel_de_read(dev_priv, TV_DAC);
1628 drm_dbg_kms(&dev_priv->drm, "TV detected: %x, %x\n", tv_ctl, tv_dac);
1629
1630
1631
1632
1633
1634
1635 if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
1636 drm_dbg_kms(&dev_priv->drm,
1637 "Detected Composite TV connection\n");
1638 type = DRM_MODE_CONNECTOR_Composite;
1639 } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
1640 drm_dbg_kms(&dev_priv->drm,
1641 "Detected S-Video TV connection\n");
1642 type = DRM_MODE_CONNECTOR_SVIDEO;
1643 } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
1644 drm_dbg_kms(&dev_priv->drm,
1645 "Detected Component TV connection\n");
1646 type = DRM_MODE_CONNECTOR_Component;
1647 } else {
1648 drm_dbg_kms(&dev_priv->drm, "Unrecognised TV connection\n");
1649 type = -1;
1650 }
1651
1652 intel_de_write(dev_priv, TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1653 intel_de_write(dev_priv, TV_CTL, save_tv_ctl);
1654 intel_de_posting_read(dev_priv, TV_CTL);
1655
1656
1657 intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
1658
1659
1660 if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
1661 spin_lock_irq(&dev_priv->irq_lock);
1662 i915_enable_pipestat(dev_priv, 0,
1663 PIPE_HOTPLUG_INTERRUPT_STATUS |
1664 PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
1665 spin_unlock_irq(&dev_priv->irq_lock);
1666 }
1667
1668 return type;
1669}
1670
1671
1672
1673
1674
1675static void intel_tv_find_better_format(struct drm_connector *connector)
1676{
1677 struct intel_tv *intel_tv = intel_attached_tv(to_intel_connector(connector));
1678 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1679 int i;
1680
1681
1682 if (intel_tv->type == DRM_MODE_CONNECTOR_Component)
1683 return;
1684
1685
1686 if (!tv_mode->component_only)
1687 return;
1688
1689 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1690 tv_mode = &tv_modes[i];
1691
1692 if (!tv_mode->component_only)
1693 break;
1694 }
1695
1696 connector->state->tv.mode = i;
1697}
1698
1699static int
1700intel_tv_detect(struct drm_connector *connector,
1701 struct drm_modeset_acquire_ctx *ctx,
1702 bool force)
1703{
1704 struct drm_i915_private *i915 = to_i915(connector->dev);
1705 struct intel_tv *intel_tv = intel_attached_tv(to_intel_connector(connector));
1706 enum drm_connector_status status;
1707 int type;
1708
1709 drm_dbg_kms(&i915->drm, "[CONNECTOR:%d:%s] force=%d\n",
1710 connector->base.id, connector->name, force);
1711
1712 if (force) {
1713 struct intel_load_detect_pipe tmp;
1714 int ret;
1715
1716 ret = intel_get_load_detect_pipe(connector, &tmp, ctx);
1717 if (ret < 0)
1718 return ret;
1719
1720 if (ret > 0) {
1721 type = intel_tv_detect_type(intel_tv, connector);
1722 intel_release_load_detect_pipe(connector, &tmp, ctx);
1723 status = type < 0 ?
1724 connector_status_disconnected :
1725 connector_status_connected;
1726 } else
1727 status = connector_status_unknown;
1728
1729 if (status == connector_status_connected) {
1730 intel_tv->type = type;
1731 intel_tv_find_better_format(connector);
1732 }
1733
1734 return status;
1735 } else
1736 return connector->status;
1737}
1738
1739static const struct input_res {
1740 u16 w, h;
1741} input_res_table[] = {
1742 { 640, 480 },
1743 { 800, 600 },
1744 { 1024, 768 },
1745 { 1280, 1024 },
1746 { 848, 480 },
1747 { 1280, 720 },
1748 { 1920, 1080 },
1749};
1750
1751
1752static bool
1753intel_tv_is_preferred_mode(const struct drm_display_mode *mode,
1754 const struct tv_mode *tv_mode)
1755{
1756 int vdisplay = intel_tv_mode_vdisplay(tv_mode);
1757
1758
1759 if (vdisplay <= 576)
1760 vdisplay = 480;
1761
1762 return vdisplay == mode->vdisplay;
1763}
1764
1765static void
1766intel_tv_set_mode_type(struct drm_display_mode *mode,
1767 const struct tv_mode *tv_mode)
1768{
1769 mode->type = DRM_MODE_TYPE_DRIVER;
1770
1771 if (intel_tv_is_preferred_mode(mode, tv_mode))
1772 mode->type |= DRM_MODE_TYPE_PREFERRED;
1773}
1774
1775static int
1776intel_tv_get_modes(struct drm_connector *connector)
1777{
1778 struct drm_i915_private *dev_priv = to_i915(connector->dev);
1779 const struct tv_mode *tv_mode = intel_tv_mode_find(connector->state);
1780 int i, count = 0;
1781
1782 for (i = 0; i < ARRAY_SIZE(input_res_table); i++) {
1783 const struct input_res *input = &input_res_table[i];
1784 struct drm_display_mode *mode;
1785
1786 if (input->w > 1024 &&
1787 !tv_mode->progressive &&
1788 !tv_mode->component_only)
1789 continue;
1790
1791
1792 if (IS_GEN(dev_priv, 3) && input->w > 1024 &&
1793 input->h > intel_tv_mode_vdisplay(tv_mode))
1794 continue;
1795
1796 mode = drm_mode_create(connector->dev);
1797 if (!mode)
1798 continue;
1799
1800
1801
1802
1803
1804
1805
1806
1807 intel_tv_mode_to_mode(mode, tv_mode);
1808 if (count == 0) {
1809 drm_dbg_kms(&dev_priv->drm, "TV mode:\n");
1810 drm_mode_debug_printmodeline(mode);
1811 }
1812 intel_tv_scale_mode_horiz(mode, input->w, 0, 0);
1813 intel_tv_scale_mode_vert(mode, input->h, 0, 0);
1814 intel_tv_set_mode_type(mode, tv_mode);
1815
1816 drm_mode_set_name(mode);
1817
1818 drm_mode_probed_add(connector, mode);
1819 count++;
1820 }
1821
1822 return count;
1823}
1824
1825static const struct drm_connector_funcs intel_tv_connector_funcs = {
1826 .late_register = intel_connector_register,
1827 .early_unregister = intel_connector_unregister,
1828 .destroy = intel_connector_destroy,
1829 .fill_modes = drm_helper_probe_single_connector_modes,
1830 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
1831 .atomic_duplicate_state = intel_tv_connector_duplicate_state,
1832};
1833
1834static int intel_tv_atomic_check(struct drm_connector *connector,
1835 struct drm_atomic_state *state)
1836{
1837 struct drm_connector_state *new_state;
1838 struct drm_crtc_state *new_crtc_state;
1839 struct drm_connector_state *old_state;
1840
1841 new_state = drm_atomic_get_new_connector_state(state, connector);
1842 if (!new_state->crtc)
1843 return 0;
1844
1845 old_state = drm_atomic_get_old_connector_state(state, connector);
1846 new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
1847
1848 if (old_state->tv.mode != new_state->tv.mode ||
1849 old_state->tv.margins.left != new_state->tv.margins.left ||
1850 old_state->tv.margins.right != new_state->tv.margins.right ||
1851 old_state->tv.margins.top != new_state->tv.margins.top ||
1852 old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
1853
1854
1855 new_crtc_state->connectors_changed = true;
1856 }
1857
1858 return 0;
1859}
1860
1861static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
1862 .detect_ctx = intel_tv_detect,
1863 .mode_valid = intel_tv_mode_valid,
1864 .get_modes = intel_tv_get_modes,
1865 .atomic_check = intel_tv_atomic_check,
1866};
1867
1868static const struct drm_encoder_funcs intel_tv_enc_funcs = {
1869 .destroy = intel_encoder_destroy,
1870};
1871
1872void
1873intel_tv_init(struct drm_i915_private *dev_priv)
1874{
1875 struct drm_device *dev = &dev_priv->drm;
1876 struct drm_connector *connector;
1877 struct intel_tv *intel_tv;
1878 struct intel_encoder *intel_encoder;
1879 struct intel_connector *intel_connector;
1880 u32 tv_dac_on, tv_dac_off, save_tv_dac;
1881 const char *tv_format_names[ARRAY_SIZE(tv_modes)];
1882 int i, initial_mode = 0;
1883 struct drm_connector_state *state;
1884
1885 if ((intel_de_read(dev_priv, TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
1886 return;
1887
1888 if (!intel_bios_is_tv_present(dev_priv)) {
1889 drm_dbg_kms(&dev_priv->drm, "Integrated TV is not present.\n");
1890 return;
1891 }
1892
1893
1894
1895
1896
1897 save_tv_dac = intel_de_read(dev_priv, TV_DAC);
1898
1899 intel_de_write(dev_priv, TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
1900 tv_dac_on = intel_de_read(dev_priv, TV_DAC);
1901
1902 intel_de_write(dev_priv, TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
1903 tv_dac_off = intel_de_read(dev_priv, TV_DAC);
1904
1905 intel_de_write(dev_priv, TV_DAC, save_tv_dac);
1906
1907
1908
1909
1910
1911
1912 if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 ||
1913 (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
1914 return;
1915
1916 intel_tv = kzalloc(sizeof(*intel_tv), GFP_KERNEL);
1917 if (!intel_tv) {
1918 return;
1919 }
1920
1921 intel_connector = intel_connector_alloc();
1922 if (!intel_connector) {
1923 kfree(intel_tv);
1924 return;
1925 }
1926
1927 intel_encoder = &intel_tv->base;
1928 connector = &intel_connector->base;
1929 state = connector->state;
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941 intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1942
1943 drm_connector_init(dev, connector, &intel_tv_connector_funcs,
1944 DRM_MODE_CONNECTOR_SVIDEO);
1945
1946 drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
1947 DRM_MODE_ENCODER_TVDAC, "TV");
1948
1949 intel_encoder->compute_config = intel_tv_compute_config;
1950 intel_encoder->get_config = intel_tv_get_config;
1951 intel_encoder->pre_enable = intel_tv_pre_enable;
1952 intel_encoder->enable = intel_enable_tv;
1953 intel_encoder->disable = intel_disable_tv;
1954 intel_encoder->get_hw_state = intel_tv_get_hw_state;
1955 intel_connector->get_hw_state = intel_connector_get_hw_state;
1956
1957 intel_connector_attach_encoder(intel_connector, intel_encoder);
1958
1959 intel_encoder->type = INTEL_OUTPUT_TVOUT;
1960 intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
1961 intel_encoder->port = PORT_NONE;
1962 intel_encoder->pipe_mask = ~0;
1963 intel_encoder->cloneable = 0;
1964 intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
1965
1966
1967 state->tv.margins.left = 54;
1968 state->tv.margins.top = 36;
1969 state->tv.margins.right = 46;
1970 state->tv.margins.bottom = 37;
1971
1972 state->tv.mode = initial_mode;
1973
1974 drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
1975 connector->interlace_allowed = false;
1976 connector->doublescan_allowed = false;
1977
1978
1979 for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
1980
1981 if (IS_GEN(dev_priv, 3) &&
1982 tv_modes[i].oversample == 1)
1983 break;
1984
1985 tv_format_names[i] = tv_modes[i].name;
1986 }
1987 drm_mode_create_tv_properties(dev, i, tv_format_names);
1988
1989 drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
1990 state->tv.mode);
1991 drm_object_attach_property(&connector->base,
1992 dev->mode_config.tv_left_margin_property,
1993 state->tv.margins.left);
1994 drm_object_attach_property(&connector->base,
1995 dev->mode_config.tv_top_margin_property,
1996 state->tv.margins.top);
1997 drm_object_attach_property(&connector->base,
1998 dev->mode_config.tv_right_margin_property,
1999 state->tv.margins.right);
2000 drm_object_attach_property(&connector->base,
2001 dev->mode_config.tv_bottom_margin_property,
2002 state->tv.margins.bottom);
2003}
2004