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 return nmode;
75}
76EXPORT_SYMBOL(drm_mode_create);
77
78
79
80
81
82
83
84
85void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
86{
87 if (!mode)
88 return;
89
90 kfree(mode);
91}
92EXPORT_SYMBOL(drm_mode_destroy);
93
94
95
96
97
98
99
100
101
102
103void drm_mode_probed_add(struct drm_connector *connector,
104 struct drm_display_mode *mode)
105{
106 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
107
108 list_add_tail(&mode->head, &connector->probed_modes);
109}
110EXPORT_SYMBOL(drm_mode_probed_add);
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
137 int vdisplay, int vrefresh,
138 bool reduced, bool interlaced, bool margins)
139{
140#define HV_FACTOR 1000
141
142#define CVT_MARGIN_PERCENTAGE 18
143
144#define CVT_H_GRANULARITY 8
145
146#define CVT_MIN_V_PORCH 3
147
148#define CVT_MIN_V_BPORCH 6
149
150#define CVT_CLOCK_STEP 250
151 struct drm_display_mode *drm_mode;
152 unsigned int vfieldrate, hperiod;
153 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
154 int interlace;
155 u64 tmp;
156
157
158
159
160 drm_mode = drm_mode_create(dev);
161 if (!drm_mode)
162 return NULL;
163
164
165 if (!vrefresh)
166 vrefresh = 60;
167
168
169 if (interlaced)
170 vfieldrate = vrefresh * 2;
171 else
172 vfieldrate = vrefresh;
173
174
175 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
176
177
178 hmargin = 0;
179 if (margins) {
180 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
181 hmargin -= hmargin % CVT_H_GRANULARITY;
182 }
183
184 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
185
186
187 if (interlaced)
188 vdisplay_rnd = vdisplay / 2;
189 else
190 vdisplay_rnd = vdisplay;
191
192
193 vmargin = 0;
194 if (margins)
195 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
196
197 drm_mode->vdisplay = vdisplay + 2 * vmargin;
198
199
200 if (interlaced)
201 interlace = 1;
202 else
203 interlace = 0;
204
205
206 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
207 vsync = 4;
208 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
209 vsync = 5;
210 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
211 vsync = 6;
212 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
213 vsync = 7;
214 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
215 vsync = 7;
216 else
217 vsync = 10;
218
219 if (!reduced) {
220
221
222
223
224 int tmp1, tmp2;
225#define CVT_MIN_VSYNC_BP 550
226
227#define CVT_HSYNC_PERCENTAGE 8
228 unsigned int hblank_percentage;
229 int vsyncandback_porch, vback_porch, hblank;
230
231
232 tmp1 = HV_FACTOR * 1000000 -
233 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
234 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
235 interlace;
236 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
237
238 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
239
240 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
241 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
242 else
243 vsyncandback_porch = tmp1;
244
245 vback_porch = vsyncandback_porch - vsync;
246 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
247 vsyncandback_porch + CVT_MIN_V_PORCH;
248
249
250#define CVT_M_FACTOR 600
251
252#define CVT_C_FACTOR 40
253
254#define CVT_K_FACTOR 128
255
256#define CVT_J_FACTOR 20
257#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
258#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
259 CVT_J_FACTOR)
260
261 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
262 hperiod / 1000;
263
264 if (hblank_percentage < 20 * HV_FACTOR)
265 hblank_percentage = 20 * HV_FACTOR;
266 hblank = drm_mode->hdisplay * hblank_percentage /
267 (100 * HV_FACTOR - hblank_percentage);
268 hblank -= hblank % (2 * CVT_H_GRANULARITY);
269
270 drm_mode->htotal = drm_mode->hdisplay + hblank;
271 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
272 drm_mode->hsync_start = drm_mode->hsync_end -
273 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
274 drm_mode->hsync_start += CVT_H_GRANULARITY -
275 drm_mode->hsync_start % CVT_H_GRANULARITY;
276
277 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
278 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
279 } else {
280
281
282#define CVT_RB_MIN_VBLANK 460
283
284#define CVT_RB_H_SYNC 32
285
286#define CVT_RB_H_BLANK 160
287
288#define CVT_RB_VFPORCH 3
289 int vbilines;
290 int tmp1, tmp2;
291
292 tmp1 = HV_FACTOR * 1000000 -
293 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
294 tmp2 = vdisplay_rnd + 2 * vmargin;
295 hperiod = tmp1 / (tmp2 * vfieldrate);
296
297 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
298
299 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
300 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
301
302 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
303
304 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
305
306 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
307 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
308
309 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
310 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
311 }
312
313 tmp = drm_mode->htotal;
314 tmp *= HV_FACTOR * 1000;
315 do_div(tmp, hperiod);
316 tmp -= drm_mode->clock % CVT_CLOCK_STEP;
317 drm_mode->clock = tmp;
318
319
320 if (interlaced) {
321 drm_mode->vtotal *= 2;
322 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
323 }
324
325 drm_mode_set_name(drm_mode);
326 if (reduced)
327 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
328 DRM_MODE_FLAG_NVSYNC);
329 else
330 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
331 DRM_MODE_FLAG_NHSYNC);
332
333 return drm_mode;
334}
335EXPORT_SYMBOL(drm_cvt_mode);
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358struct drm_display_mode *
359drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
360 int vrefresh, bool interlaced, int margins,
361 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
362{
363#define GTF_MARGIN_PERCENTAGE 18
364
365#define GTF_CELL_GRAN 8
366
367#define GTF_MIN_V_PORCH 1
368
369#define V_SYNC_RQD 3
370
371#define H_SYNC_PERCENT 8
372
373#define MIN_VSYNC_PLUS_BP 550
374
375#define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
376#define GTF_M_PRIME (GTF_K * GTF_M / 256)
377 struct drm_display_mode *drm_mode;
378 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
379 int top_margin, bottom_margin;
380 int interlace;
381 unsigned int hfreq_est;
382 int vsync_plus_bp, vback_porch;
383 unsigned int vtotal_lines, vfieldrate_est, hperiod;
384 unsigned int vfield_rate, vframe_rate;
385 int left_margin, right_margin;
386 unsigned int total_active_pixels, ideal_duty_cycle;
387 unsigned int hblank, total_pixels, pixel_freq;
388 int hsync, hfront_porch, vodd_front_porch_lines;
389 unsigned int tmp1, tmp2;
390
391 drm_mode = drm_mode_create(dev);
392 if (!drm_mode)
393 return NULL;
394
395
396
397
398
399
400 hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
401 hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
402
403
404
405
406
407 if (interlaced)
408 vdisplay_rnd = vdisplay / 2;
409 else
410 vdisplay_rnd = vdisplay;
411
412
413 if (interlaced)
414 vfieldrate_rqd = vrefresh * 2;
415 else
416 vfieldrate_rqd = vrefresh;
417
418
419 top_margin = 0;
420 if (margins)
421 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
422 1000;
423
424 bottom_margin = top_margin;
425
426
427 if (interlaced)
428 interlace = 1;
429 else
430 interlace = 0;
431
432
433 {
434 tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
435 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
436 2 + interlace;
437 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
438 }
439
440
441
442 vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
443 vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
444
445 vback_porch = vsync_plus_bp - V_SYNC_RQD;
446
447 vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
448 vsync_plus_bp + GTF_MIN_V_PORCH;
449
450 vfieldrate_est = hfreq_est / vtotal_lines;
451
452 hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
453
454
455 vfield_rate = hfreq_est / vtotal_lines;
456
457 if (interlaced)
458 vframe_rate = vfield_rate / 2;
459 else
460 vframe_rate = vfield_rate;
461
462 if (margins)
463 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
464 1000;
465 else
466 left_margin = 0;
467
468
469 right_margin = left_margin;
470
471 total_active_pixels = hdisplay_rnd + left_margin + right_margin;
472
473 ideal_duty_cycle = GTF_C_PRIME * 1000 -
474 (GTF_M_PRIME * 1000000 / hfreq_est);
475
476
477 hblank = total_active_pixels * ideal_duty_cycle /
478 (100000 - ideal_duty_cycle);
479 hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
480 hblank = hblank * 2 * GTF_CELL_GRAN;
481
482 total_pixels = total_active_pixels + hblank;
483
484 pixel_freq = total_pixels * hfreq_est / 1000;
485
486
487
488
489
490 hsync = H_SYNC_PERCENT * total_pixels / 100;
491 hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
492 hsync = hsync * GTF_CELL_GRAN;
493
494 hfront_porch = hblank / 2 - hsync;
495
496 vodd_front_porch_lines = GTF_MIN_V_PORCH ;
497
498
499 drm_mode->hdisplay = hdisplay_rnd;
500 drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
501 drm_mode->hsync_end = drm_mode->hsync_start + hsync;
502 drm_mode->htotal = total_pixels;
503 drm_mode->vdisplay = vdisplay_rnd;
504 drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
505 drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
506 drm_mode->vtotal = vtotal_lines;
507
508 drm_mode->clock = pixel_freq;
509
510 if (interlaced) {
511 drm_mode->vtotal *= 2;
512 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
513 }
514
515 drm_mode_set_name(drm_mode);
516 if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
517 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
518 else
519 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
520
521 return drm_mode;
522}
523EXPORT_SYMBOL(drm_gtf_mode_complex);
524
525
526
527
528
529
530
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
559struct drm_display_mode *
560drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
561 bool interlaced, int margins)
562{
563 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
564 interlaced, margins,
565 600, 40 * 2, 128, 20 * 2);
566}
567EXPORT_SYMBOL(drm_gtf_mode);
568
569#ifdef CONFIG_VIDEOMODE_HELPERS
570
571
572
573
574
575
576
577void drm_display_mode_from_videomode(const struct videomode *vm,
578 struct drm_display_mode *dmode)
579{
580 dmode->hdisplay = vm->hactive;
581 dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
582 dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
583 dmode->htotal = dmode->hsync_end + vm->hback_porch;
584
585 dmode->vdisplay = vm->vactive;
586 dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
587 dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
588 dmode->vtotal = dmode->vsync_end + vm->vback_porch;
589
590 dmode->clock = vm->pixelclock / 1000;
591
592 dmode->flags = 0;
593 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
594 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
595 else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
596 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
597 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
598 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
599 else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
600 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
601 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
602 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
603 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
604 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
605 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
606 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
607 drm_mode_set_name(dmode);
608}
609EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
610
611
612
613
614
615
616
617
618void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
619 struct videomode *vm)
620{
621 vm->hactive = dmode->hdisplay;
622 vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
623 vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
624 vm->hback_porch = dmode->htotal - dmode->hsync_end;
625
626 vm->vactive = dmode->vdisplay;
627 vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
628 vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
629 vm->vback_porch = dmode->vtotal - dmode->vsync_end;
630
631 vm->pixelclock = dmode->clock * 1000;
632
633 vm->flags = 0;
634 if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
635 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
636 else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
637 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
638 if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
639 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
640 else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
641 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
642 if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
643 vm->flags |= DISPLAY_FLAGS_INTERLACED;
644 if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
645 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
646 if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
647 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
648}
649EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
650
651
652
653
654
655
656
657
658
659
660
661
662void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
663{
664 *bus_flags = 0;
665 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
666 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
667 if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
668 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
669
670 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
671 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
672 if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
673 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_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\n",
713 np, vm.hactive, vm.vactive);
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 struct list_head head = dst->head;
908
909 *dst = *src;
910 dst->head = head;
911}
912EXPORT_SYMBOL(drm_mode_copy);
913
914
915
916
917
918
919
920
921
922
923
924
925struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
926 const struct drm_display_mode *mode)
927{
928 struct drm_display_mode *nmode;
929
930 nmode = drm_mode_create(dev);
931 if (!nmode)
932 return NULL;
933
934 drm_mode_copy(nmode, mode);
935
936 return nmode;
937}
938EXPORT_SYMBOL(drm_mode_duplicate);
939
940static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
941 const struct drm_display_mode *mode2)
942{
943 return mode1->hdisplay == mode2->hdisplay &&
944 mode1->hsync_start == mode2->hsync_start &&
945 mode1->hsync_end == mode2->hsync_end &&
946 mode1->htotal == mode2->htotal &&
947 mode1->hskew == mode2->hskew &&
948 mode1->vdisplay == mode2->vdisplay &&
949 mode1->vsync_start == mode2->vsync_start &&
950 mode1->vsync_end == mode2->vsync_end &&
951 mode1->vtotal == mode2->vtotal &&
952 mode1->vscan == mode2->vscan;
953}
954
955static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
956 const struct drm_display_mode *mode2)
957{
958
959
960
961
962 if (mode1->clock && mode2->clock)
963 return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
964 else
965 return mode1->clock == mode2->clock;
966}
967
968static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
969 const struct drm_display_mode *mode2)
970{
971 return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
972 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
973}
974
975static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
976 const struct drm_display_mode *mode2)
977{
978 return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
979 (mode2->flags & DRM_MODE_FLAG_3D_MASK);
980}
981
982static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
983 const struct drm_display_mode *mode2)
984{
985 return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
986}
987
988
989
990
991
992
993
994
995
996
997
998
999bool drm_mode_match(const struct drm_display_mode *mode1,
1000 const struct drm_display_mode *mode2,
1001 unsigned int match_flags)
1002{
1003 if (!mode1 && !mode2)
1004 return true;
1005
1006 if (!mode1 || !mode2)
1007 return false;
1008
1009 if (match_flags & DRM_MODE_MATCH_TIMINGS &&
1010 !drm_mode_match_timings(mode1, mode2))
1011 return false;
1012
1013 if (match_flags & DRM_MODE_MATCH_CLOCK &&
1014 !drm_mode_match_clock(mode1, mode2))
1015 return false;
1016
1017 if (match_flags & DRM_MODE_MATCH_FLAGS &&
1018 !drm_mode_match_flags(mode1, mode2))
1019 return false;
1020
1021 if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
1022 !drm_mode_match_3d_flags(mode1, mode2))
1023 return false;
1024
1025 if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
1026 !drm_mode_match_aspect_ratio(mode1, mode2))
1027 return false;
1028
1029 return true;
1030}
1031EXPORT_SYMBOL(drm_mode_match);
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043bool drm_mode_equal(const struct drm_display_mode *mode1,
1044 const struct drm_display_mode *mode2)
1045{
1046 return drm_mode_match(mode1, mode2,
1047 DRM_MODE_MATCH_TIMINGS |
1048 DRM_MODE_MATCH_CLOCK |
1049 DRM_MODE_MATCH_FLAGS |
1050 DRM_MODE_MATCH_3D_FLAGS|
1051 DRM_MODE_MATCH_ASPECT_RATIO);
1052}
1053EXPORT_SYMBOL(drm_mode_equal);
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
1067 const struct drm_display_mode *mode2)
1068{
1069 return drm_mode_match(mode1, mode2,
1070 DRM_MODE_MATCH_TIMINGS |
1071 DRM_MODE_MATCH_FLAGS |
1072 DRM_MODE_MATCH_3D_FLAGS);
1073}
1074EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
1088 const struct drm_display_mode *mode2)
1089{
1090 return drm_mode_match(mode1, mode2,
1091 DRM_MODE_MATCH_TIMINGS |
1092 DRM_MODE_MATCH_FLAGS);
1093}
1094EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1095
1096static enum drm_mode_status
1097drm_mode_validate_basic(const struct drm_display_mode *mode)
1098{
1099 if (mode->type & ~DRM_MODE_TYPE_ALL)
1100 return MODE_BAD;
1101
1102 if (mode->flags & ~DRM_MODE_FLAG_ALL)
1103 return MODE_BAD;
1104
1105 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1106 return MODE_BAD;
1107
1108 if (mode->clock == 0)
1109 return MODE_CLOCK_LOW;
1110
1111 if (mode->hdisplay == 0 ||
1112 mode->hsync_start < mode->hdisplay ||
1113 mode->hsync_end < mode->hsync_start ||
1114 mode->htotal < mode->hsync_end)
1115 return MODE_H_ILLEGAL;
1116
1117 if (mode->vdisplay == 0 ||
1118 mode->vsync_start < mode->vdisplay ||
1119 mode->vsync_end < mode->vsync_start ||
1120 mode->vtotal < mode->vsync_end)
1121 return MODE_V_ILLEGAL;
1122
1123 return MODE_OK;
1124}
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138enum drm_mode_status
1139drm_mode_validate_driver(struct drm_device *dev,
1140 const struct drm_display_mode *mode)
1141{
1142 enum drm_mode_status status;
1143
1144 status = drm_mode_validate_basic(mode);
1145 if (status != MODE_OK)
1146 return status;
1147
1148 if (dev->mode_config.funcs->mode_valid)
1149 return dev->mode_config.funcs->mode_valid(dev, mode);
1150 else
1151 return MODE_OK;
1152}
1153EXPORT_SYMBOL(drm_mode_validate_driver);
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169enum drm_mode_status
1170drm_mode_validate_size(const struct drm_display_mode *mode,
1171 int maxX, int maxY)
1172{
1173 if (maxX > 0 && mode->hdisplay > maxX)
1174 return MODE_VIRTUAL_X;
1175
1176 if (maxY > 0 && mode->vdisplay > maxY)
1177 return MODE_VIRTUAL_Y;
1178
1179 return MODE_OK;
1180}
1181EXPORT_SYMBOL(drm_mode_validate_size);
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194enum drm_mode_status
1195drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
1196 struct drm_connector *connector)
1197{
1198 u8 vic = drm_match_cea_mode(mode);
1199 enum drm_mode_status status = MODE_OK;
1200 struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
1201
1202 if (test_bit(vic, hdmi->y420_vdb_modes)) {
1203 if (!connector->ycbcr_420_allowed)
1204 status = MODE_NO_420;
1205 }
1206
1207 return status;
1208}
1209EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1210
1211#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1212
1213static const char * const drm_mode_status_names[] = {
1214 MODE_STATUS(OK),
1215 MODE_STATUS(HSYNC),
1216 MODE_STATUS(VSYNC),
1217 MODE_STATUS(H_ILLEGAL),
1218 MODE_STATUS(V_ILLEGAL),
1219 MODE_STATUS(BAD_WIDTH),
1220 MODE_STATUS(NOMODE),
1221 MODE_STATUS(NO_INTERLACE),
1222 MODE_STATUS(NO_DBLESCAN),
1223 MODE_STATUS(NO_VSCAN),
1224 MODE_STATUS(MEM),
1225 MODE_STATUS(VIRTUAL_X),
1226 MODE_STATUS(VIRTUAL_Y),
1227 MODE_STATUS(MEM_VIRT),
1228 MODE_STATUS(NOCLOCK),
1229 MODE_STATUS(CLOCK_HIGH),
1230 MODE_STATUS(CLOCK_LOW),
1231 MODE_STATUS(CLOCK_RANGE),
1232 MODE_STATUS(BAD_HVALUE),
1233 MODE_STATUS(BAD_VVALUE),
1234 MODE_STATUS(BAD_VSCAN),
1235 MODE_STATUS(HSYNC_NARROW),
1236 MODE_STATUS(HSYNC_WIDE),
1237 MODE_STATUS(HBLANK_NARROW),
1238 MODE_STATUS(HBLANK_WIDE),
1239 MODE_STATUS(VSYNC_NARROW),
1240 MODE_STATUS(VSYNC_WIDE),
1241 MODE_STATUS(VBLANK_NARROW),
1242 MODE_STATUS(VBLANK_WIDE),
1243 MODE_STATUS(PANEL),
1244 MODE_STATUS(INTERLACE_WIDTH),
1245 MODE_STATUS(ONE_WIDTH),
1246 MODE_STATUS(ONE_HEIGHT),
1247 MODE_STATUS(ONE_SIZE),
1248 MODE_STATUS(NO_REDUCED),
1249 MODE_STATUS(NO_STEREO),
1250 MODE_STATUS(NO_420),
1251 MODE_STATUS(STALE),
1252 MODE_STATUS(BAD),
1253 MODE_STATUS(ERROR),
1254};
1255
1256#undef MODE_STATUS
1257
1258const char *drm_get_mode_status_name(enum drm_mode_status status)
1259{
1260 int index = status + 3;
1261
1262 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1263 return "";
1264
1265 return drm_mode_status_names[index];
1266}
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279void drm_mode_prune_invalid(struct drm_device *dev,
1280 struct list_head *mode_list, bool verbose)
1281{
1282 struct drm_display_mode *mode, *t;
1283
1284 list_for_each_entry_safe(mode, t, mode_list, head) {
1285 if (mode->status != MODE_OK) {
1286 list_del(&mode->head);
1287 if (verbose) {
1288 drm_mode_debug_printmodeline(mode);
1289 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1290 mode->name,
1291 drm_get_mode_status_name(mode->status));
1292 }
1293 drm_mode_destroy(dev, mode);
1294 }
1295 }
1296}
1297EXPORT_SYMBOL(drm_mode_prune_invalid);
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1313{
1314 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1315 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1316 int diff;
1317
1318 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1319 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1320 if (diff)
1321 return diff;
1322 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1323 if (diff)
1324 return diff;
1325
1326 diff = b->vrefresh - a->vrefresh;
1327 if (diff)
1328 return diff;
1329
1330 diff = b->clock - a->clock;
1331 return diff;
1332}
1333
1334
1335
1336
1337
1338
1339
1340void drm_mode_sort(struct list_head *mode_list)
1341{
1342 list_sort(NULL, mode_list, drm_mode_compare);
1343}
1344EXPORT_SYMBOL(drm_mode_sort);
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357void drm_connector_list_update(struct drm_connector *connector)
1358{
1359 struct drm_display_mode *pmode, *pt;
1360
1361 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1362
1363 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1364 struct drm_display_mode *mode;
1365 bool found_it = false;
1366
1367
1368 list_for_each_entry(mode, &connector->modes, head) {
1369 if (!drm_mode_equal(pmode, mode))
1370 continue;
1371
1372 found_it = true;
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386 if (mode->status == MODE_STALE) {
1387 drm_mode_copy(mode, pmode);
1388 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1389 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1390 pmode->type |= mode->type;
1391 drm_mode_copy(mode, pmode);
1392 } else {
1393 mode->type |= pmode->type;
1394 }
1395
1396 list_del(&pmode->head);
1397 drm_mode_destroy(connector->dev, pmode);
1398 break;
1399 }
1400
1401 if (!found_it) {
1402 list_move_tail(&pmode->head, &connector->modes);
1403 }
1404 }
1405}
1406EXPORT_SYMBOL(drm_connector_list_update);
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1430 struct drm_connector *connector,
1431 struct drm_cmdline_mode *mode)
1432{
1433 const char *name;
1434 unsigned int namelen;
1435 bool res_specified = false, bpp_specified = false, refresh_specified = false;
1436 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1437 bool yres_specified = false, cvt = false, rb = false;
1438 bool interlace = false, margins = false, was_digit = false;
1439 int i;
1440 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1441
1442#ifdef CONFIG_FB
1443 if (!mode_option)
1444 mode_option = fb_mode_option;
1445#endif
1446
1447 if (!mode_option) {
1448 mode->specified = false;
1449 return false;
1450 }
1451
1452 name = mode_option;
1453 namelen = strlen(name);
1454 for (i = namelen-1; i >= 0; i--) {
1455 switch (name[i]) {
1456 case '@':
1457 if (!refresh_specified && !bpp_specified &&
1458 !yres_specified && !cvt && !rb && was_digit) {
1459 refresh = simple_strtol(&name[i+1], NULL, 10);
1460 refresh_specified = true;
1461 was_digit = false;
1462 } else
1463 goto done;
1464 break;
1465 case '-':
1466 if (!bpp_specified && !yres_specified && !cvt &&
1467 !rb && was_digit) {
1468 bpp = simple_strtol(&name[i+1], NULL, 10);
1469 bpp_specified = true;
1470 was_digit = false;
1471 } else
1472 goto done;
1473 break;
1474 case 'x':
1475 if (!yres_specified && was_digit) {
1476 yres = simple_strtol(&name[i+1], NULL, 10);
1477 yres_specified = true;
1478 was_digit = false;
1479 } else
1480 goto done;
1481 break;
1482 case '0' ... '9':
1483 was_digit = true;
1484 break;
1485 case 'M':
1486 if (yres_specified || cvt || was_digit)
1487 goto done;
1488 cvt = true;
1489 break;
1490 case 'R':
1491 if (yres_specified || cvt || rb || was_digit)
1492 goto done;
1493 rb = true;
1494 break;
1495 case 'm':
1496 if (cvt || yres_specified || was_digit)
1497 goto done;
1498 margins = true;
1499 break;
1500 case 'i':
1501 if (cvt || yres_specified || was_digit)
1502 goto done;
1503 interlace = true;
1504 break;
1505 case 'e':
1506 if (yres_specified || bpp_specified || refresh_specified ||
1507 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1508 goto done;
1509
1510 force = DRM_FORCE_ON;
1511 break;
1512 case 'D':
1513 if (yres_specified || bpp_specified || refresh_specified ||
1514 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1515 goto done;
1516
1517 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1518 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1519 force = DRM_FORCE_ON;
1520 else
1521 force = DRM_FORCE_ON_DIGITAL;
1522 break;
1523 case 'd':
1524 if (yres_specified || bpp_specified || refresh_specified ||
1525 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1526 goto done;
1527
1528 force = DRM_FORCE_OFF;
1529 break;
1530 default:
1531 goto done;
1532 }
1533 }
1534
1535 if (i < 0 && yres_specified) {
1536 char *ch;
1537 xres = simple_strtol(name, &ch, 10);
1538 if ((ch != NULL) && (*ch == 'x'))
1539 res_specified = true;
1540 else
1541 i = ch - name;
1542 } else if (!yres_specified && was_digit) {
1543
1544 i = 0;
1545 }
1546done:
1547 if (i >= 0) {
1548 pr_warn("[drm] parse error at position %i in video mode '%s'\n",
1549 i, name);
1550 mode->specified = false;
1551 return false;
1552 }
1553
1554 if (res_specified) {
1555 mode->specified = true;
1556 mode->xres = xres;
1557 mode->yres = yres;
1558 }
1559
1560 if (refresh_specified) {
1561 mode->refresh_specified = true;
1562 mode->refresh = refresh;
1563 }
1564
1565 if (bpp_specified) {
1566 mode->bpp_specified = true;
1567 mode->bpp = bpp;
1568 }
1569 mode->rb = rb;
1570 mode->cvt = cvt;
1571 mode->interlace = interlace;
1572 mode->margins = margins;
1573 mode->force = force;
1574
1575 return true;
1576}
1577EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587struct drm_display_mode *
1588drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1589 struct drm_cmdline_mode *cmd)
1590{
1591 struct drm_display_mode *mode;
1592
1593 if (cmd->cvt)
1594 mode = drm_cvt_mode(dev,
1595 cmd->xres, cmd->yres,
1596 cmd->refresh_specified ? cmd->refresh : 60,
1597 cmd->rb, cmd->interlace,
1598 cmd->margins);
1599 else
1600 mode = drm_gtf_mode(dev,
1601 cmd->xres, cmd->yres,
1602 cmd->refresh_specified ? cmd->refresh : 60,
1603 cmd->interlace,
1604 cmd->margins);
1605 if (!mode)
1606 return NULL;
1607
1608 mode->type |= DRM_MODE_TYPE_USERDEF;
1609
1610 if (cmd->xres == 1366)
1611 drm_mode_fixup_1366x768(mode);
1612 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1613 return mode;
1614}
1615EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1626 const struct drm_display_mode *in)
1627{
1628 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1629 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1630 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1631 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1632 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1633 "timing values too large for mode info\n");
1634
1635 out->clock = in->clock;
1636 out->hdisplay = in->hdisplay;
1637 out->hsync_start = in->hsync_start;
1638 out->hsync_end = in->hsync_end;
1639 out->htotal = in->htotal;
1640 out->hskew = in->hskew;
1641 out->vdisplay = in->vdisplay;
1642 out->vsync_start = in->vsync_start;
1643 out->vsync_end = in->vsync_end;
1644 out->vtotal = in->vtotal;
1645 out->vscan = in->vscan;
1646 out->vrefresh = in->vrefresh;
1647 out->flags = in->flags;
1648 out->type = in->type;
1649
1650 switch (in->picture_aspect_ratio) {
1651 case HDMI_PICTURE_ASPECT_4_3:
1652 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
1653 break;
1654 case HDMI_PICTURE_ASPECT_16_9:
1655 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
1656 break;
1657 case HDMI_PICTURE_ASPECT_64_27:
1658 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
1659 break;
1660 case HDMI_PICTURE_ASPECT_256_135:
1661 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
1662 break;
1663 case HDMI_PICTURE_ASPECT_RESERVED:
1664 default:
1665 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
1666 break;
1667 }
1668
1669 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1670 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1671}
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685int drm_mode_convert_umode(struct drm_device *dev,
1686 struct drm_display_mode *out,
1687 const struct drm_mode_modeinfo *in)
1688{
1689 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1690 return -ERANGE;
1691
1692 out->clock = in->clock;
1693 out->hdisplay = in->hdisplay;
1694 out->hsync_start = in->hsync_start;
1695 out->hsync_end = in->hsync_end;
1696 out->htotal = in->htotal;
1697 out->hskew = in->hskew;
1698 out->vdisplay = in->vdisplay;
1699 out->vsync_start = in->vsync_start;
1700 out->vsync_end = in->vsync_end;
1701 out->vtotal = in->vtotal;
1702 out->vscan = in->vscan;
1703 out->vrefresh = in->vrefresh;
1704 out->flags = in->flags;
1705
1706
1707
1708
1709
1710
1711 out->type = in->type & DRM_MODE_TYPE_ALL;
1712 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1713 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1714
1715
1716
1717
1718
1719 out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
1720
1721 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
1722 case DRM_MODE_FLAG_PIC_AR_4_3:
1723 out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_4_3;
1724 break;
1725 case DRM_MODE_FLAG_PIC_AR_16_9:
1726 out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_16_9;
1727 break;
1728 case DRM_MODE_FLAG_PIC_AR_64_27:
1729 out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_64_27;
1730 break;
1731 case DRM_MODE_FLAG_PIC_AR_256_135:
1732 out->picture_aspect_ratio |= HDMI_PICTURE_ASPECT_256_135;
1733 break;
1734 default:
1735 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
1736 break;
1737 }
1738
1739 out->status = drm_mode_validate_driver(dev, out);
1740 if (out->status != MODE_OK)
1741 return -EINVAL;
1742
1743 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
1744
1745 return 0;
1746}
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759bool drm_mode_is_420_only(const struct drm_display_info *display,
1760 const struct drm_display_mode *mode)
1761{
1762 u8 vic = drm_match_cea_mode(mode);
1763
1764 return test_bit(vic, display->hdmi.y420_vdb_modes);
1765}
1766EXPORT_SYMBOL(drm_mode_is_420_only);
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779bool drm_mode_is_420_also(const struct drm_display_info *display,
1780 const struct drm_display_mode *mode)
1781{
1782 u8 vic = drm_match_cea_mode(mode);
1783
1784 return test_bit(vic, display->hdmi.y420_cmdb_modes);
1785}
1786EXPORT_SYMBOL(drm_mode_is_420_also);
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798bool drm_mode_is_420(const struct drm_display_info *display,
1799 const struct drm_display_mode *mode)
1800{
1801 return drm_mode_is_420_only(display, mode) ||
1802 drm_mode_is_420_also(display, mode);
1803}
1804EXPORT_SYMBOL(drm_mode_is_420);
1805