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 <linux/list.h>
34#include <linux/list_sort.h>
35#include <linux/export.h>
36#include <drm/drmP.h>
37#include <drm/drm_crtc.h>
38#include <video/of_videomode.h>
39#include <video/videomode.h>
40#include <drm/drm_modes.h>
41
42#include "drm_crtc_internal.h"
43
44
45
46
47
48
49
50void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
51{
52 DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
53}
54EXPORT_SYMBOL(drm_mode_debug_printmodeline);
55
56
57
58
59
60
61
62
63
64
65
66struct drm_display_mode *drm_mode_create(struct drm_device *dev)
67{
68 struct drm_display_mode *nmode;
69
70 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
71 if (!nmode)
72 return NULL;
73
74 if (drm_mode_object_add(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
75 kfree(nmode);
76 return NULL;
77 }
78
79 return nmode;
80}
81EXPORT_SYMBOL(drm_mode_create);
82
83
84
85
86
87
88
89
90void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
91{
92 if (!mode)
93 return;
94
95 drm_mode_object_unregister(dev, &mode->base);
96
97 kfree(mode);
98}
99EXPORT_SYMBOL(drm_mode_destroy);
100
101
102
103
104
105
106
107
108
109
110void drm_mode_probed_add(struct drm_connector *connector,
111 struct drm_display_mode *mode)
112{
113 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
114
115 list_add_tail(&mode->head, &connector->probed_modes);
116}
117EXPORT_SYMBOL(drm_mode_probed_add);
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
143struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
144 int vdisplay, int vrefresh,
145 bool reduced, bool interlaced, bool margins)
146{
147#define HV_FACTOR 1000
148
149#define CVT_MARGIN_PERCENTAGE 18
150
151#define CVT_H_GRANULARITY 8
152
153#define CVT_MIN_V_PORCH 3
154
155#define CVT_MIN_V_BPORCH 6
156
157#define CVT_CLOCK_STEP 250
158 struct drm_display_mode *drm_mode;
159 unsigned int vfieldrate, hperiod;
160 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
161 int interlace;
162 u64 tmp;
163
164
165
166
167 drm_mode = drm_mode_create(dev);
168 if (!drm_mode)
169 return NULL;
170
171
172 if (!vrefresh)
173 vrefresh = 60;
174
175
176 if (interlaced)
177 vfieldrate = vrefresh * 2;
178 else
179 vfieldrate = vrefresh;
180
181
182 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
183
184
185 hmargin = 0;
186 if (margins) {
187 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
188 hmargin -= hmargin % CVT_H_GRANULARITY;
189 }
190
191 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
192
193
194 if (interlaced)
195 vdisplay_rnd = vdisplay / 2;
196 else
197 vdisplay_rnd = vdisplay;
198
199
200 vmargin = 0;
201 if (margins)
202 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
203
204 drm_mode->vdisplay = vdisplay + 2 * vmargin;
205
206
207 if (interlaced)
208 interlace = 1;
209 else
210 interlace = 0;
211
212
213 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
214 vsync = 4;
215 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
216 vsync = 5;
217 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
218 vsync = 6;
219 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
220 vsync = 7;
221 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
222 vsync = 7;
223 else
224 vsync = 10;
225
226 if (!reduced) {
227
228
229
230
231 int tmp1, tmp2;
232#define CVT_MIN_VSYNC_BP 550
233
234#define CVT_HSYNC_PERCENTAGE 8
235 unsigned int hblank_percentage;
236 int vsyncandback_porch, vback_porch, hblank;
237
238
239 tmp1 = HV_FACTOR * 1000000 -
240 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
241 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
242 interlace;
243 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
244
245 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
246
247 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
248 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
249 else
250 vsyncandback_porch = tmp1;
251
252 vback_porch = vsyncandback_porch - vsync;
253 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
254 vsyncandback_porch + CVT_MIN_V_PORCH;
255
256
257#define CVT_M_FACTOR 600
258
259#define CVT_C_FACTOR 40
260
261#define CVT_K_FACTOR 128
262
263#define CVT_J_FACTOR 20
264#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
265#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
266 CVT_J_FACTOR)
267
268 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
269 hperiod / 1000;
270
271 if (hblank_percentage < 20 * HV_FACTOR)
272 hblank_percentage = 20 * HV_FACTOR;
273 hblank = drm_mode->hdisplay * hblank_percentage /
274 (100 * HV_FACTOR - hblank_percentage);
275 hblank -= hblank % (2 * CVT_H_GRANULARITY);
276
277 drm_mode->htotal = drm_mode->hdisplay + hblank;
278 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
279 drm_mode->hsync_start = drm_mode->hsync_end -
280 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
281 drm_mode->hsync_start += CVT_H_GRANULARITY -
282 drm_mode->hsync_start % CVT_H_GRANULARITY;
283
284 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
285 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
286 } else {
287
288
289#define CVT_RB_MIN_VBLANK 460
290
291#define CVT_RB_H_SYNC 32
292
293#define CVT_RB_H_BLANK 160
294
295#define CVT_RB_VFPORCH 3
296 int vbilines;
297 int tmp1, tmp2;
298
299 tmp1 = HV_FACTOR * 1000000 -
300 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
301 tmp2 = vdisplay_rnd + 2 * vmargin;
302 hperiod = tmp1 / (tmp2 * vfieldrate);
303
304 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
305
306 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
307 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
308
309 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
310
311 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
312
313 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
314 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
315
316 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
317 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
318 }
319
320 tmp = drm_mode->htotal;
321 tmp *= HV_FACTOR * 1000;
322 do_div(tmp, hperiod);
323 tmp -= drm_mode->clock % CVT_CLOCK_STEP;
324 drm_mode->clock = tmp;
325
326
327 if (interlaced) {
328 drm_mode->vtotal *= 2;
329 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
330 }
331
332 drm_mode_set_name(drm_mode);
333 if (reduced)
334 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
335 DRM_MODE_FLAG_NVSYNC);
336 else
337 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
338 DRM_MODE_FLAG_NHSYNC);
339
340 return drm_mode;
341}
342EXPORT_SYMBOL(drm_cvt_mode);
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365struct drm_display_mode *
366drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
367 int vrefresh, bool interlaced, int margins,
368 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
369{
370#define GTF_MARGIN_PERCENTAGE 18
371
372#define GTF_CELL_GRAN 8
373
374#define GTF_MIN_V_PORCH 1
375
376#define V_SYNC_RQD 3
377
378#define H_SYNC_PERCENT 8
379
380#define MIN_VSYNC_PLUS_BP 550
381
382#define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
383#define GTF_M_PRIME (GTF_K * GTF_M / 256)
384 struct drm_display_mode *drm_mode;
385 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
386 int top_margin, bottom_margin;
387 int interlace;
388 unsigned int hfreq_est;
389 int vsync_plus_bp, vback_porch;
390 unsigned int vtotal_lines, vfieldrate_est, hperiod;
391 unsigned int vfield_rate, vframe_rate;
392 int left_margin, right_margin;
393 unsigned int total_active_pixels, ideal_duty_cycle;
394 unsigned int hblank, total_pixels, pixel_freq;
395 int hsync, hfront_porch, vodd_front_porch_lines;
396 unsigned int tmp1, tmp2;
397
398 drm_mode = drm_mode_create(dev);
399 if (!drm_mode)
400 return NULL;
401
402
403
404
405
406
407 hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
408 hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
409
410
411
412
413
414 if (interlaced)
415 vdisplay_rnd = vdisplay / 2;
416 else
417 vdisplay_rnd = vdisplay;
418
419
420 if (interlaced)
421 vfieldrate_rqd = vrefresh * 2;
422 else
423 vfieldrate_rqd = vrefresh;
424
425
426 top_margin = 0;
427 if (margins)
428 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
429 1000;
430
431 bottom_margin = top_margin;
432
433
434 if (interlaced)
435 interlace = 1;
436 else
437 interlace = 0;
438
439
440 {
441 tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
442 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
443 2 + interlace;
444 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
445 }
446
447
448
449 vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
450 vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
451
452 vback_porch = vsync_plus_bp - V_SYNC_RQD;
453
454 vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
455 vsync_plus_bp + GTF_MIN_V_PORCH;
456
457 vfieldrate_est = hfreq_est / vtotal_lines;
458
459 hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
460
461
462 vfield_rate = hfreq_est / vtotal_lines;
463
464 if (interlaced)
465 vframe_rate = vfield_rate / 2;
466 else
467 vframe_rate = vfield_rate;
468
469 if (margins)
470 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
471 1000;
472 else
473 left_margin = 0;
474
475
476 right_margin = left_margin;
477
478 total_active_pixels = hdisplay_rnd + left_margin + right_margin;
479
480 ideal_duty_cycle = GTF_C_PRIME * 1000 -
481 (GTF_M_PRIME * 1000000 / hfreq_est);
482
483
484 hblank = total_active_pixels * ideal_duty_cycle /
485 (100000 - ideal_duty_cycle);
486 hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
487 hblank = hblank * 2 * GTF_CELL_GRAN;
488
489 total_pixels = total_active_pixels + hblank;
490
491 pixel_freq = total_pixels * hfreq_est / 1000;
492
493
494
495
496
497 hsync = H_SYNC_PERCENT * total_pixels / 100;
498 hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
499 hsync = hsync * GTF_CELL_GRAN;
500
501 hfront_porch = hblank / 2 - hsync;
502
503 vodd_front_porch_lines = GTF_MIN_V_PORCH ;
504
505
506 drm_mode->hdisplay = hdisplay_rnd;
507 drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
508 drm_mode->hsync_end = drm_mode->hsync_start + hsync;
509 drm_mode->htotal = total_pixels;
510 drm_mode->vdisplay = vdisplay_rnd;
511 drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
512 drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
513 drm_mode->vtotal = vtotal_lines;
514
515 drm_mode->clock = pixel_freq;
516
517 if (interlaced) {
518 drm_mode->vtotal *= 2;
519 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
520 }
521
522 drm_mode_set_name(drm_mode);
523 if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
524 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
525 else
526 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
527
528 return drm_mode;
529}
530EXPORT_SYMBOL(drm_gtf_mode_complex);
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566struct drm_display_mode *
567drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
568 bool interlaced, int margins)
569{
570 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
571 interlaced, margins,
572 600, 40 * 2, 128, 20 * 2);
573}
574EXPORT_SYMBOL(drm_gtf_mode);
575
576#ifdef CONFIG_VIDEOMODE_HELPERS
577
578
579
580
581
582
583
584void drm_display_mode_from_videomode(const struct videomode *vm,
585 struct drm_display_mode *dmode)
586{
587 dmode->hdisplay = vm->hactive;
588 dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
589 dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
590 dmode->htotal = dmode->hsync_end + vm->hback_porch;
591
592 dmode->vdisplay = vm->vactive;
593 dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
594 dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
595 dmode->vtotal = dmode->vsync_end + vm->vback_porch;
596
597 dmode->clock = vm->pixelclock / 1000;
598
599 dmode->flags = 0;
600 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
601 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
602 else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
603 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
604 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
605 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
606 else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
607 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
608 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
609 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
610 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
611 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
612 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
613 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
614 drm_mode_set_name(dmode);
615}
616EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
617
618
619
620
621
622
623
624
625void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
626 struct videomode *vm)
627{
628 vm->hactive = dmode->hdisplay;
629 vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
630 vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
631 vm->hback_porch = dmode->htotal - dmode->hsync_end;
632
633 vm->vactive = dmode->vdisplay;
634 vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
635 vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
636 vm->vback_porch = dmode->vtotal - dmode->vsync_end;
637
638 vm->pixelclock = dmode->clock * 1000;
639
640 vm->flags = 0;
641 if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
642 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
643 else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
644 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
645 if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
646 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
647 else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
648 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
649 if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
650 vm->flags |= DISPLAY_FLAGS_INTERLACED;
651 if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
652 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
653 if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
654 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
655}
656EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
657
658
659
660
661
662
663
664
665
666
667void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
668{
669 *bus_flags = 0;
670 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
671 *bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
672 if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
673 *bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
674
675 if (vm->flags & DISPLAY_FLAGS_DE_LOW)
676 *bus_flags |= DRM_BUS_FLAG_DE_LOW;
677 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
678 *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
679}
680EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
681
682#ifdef CONFIG_OF
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697int of_get_drm_display_mode(struct device_node *np,
698 struct drm_display_mode *dmode, u32 *bus_flags,
699 int index)
700{
701 struct videomode vm;
702 int ret;
703
704 ret = of_get_videomode(np, &vm, index);
705 if (ret)
706 return ret;
707
708 drm_display_mode_from_videomode(&vm, dmode);
709 if (bus_flags)
710 drm_bus_flags_from_videomode(&vm, bus_flags);
711
712 pr_debug("%pOF: got %dx%d display mode from %s\n",
713 np, vm.hactive, vm.vactive, np->name);
714 drm_mode_debug_printmodeline(dmode);
715
716 return 0;
717}
718EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
719#endif
720#endif
721
722
723
724
725
726
727
728
729void drm_mode_set_name(struct drm_display_mode *mode)
730{
731 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
732
733 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
734 mode->hdisplay, mode->vdisplay,
735 interlaced ? "i" : "");
736}
737EXPORT_SYMBOL(drm_mode_set_name);
738
739
740
741
742
743
744
745
746
747int drm_mode_hsync(const struct drm_display_mode *mode)
748{
749 unsigned int calc_val;
750
751 if (mode->hsync)
752 return mode->hsync;
753
754 if (mode->htotal < 0)
755 return 0;
756
757 calc_val = (mode->clock * 1000) / mode->htotal;
758 calc_val += 500;
759 calc_val /= 1000;
760
761 return calc_val;
762}
763EXPORT_SYMBOL(drm_mode_hsync);
764
765
766
767
768
769
770
771
772
773int drm_mode_vrefresh(const struct drm_display_mode *mode)
774{
775 int refresh = 0;
776
777 if (mode->vrefresh > 0)
778 refresh = mode->vrefresh;
779 else if (mode->htotal > 0 && mode->vtotal > 0) {
780 unsigned int num, den;
781
782 num = mode->clock * 1000;
783 den = mode->htotal * mode->vtotal;
784
785 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
786 num *= 2;
787 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
788 den *= 2;
789 if (mode->vscan > 1)
790 den *= mode->vscan;
791
792 refresh = DIV_ROUND_CLOSEST(num, den);
793 }
794 return refresh;
795}
796EXPORT_SYMBOL(drm_mode_vrefresh);
797
798
799
800
801
802
803
804
805
806
807void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
808 int *hdisplay, int *vdisplay)
809{
810 struct drm_display_mode adjusted = *mode;
811
812 drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
813 *hdisplay = adjusted.crtc_hdisplay;
814 *vdisplay = adjusted.crtc_vdisplay;
815}
816EXPORT_SYMBOL(drm_mode_get_hv_timing);
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
834{
835 if (!p)
836 return;
837
838 p->crtc_clock = p->clock;
839 p->crtc_hdisplay = p->hdisplay;
840 p->crtc_hsync_start = p->hsync_start;
841 p->crtc_hsync_end = p->hsync_end;
842 p->crtc_htotal = p->htotal;
843 p->crtc_hskew = p->hskew;
844 p->crtc_vdisplay = p->vdisplay;
845 p->crtc_vsync_start = p->vsync_start;
846 p->crtc_vsync_end = p->vsync_end;
847 p->crtc_vtotal = p->vtotal;
848
849 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
850 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
851 p->crtc_vdisplay /= 2;
852 p->crtc_vsync_start /= 2;
853 p->crtc_vsync_end /= 2;
854 p->crtc_vtotal /= 2;
855 }
856 }
857
858 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
859 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
860 p->crtc_vdisplay *= 2;
861 p->crtc_vsync_start *= 2;
862 p->crtc_vsync_end *= 2;
863 p->crtc_vtotal *= 2;
864 }
865 }
866
867 if (!(adjust_flags & CRTC_NO_VSCAN)) {
868 if (p->vscan > 1) {
869 p->crtc_vdisplay *= p->vscan;
870 p->crtc_vsync_start *= p->vscan;
871 p->crtc_vsync_end *= p->vscan;
872 p->crtc_vtotal *= p->vscan;
873 }
874 }
875
876 if (adjust_flags & CRTC_STEREO_DOUBLE) {
877 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
878
879 switch (layout) {
880 case DRM_MODE_FLAG_3D_FRAME_PACKING:
881 p->crtc_clock *= 2;
882 p->crtc_vdisplay += p->crtc_vtotal;
883 p->crtc_vsync_start += p->crtc_vtotal;
884 p->crtc_vsync_end += p->crtc_vtotal;
885 p->crtc_vtotal += p->crtc_vtotal;
886 break;
887 }
888 }
889
890 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
891 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
892 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
893 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
894}
895EXPORT_SYMBOL(drm_mode_set_crtcinfo);
896
897
898
899
900
901
902
903
904
905void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
906{
907 int id = dst->base.id;
908 struct list_head head = dst->head;
909
910 *dst = *src;
911 dst->base.id = id;
912 dst->head = head;
913}
914EXPORT_SYMBOL(drm_mode_copy);
915
916
917
918
919
920
921
922
923
924
925
926
927struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
928 const struct drm_display_mode *mode)
929{
930 struct drm_display_mode *nmode;
931
932 nmode = drm_mode_create(dev);
933 if (!nmode)
934 return NULL;
935
936 drm_mode_copy(nmode, mode);
937
938 return nmode;
939}
940EXPORT_SYMBOL(drm_mode_duplicate);
941
942
943
944
945
946
947
948
949
950
951
952bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
953{
954 if (!mode1 && !mode2)
955 return true;
956
957 if (!mode1 || !mode2)
958 return false;
959
960
961
962 if (mode1->clock && mode2->clock) {
963 if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
964 return false;
965 } else if (mode1->clock != mode2->clock)
966 return false;
967
968 return drm_mode_equal_no_clocks(mode1, mode2);
969}
970EXPORT_SYMBOL(drm_mode_equal);
971
972
973
974
975
976
977
978
979
980
981
982
983bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
984{
985 if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) !=
986 (mode2->flags & DRM_MODE_FLAG_3D_MASK))
987 return false;
988
989 return drm_mode_equal_no_clocks_no_stereo(mode1, mode2);
990}
991EXPORT_SYMBOL(drm_mode_equal_no_clocks);
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
1005 const struct drm_display_mode *mode2)
1006{
1007 if (mode1->hdisplay == mode2->hdisplay &&
1008 mode1->hsync_start == mode2->hsync_start &&
1009 mode1->hsync_end == mode2->hsync_end &&
1010 mode1->htotal == mode2->htotal &&
1011 mode1->hskew == mode2->hskew &&
1012 mode1->vdisplay == mode2->vdisplay &&
1013 mode1->vsync_start == mode2->vsync_start &&
1014 mode1->vsync_end == mode2->vsync_end &&
1015 mode1->vtotal == mode2->vtotal &&
1016 mode1->vscan == mode2->vscan &&
1017 (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
1018 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK))
1019 return true;
1020
1021 return false;
1022}
1023EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1024
1025static enum drm_mode_status
1026drm_mode_validate_basic(const struct drm_display_mode *mode)
1027{
1028 if (mode->type & ~DRM_MODE_TYPE_ALL)
1029 return MODE_BAD;
1030
1031 if (mode->flags & ~DRM_MODE_FLAG_ALL)
1032 return MODE_BAD;
1033
1034 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1035 return MODE_BAD;
1036
1037 if (mode->clock == 0)
1038 return MODE_CLOCK_LOW;
1039
1040 if (mode->hdisplay == 0 ||
1041 mode->hsync_start < mode->hdisplay ||
1042 mode->hsync_end < mode->hsync_start ||
1043 mode->htotal < mode->hsync_end)
1044 return MODE_H_ILLEGAL;
1045
1046 if (mode->vdisplay == 0 ||
1047 mode->vsync_start < mode->vdisplay ||
1048 mode->vsync_end < mode->vsync_start ||
1049 mode->vtotal < mode->vsync_end)
1050 return MODE_V_ILLEGAL;
1051
1052 return MODE_OK;
1053}
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067enum drm_mode_status
1068drm_mode_validate_driver(struct drm_device *dev,
1069 const struct drm_display_mode *mode)
1070{
1071 enum drm_mode_status status;
1072
1073 status = drm_mode_validate_basic(mode);
1074 if (status != MODE_OK)
1075 return status;
1076
1077 if (dev->mode_config.funcs->mode_valid)
1078 return dev->mode_config.funcs->mode_valid(dev, mode);
1079 else
1080 return MODE_OK;
1081}
1082EXPORT_SYMBOL(drm_mode_validate_driver);
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098enum drm_mode_status
1099drm_mode_validate_size(const struct drm_display_mode *mode,
1100 int maxX, int maxY)
1101{
1102 if (maxX > 0 && mode->hdisplay > maxX)
1103 return MODE_VIRTUAL_X;
1104
1105 if (maxY > 0 && mode->vdisplay > maxY)
1106 return MODE_VIRTUAL_Y;
1107
1108 return MODE_OK;
1109}
1110EXPORT_SYMBOL(drm_mode_validate_size);
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123enum drm_mode_status
1124drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
1125 struct drm_connector *connector)
1126{
1127 u8 vic = drm_match_cea_mode(mode);
1128 enum drm_mode_status status = MODE_OK;
1129 struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
1130
1131 if (test_bit(vic, hdmi->y420_vdb_modes)) {
1132 if (!connector->ycbcr_420_allowed)
1133 status = MODE_NO_420;
1134 }
1135
1136 return status;
1137}
1138EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1139
1140#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1141
1142static const char * const drm_mode_status_names[] = {
1143 MODE_STATUS(OK),
1144 MODE_STATUS(HSYNC),
1145 MODE_STATUS(VSYNC),
1146 MODE_STATUS(H_ILLEGAL),
1147 MODE_STATUS(V_ILLEGAL),
1148 MODE_STATUS(BAD_WIDTH),
1149 MODE_STATUS(NOMODE),
1150 MODE_STATUS(NO_INTERLACE),
1151 MODE_STATUS(NO_DBLESCAN),
1152 MODE_STATUS(NO_VSCAN),
1153 MODE_STATUS(MEM),
1154 MODE_STATUS(VIRTUAL_X),
1155 MODE_STATUS(VIRTUAL_Y),
1156 MODE_STATUS(MEM_VIRT),
1157 MODE_STATUS(NOCLOCK),
1158 MODE_STATUS(CLOCK_HIGH),
1159 MODE_STATUS(CLOCK_LOW),
1160 MODE_STATUS(CLOCK_RANGE),
1161 MODE_STATUS(BAD_HVALUE),
1162 MODE_STATUS(BAD_VVALUE),
1163 MODE_STATUS(BAD_VSCAN),
1164 MODE_STATUS(HSYNC_NARROW),
1165 MODE_STATUS(HSYNC_WIDE),
1166 MODE_STATUS(HBLANK_NARROW),
1167 MODE_STATUS(HBLANK_WIDE),
1168 MODE_STATUS(VSYNC_NARROW),
1169 MODE_STATUS(VSYNC_WIDE),
1170 MODE_STATUS(VBLANK_NARROW),
1171 MODE_STATUS(VBLANK_WIDE),
1172 MODE_STATUS(PANEL),
1173 MODE_STATUS(INTERLACE_WIDTH),
1174 MODE_STATUS(ONE_WIDTH),
1175 MODE_STATUS(ONE_HEIGHT),
1176 MODE_STATUS(ONE_SIZE),
1177 MODE_STATUS(NO_REDUCED),
1178 MODE_STATUS(NO_STEREO),
1179 MODE_STATUS(NO_420),
1180 MODE_STATUS(STALE),
1181 MODE_STATUS(BAD),
1182 MODE_STATUS(ERROR),
1183};
1184
1185#undef MODE_STATUS
1186
1187static const char *drm_get_mode_status_name(enum drm_mode_status status)
1188{
1189 int index = status + 3;
1190
1191 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1192 return "";
1193
1194 return drm_mode_status_names[index];
1195}
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208void drm_mode_prune_invalid(struct drm_device *dev,
1209 struct list_head *mode_list, bool verbose)
1210{
1211 struct drm_display_mode *mode, *t;
1212
1213 list_for_each_entry_safe(mode, t, mode_list, head) {
1214 if (mode->status != MODE_OK) {
1215 list_del(&mode->head);
1216 if (verbose) {
1217 drm_mode_debug_printmodeline(mode);
1218 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1219 mode->name,
1220 drm_get_mode_status_name(mode->status));
1221 }
1222 drm_mode_destroy(dev, mode);
1223 }
1224 }
1225}
1226EXPORT_SYMBOL(drm_mode_prune_invalid);
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1242{
1243 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1244 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1245 int diff;
1246
1247 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1248 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1249 if (diff)
1250 return diff;
1251 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1252 if (diff)
1253 return diff;
1254
1255 diff = b->vrefresh - a->vrefresh;
1256 if (diff)
1257 return diff;
1258
1259 diff = b->clock - a->clock;
1260 return diff;
1261}
1262
1263
1264
1265
1266
1267
1268
1269void drm_mode_sort(struct list_head *mode_list)
1270{
1271 list_sort(NULL, mode_list, drm_mode_compare);
1272}
1273EXPORT_SYMBOL(drm_mode_sort);
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286void drm_mode_connector_list_update(struct drm_connector *connector)
1287{
1288 struct drm_display_mode *pmode, *pt;
1289
1290 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1291
1292 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1293 struct drm_display_mode *mode;
1294 bool found_it = false;
1295
1296
1297 list_for_each_entry(mode, &connector->modes, head) {
1298 if (!drm_mode_equal(pmode, mode))
1299 continue;
1300
1301 found_it = true;
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315 if (mode->status == MODE_STALE) {
1316 drm_mode_copy(mode, pmode);
1317 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1318 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1319 pmode->type |= mode->type;
1320 drm_mode_copy(mode, pmode);
1321 } else {
1322 mode->type |= pmode->type;
1323 }
1324
1325 list_del(&pmode->head);
1326 drm_mode_destroy(connector->dev, pmode);
1327 break;
1328 }
1329
1330 if (!found_it) {
1331 list_move_tail(&pmode->head, &connector->modes);
1332 }
1333 }
1334}
1335EXPORT_SYMBOL(drm_mode_connector_list_update);
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1359 struct drm_connector *connector,
1360 struct drm_cmdline_mode *mode)
1361{
1362 const char *name;
1363 unsigned int namelen;
1364 bool res_specified = false, bpp_specified = false, refresh_specified = false;
1365 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1366 bool yres_specified = false, cvt = false, rb = false;
1367 bool interlace = false, margins = false, was_digit = false;
1368 int i;
1369 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1370
1371#ifdef CONFIG_FB
1372 if (!mode_option)
1373 mode_option = fb_mode_option;
1374#endif
1375
1376 if (!mode_option) {
1377 mode->specified = false;
1378 return false;
1379 }
1380
1381 name = mode_option;
1382 namelen = strlen(name);
1383 for (i = namelen-1; i >= 0; i--) {
1384 switch (name[i]) {
1385 case '@':
1386 if (!refresh_specified && !bpp_specified &&
1387 !yres_specified && !cvt && !rb && was_digit) {
1388 refresh = simple_strtol(&name[i+1], NULL, 10);
1389 refresh_specified = true;
1390 was_digit = false;
1391 } else
1392 goto done;
1393 break;
1394 case '-':
1395 if (!bpp_specified && !yres_specified && !cvt &&
1396 !rb && was_digit) {
1397 bpp = simple_strtol(&name[i+1], NULL, 10);
1398 bpp_specified = true;
1399 was_digit = false;
1400 } else
1401 goto done;
1402 break;
1403 case 'x':
1404 if (!yres_specified && was_digit) {
1405 yres = simple_strtol(&name[i+1], NULL, 10);
1406 yres_specified = true;
1407 was_digit = false;
1408 } else
1409 goto done;
1410 break;
1411 case '0' ... '9':
1412 was_digit = true;
1413 break;
1414 case 'M':
1415 if (yres_specified || cvt || was_digit)
1416 goto done;
1417 cvt = true;
1418 break;
1419 case 'R':
1420 if (yres_specified || cvt || rb || was_digit)
1421 goto done;
1422 rb = true;
1423 break;
1424 case 'm':
1425 if (cvt || yres_specified || was_digit)
1426 goto done;
1427 margins = true;
1428 break;
1429 case 'i':
1430 if (cvt || yres_specified || was_digit)
1431 goto done;
1432 interlace = true;
1433 break;
1434 case 'e':
1435 if (yres_specified || bpp_specified || refresh_specified ||
1436 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1437 goto done;
1438
1439 force = DRM_FORCE_ON;
1440 break;
1441 case 'D':
1442 if (yres_specified || bpp_specified || refresh_specified ||
1443 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1444 goto done;
1445
1446 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1447 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1448 force = DRM_FORCE_ON;
1449 else
1450 force = DRM_FORCE_ON_DIGITAL;
1451 break;
1452 case 'd':
1453 if (yres_specified || bpp_specified || refresh_specified ||
1454 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1455 goto done;
1456
1457 force = DRM_FORCE_OFF;
1458 break;
1459 default:
1460 goto done;
1461 }
1462 }
1463
1464 if (i < 0 && yres_specified) {
1465 char *ch;
1466 xres = simple_strtol(name, &ch, 10);
1467 if ((ch != NULL) && (*ch == 'x'))
1468 res_specified = true;
1469 else
1470 i = ch - name;
1471 } else if (!yres_specified && was_digit) {
1472
1473 i = 0;
1474 }
1475done:
1476 if (i >= 0) {
1477 pr_warn("[drm] parse error at position %i in video mode '%s'\n",
1478 i, name);
1479 mode->specified = false;
1480 return false;
1481 }
1482
1483 if (res_specified) {
1484 mode->specified = true;
1485 mode->xres = xres;
1486 mode->yres = yres;
1487 }
1488
1489 if (refresh_specified) {
1490 mode->refresh_specified = true;
1491 mode->refresh = refresh;
1492 }
1493
1494 if (bpp_specified) {
1495 mode->bpp_specified = true;
1496 mode->bpp = bpp;
1497 }
1498 mode->rb = rb;
1499 mode->cvt = cvt;
1500 mode->interlace = interlace;
1501 mode->margins = margins;
1502 mode->force = force;
1503
1504 return true;
1505}
1506EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516struct drm_display_mode *
1517drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1518 struct drm_cmdline_mode *cmd)
1519{
1520 struct drm_display_mode *mode;
1521
1522 if (cmd->cvt)
1523 mode = drm_cvt_mode(dev,
1524 cmd->xres, cmd->yres,
1525 cmd->refresh_specified ? cmd->refresh : 60,
1526 cmd->rb, cmd->interlace,
1527 cmd->margins);
1528 else
1529 mode = drm_gtf_mode(dev,
1530 cmd->xres, cmd->yres,
1531 cmd->refresh_specified ? cmd->refresh : 60,
1532 cmd->interlace,
1533 cmd->margins);
1534 if (!mode)
1535 return NULL;
1536
1537 mode->type |= DRM_MODE_TYPE_USERDEF;
1538
1539 if (cmd->xres == 1366)
1540 drm_mode_fixup_1366x768(mode);
1541 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1542 return mode;
1543}
1544EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1555 const struct drm_display_mode *in)
1556{
1557 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1558 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1559 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1560 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1561 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1562 "timing values too large for mode info\n");
1563
1564 out->clock = in->clock;
1565 out->hdisplay = in->hdisplay;
1566 out->hsync_start = in->hsync_start;
1567 out->hsync_end = in->hsync_end;
1568 out->htotal = in->htotal;
1569 out->hskew = in->hskew;
1570 out->vdisplay = in->vdisplay;
1571 out->vsync_start = in->vsync_start;
1572 out->vsync_end = in->vsync_end;
1573 out->vtotal = in->vtotal;
1574 out->vscan = in->vscan;
1575 out->vrefresh = in->vrefresh;
1576 out->flags = in->flags;
1577 out->type = in->type;
1578 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1579 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1580}
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594int drm_mode_convert_umode(struct drm_device *dev,
1595 struct drm_display_mode *out,
1596 const struct drm_mode_modeinfo *in)
1597{
1598 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1599 return -ERANGE;
1600
1601 out->clock = in->clock;
1602 out->hdisplay = in->hdisplay;
1603 out->hsync_start = in->hsync_start;
1604 out->hsync_end = in->hsync_end;
1605 out->htotal = in->htotal;
1606 out->hskew = in->hskew;
1607 out->vdisplay = in->vdisplay;
1608 out->vsync_start = in->vsync_start;
1609 out->vsync_end = in->vsync_end;
1610 out->vtotal = in->vtotal;
1611 out->vscan = in->vscan;
1612 out->vrefresh = in->vrefresh;
1613 out->flags = in->flags;
1614
1615
1616
1617
1618
1619
1620 out->type = in->type & DRM_MODE_TYPE_ALL;
1621 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1622 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1623
1624 out->status = drm_mode_validate_driver(dev, out);
1625 if (out->status != MODE_OK)
1626 return -EINVAL;
1627
1628 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
1629
1630 return 0;
1631}
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644bool drm_mode_is_420_only(const struct drm_display_info *display,
1645 const struct drm_display_mode *mode)
1646{
1647 u8 vic = drm_match_cea_mode(mode);
1648
1649 return test_bit(vic, display->hdmi.y420_vdb_modes);
1650}
1651EXPORT_SYMBOL(drm_mode_is_420_only);
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664bool drm_mode_is_420_also(const struct drm_display_info *display,
1665 const struct drm_display_mode *mode)
1666{
1667 u8 vic = drm_match_cea_mode(mode);
1668
1669 return test_bit(vic, display->hdmi.y420_cmdb_modes);
1670}
1671EXPORT_SYMBOL(drm_mode_is_420_also);
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683bool drm_mode_is_420(const struct drm_display_info *display,
1684 const struct drm_display_mode *mode)
1685{
1686 return drm_mode_is_420_only(display, mode) ||
1687 drm_mode_is_420_also(display, mode);
1688}
1689EXPORT_SYMBOL(drm_mode_is_420);
1690