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
41
42
43
44
45
46
47
48
49
50
51void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
52{
53 DRM_DEBUG_KMS("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d "
54 "0x%x 0x%x\n",
55 mode->base.id, mode->name, mode->vrefresh, mode->clock,
56 mode->hdisplay, mode->hsync_start,
57 mode->hsync_end, mode->htotal,
58 mode->vdisplay, mode->vsync_start,
59 mode->vsync_end, mode->vtotal, mode->type, mode->flags);
60}
61EXPORT_SYMBOL(drm_mode_debug_printmodeline);
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86#define HV_FACTOR 1000
87struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
88 int vdisplay, int vrefresh,
89 bool reduced, bool interlaced, bool margins)
90{
91
92#define CVT_MARGIN_PERCENTAGE 18
93
94#define CVT_H_GRANULARITY 8
95
96#define CVT_MIN_V_PORCH 3
97
98#define CVT_MIN_V_BPORCH 6
99
100#define CVT_CLOCK_STEP 250
101 struct drm_display_mode *drm_mode;
102 unsigned int vfieldrate, hperiod;
103 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
104 int interlace;
105
106
107
108
109 drm_mode = drm_mode_create(dev);
110 if (!drm_mode)
111 return NULL;
112
113
114 if (!vrefresh)
115 vrefresh = 60;
116
117
118 if (interlaced)
119 vfieldrate = vrefresh * 2;
120 else
121 vfieldrate = vrefresh;
122
123
124 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
125
126
127 hmargin = 0;
128 if (margins) {
129 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
130 hmargin -= hmargin % CVT_H_GRANULARITY;
131 }
132
133 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
134
135
136 if (interlaced)
137 vdisplay_rnd = vdisplay / 2;
138 else
139 vdisplay_rnd = vdisplay;
140
141
142 vmargin = 0;
143 if (margins)
144 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
145
146 drm_mode->vdisplay = vdisplay + 2 * vmargin;
147
148
149 if (interlaced)
150 interlace = 1;
151 else
152 interlace = 0;
153
154
155 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
156 vsync = 4;
157 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
158 vsync = 5;
159 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
160 vsync = 6;
161 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
162 vsync = 7;
163 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
164 vsync = 7;
165 else
166 vsync = 10;
167
168 if (!reduced) {
169
170
171
172
173 int tmp1, tmp2;
174#define CVT_MIN_VSYNC_BP 550
175
176#define CVT_HSYNC_PERCENTAGE 8
177 unsigned int hblank_percentage;
178 int vsyncandback_porch, vback_porch, hblank;
179
180
181 tmp1 = HV_FACTOR * 1000000 -
182 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
183 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
184 interlace;
185 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
186
187 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
188
189 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
190 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
191 else
192 vsyncandback_porch = tmp1;
193
194 vback_porch = vsyncandback_porch - vsync;
195 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
196 vsyncandback_porch + CVT_MIN_V_PORCH;
197
198
199#define CVT_M_FACTOR 600
200
201#define CVT_C_FACTOR 40
202
203#define CVT_K_FACTOR 128
204
205#define CVT_J_FACTOR 20
206#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
207#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
208 CVT_J_FACTOR)
209
210 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
211 hperiod / 1000;
212
213 if (hblank_percentage < 20 * HV_FACTOR)
214 hblank_percentage = 20 * HV_FACTOR;
215 hblank = drm_mode->hdisplay * hblank_percentage /
216 (100 * HV_FACTOR - hblank_percentage);
217 hblank -= hblank % (2 * CVT_H_GRANULARITY);
218
219 drm_mode->htotal = drm_mode->hdisplay + hblank;
220 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
221 drm_mode->hsync_start = drm_mode->hsync_end -
222 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
223 drm_mode->hsync_start += CVT_H_GRANULARITY -
224 drm_mode->hsync_start % CVT_H_GRANULARITY;
225
226 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
227 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
228 } else {
229
230
231#define CVT_RB_MIN_VBLANK 460
232
233#define CVT_RB_H_SYNC 32
234
235#define CVT_RB_H_BLANK 160
236
237#define CVT_RB_VFPORCH 3
238 int vbilines;
239 int tmp1, tmp2;
240
241 tmp1 = HV_FACTOR * 1000000 -
242 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
243 tmp2 = vdisplay_rnd + 2 * vmargin;
244 hperiod = tmp1 / (tmp2 * vfieldrate);
245
246 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
247
248 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
249 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
250
251 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
252
253 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
254
255 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
256 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
257
258 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
259 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
260 }
261
262 drm_mode->clock = drm_mode->htotal * HV_FACTOR * 1000 / hperiod;
263 drm_mode->clock -= drm_mode->clock % CVT_CLOCK_STEP;
264
265
266 if (interlaced) {
267 drm_mode->vtotal *= 2;
268 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
269 }
270
271 drm_mode_set_name(drm_mode);
272 if (reduced)
273 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
274 DRM_MODE_FLAG_NVSYNC);
275 else
276 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
277 DRM_MODE_FLAG_NHSYNC);
278
279 return drm_mode;
280}
281EXPORT_SYMBOL(drm_cvt_mode);
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302struct drm_display_mode *
303drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
304 int vrefresh, bool interlaced, int margins,
305 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
306{
307#define GTF_MARGIN_PERCENTAGE 18
308
309#define GTF_CELL_GRAN 8
310
311#define GTF_MIN_V_PORCH 1
312
313#define V_SYNC_RQD 3
314
315#define H_SYNC_PERCENT 8
316
317#define MIN_VSYNC_PLUS_BP 550
318
319#define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
320#define GTF_M_PRIME (GTF_K * GTF_M / 256)
321 struct drm_display_mode *drm_mode;
322 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
323 int top_margin, bottom_margin;
324 int interlace;
325 unsigned int hfreq_est;
326 int vsync_plus_bp, vback_porch;
327 unsigned int vtotal_lines, vfieldrate_est, hperiod;
328 unsigned int vfield_rate, vframe_rate;
329 int left_margin, right_margin;
330 unsigned int total_active_pixels, ideal_duty_cycle;
331 unsigned int hblank, total_pixels, pixel_freq;
332 int hsync, hfront_porch, vodd_front_porch_lines;
333 unsigned int tmp1, tmp2;
334
335 drm_mode = drm_mode_create(dev);
336 if (!drm_mode)
337 return NULL;
338
339
340
341
342
343
344 hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
345 hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
346
347
348
349
350
351 if (interlaced)
352 vdisplay_rnd = vdisplay / 2;
353 else
354 vdisplay_rnd = vdisplay;
355
356
357 if (interlaced)
358 vfieldrate_rqd = vrefresh * 2;
359 else
360 vfieldrate_rqd = vrefresh;
361
362
363 top_margin = 0;
364 if (margins)
365 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
366 1000;
367
368 bottom_margin = top_margin;
369
370
371 if (interlaced)
372 interlace = 1;
373 else
374 interlace = 0;
375
376
377 {
378 tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
379 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
380 2 + interlace;
381 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
382 }
383
384
385
386 vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
387 vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
388
389 vback_porch = vsync_plus_bp - V_SYNC_RQD;
390
391 vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
392 vsync_plus_bp + GTF_MIN_V_PORCH;
393
394 vfieldrate_est = hfreq_est / vtotal_lines;
395
396 hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
397
398
399 vfield_rate = hfreq_est / vtotal_lines;
400
401 if (interlaced)
402 vframe_rate = vfield_rate / 2;
403 else
404 vframe_rate = vfield_rate;
405
406 if (margins)
407 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
408 1000;
409 else
410 left_margin = 0;
411
412
413 right_margin = left_margin;
414
415 total_active_pixels = hdisplay_rnd + left_margin + right_margin;
416
417 ideal_duty_cycle = GTF_C_PRIME * 1000 -
418 (GTF_M_PRIME * 1000000 / hfreq_est);
419
420
421 hblank = total_active_pixels * ideal_duty_cycle /
422 (100000 - ideal_duty_cycle);
423 hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
424 hblank = hblank * 2 * GTF_CELL_GRAN;
425
426 total_pixels = total_active_pixels + hblank;
427
428 pixel_freq = total_pixels * hfreq_est / 1000;
429
430
431
432
433
434 hsync = H_SYNC_PERCENT * total_pixels / 100;
435 hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
436 hsync = hsync * GTF_CELL_GRAN;
437
438 hfront_porch = hblank / 2 - hsync;
439
440 vodd_front_porch_lines = GTF_MIN_V_PORCH ;
441
442
443 drm_mode->hdisplay = hdisplay_rnd;
444 drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
445 drm_mode->hsync_end = drm_mode->hsync_start + hsync;
446 drm_mode->htotal = total_pixels;
447 drm_mode->vdisplay = vdisplay_rnd;
448 drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
449 drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
450 drm_mode->vtotal = vtotal_lines;
451
452 drm_mode->clock = pixel_freq;
453
454 if (interlaced) {
455 drm_mode->vtotal *= 2;
456 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
457 }
458
459 drm_mode_set_name(drm_mode);
460 if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
461 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
462 else
463 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
464
465 return drm_mode;
466}
467EXPORT_SYMBOL(drm_gtf_mode_complex);
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500struct drm_display_mode *
501drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
502 bool lace, int margins)
503{
504 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh, lace,
505 margins, 600, 40 * 2, 128, 20 * 2);
506}
507EXPORT_SYMBOL(drm_gtf_mode);
508
509#ifdef CONFIG_VIDEOMODE_HELPERS
510int drm_display_mode_from_videomode(const struct videomode *vm,
511 struct drm_display_mode *dmode)
512{
513 dmode->hdisplay = vm->hactive;
514 dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
515 dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
516 dmode->htotal = dmode->hsync_end + vm->hback_porch;
517
518 dmode->vdisplay = vm->vactive;
519 dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
520 dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
521 dmode->vtotal = dmode->vsync_end + vm->vback_porch;
522
523 dmode->clock = vm->pixelclock / 1000;
524
525 dmode->flags = 0;
526 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
527 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
528 else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
529 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
530 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
531 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
532 else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
533 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
534 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
535 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
536 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
537 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
538 drm_mode_set_name(dmode);
539
540 return 0;
541}
542EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
543
544#ifdef CONFIG_OF
545
546
547
548
549
550
551
552
553
554
555int of_get_drm_display_mode(struct device_node *np,
556 struct drm_display_mode *dmode, int index)
557{
558 struct videomode vm;
559 int ret;
560
561 ret = of_get_videomode(np, &vm, index);
562 if (ret)
563 return ret;
564
565 drm_display_mode_from_videomode(&vm, dmode);
566
567 pr_debug("%s: got %dx%d display mode from %s\n",
568 of_node_full_name(np), vm.hactive, vm.vactive, np->name);
569 drm_mode_debug_printmodeline(dmode);
570
571 return 0;
572}
573EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
574#endif
575#endif
576
577
578
579
580
581
582
583
584
585
586void drm_mode_set_name(struct drm_display_mode *mode)
587{
588 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
589
590 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
591 mode->hdisplay, mode->vdisplay,
592 interlaced ? "i" : "");
593}
594EXPORT_SYMBOL(drm_mode_set_name);
595
596
597
598
599
600
601
602
603
604
605
606void drm_mode_list_concat(struct list_head *head, struct list_head *new)
607{
608
609 struct list_head *entry, *tmp;
610
611 list_for_each_safe(entry, tmp, head) {
612 list_move_tail(entry, new);
613 }
614}
615EXPORT_SYMBOL(drm_mode_list_concat);
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631int drm_mode_width(const struct drm_display_mode *mode)
632{
633 return mode->hdisplay;
634
635}
636EXPORT_SYMBOL(drm_mode_width);
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652int drm_mode_height(const struct drm_display_mode *mode)
653{
654 return mode->vdisplay;
655}
656EXPORT_SYMBOL(drm_mode_height);
657
658
659
660
661
662
663
664
665
666int drm_mode_hsync(const struct drm_display_mode *mode)
667{
668 unsigned int calc_val;
669
670 if (mode->hsync)
671 return mode->hsync;
672
673 if (mode->htotal < 0)
674 return 0;
675
676 calc_val = (mode->clock * 1000) / mode->htotal;
677 calc_val += 500;
678 calc_val /= 1000;
679
680 return calc_val;
681}
682EXPORT_SYMBOL(drm_mode_hsync);
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700int drm_mode_vrefresh(const struct drm_display_mode *mode)
701{
702 int refresh = 0;
703 unsigned int calc_val;
704
705 if (mode->vrefresh > 0)
706 refresh = mode->vrefresh;
707 else if (mode->htotal > 0 && mode->vtotal > 0) {
708 int vtotal;
709 vtotal = mode->vtotal;
710
711 calc_val = (mode->clock * 1000);
712 calc_val /= mode->htotal;
713 refresh = (calc_val + vtotal / 2) / vtotal;
714
715 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
716 refresh *= 2;
717 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
718 refresh /= 2;
719 if (mode->vscan > 1)
720 refresh /= mode->vscan;
721 }
722 return refresh;
723}
724EXPORT_SYMBOL(drm_mode_vrefresh);
725
726
727
728
729
730
731
732
733
734
735
736void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
737{
738 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
739 return;
740
741 p->crtc_hdisplay = p->hdisplay;
742 p->crtc_hsync_start = p->hsync_start;
743 p->crtc_hsync_end = p->hsync_end;
744 p->crtc_htotal = p->htotal;
745 p->crtc_hskew = p->hskew;
746 p->crtc_vdisplay = p->vdisplay;
747 p->crtc_vsync_start = p->vsync_start;
748 p->crtc_vsync_end = p->vsync_end;
749 p->crtc_vtotal = p->vtotal;
750
751 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
752 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
753 p->crtc_vdisplay /= 2;
754 p->crtc_vsync_start /= 2;
755 p->crtc_vsync_end /= 2;
756 p->crtc_vtotal /= 2;
757 }
758 }
759
760 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
761 p->crtc_vdisplay *= 2;
762 p->crtc_vsync_start *= 2;
763 p->crtc_vsync_end *= 2;
764 p->crtc_vtotal *= 2;
765 }
766
767 if (p->vscan > 1) {
768 p->crtc_vdisplay *= p->vscan;
769 p->crtc_vsync_start *= p->vscan;
770 p->crtc_vsync_end *= p->vscan;
771 p->crtc_vtotal *= p->vscan;
772 }
773
774 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
775 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
776 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
777 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
778}
779EXPORT_SYMBOL(drm_mode_set_crtcinfo);
780
781
782
783
784
785
786
787
788
789
790
791
792
793void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
794{
795 int id = dst->base.id;
796
797 *dst = *src;
798 dst->base.id = id;
799 INIT_LIST_HEAD(&dst->head);
800}
801EXPORT_SYMBOL(drm_mode_copy);
802
803
804
805
806
807
808
809
810
811
812
813struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
814 const struct drm_display_mode *mode)
815{
816 struct drm_display_mode *nmode;
817
818 nmode = drm_mode_create(dev);
819 if (!nmode)
820 return NULL;
821
822 drm_mode_copy(nmode, mode);
823
824 return nmode;
825}
826EXPORT_SYMBOL(drm_mode_duplicate);
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
842{
843
844
845 if (mode1->clock && mode2->clock) {
846 if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
847 return false;
848 } else if (mode1->clock != mode2->clock)
849 return false;
850
851 return drm_mode_equal_no_clocks(mode1, mode2);
852}
853EXPORT_SYMBOL(drm_mode_equal);
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
870{
871 if (mode1->hdisplay == mode2->hdisplay &&
872 mode1->hsync_start == mode2->hsync_start &&
873 mode1->hsync_end == mode2->hsync_end &&
874 mode1->htotal == mode2->htotal &&
875 mode1->hskew == mode2->hskew &&
876 mode1->vdisplay == mode2->vdisplay &&
877 mode1->vsync_start == mode2->vsync_start &&
878 mode1->vsync_end == mode2->vsync_end &&
879 mode1->vtotal == mode2->vtotal &&
880 mode1->vscan == mode2->vscan &&
881 mode1->flags == mode2->flags)
882 return true;
883
884 return false;
885}
886EXPORT_SYMBOL(drm_mode_equal_no_clocks);
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903void drm_mode_validate_size(struct drm_device *dev,
904 struct list_head *mode_list,
905 int maxX, int maxY, int maxPitch)
906{
907 struct drm_display_mode *mode;
908
909 list_for_each_entry(mode, mode_list, head) {
910 if (maxPitch > 0 && mode->hdisplay > maxPitch)
911 mode->status = MODE_BAD_WIDTH;
912
913 if (maxX > 0 && mode->hdisplay > maxX)
914 mode->status = MODE_VIRTUAL_X;
915
916 if (maxY > 0 && mode->vdisplay > maxY)
917 mode->status = MODE_VIRTUAL_Y;
918 }
919}
920EXPORT_SYMBOL(drm_mode_validate_size);
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938void drm_mode_validate_clocks(struct drm_device *dev,
939 struct list_head *mode_list,
940 int *min, int *max, int n_ranges)
941{
942 struct drm_display_mode *mode;
943 int i;
944
945 list_for_each_entry(mode, mode_list, head) {
946 bool good = false;
947 for (i = 0; i < n_ranges; i++) {
948 if (mode->clock >= min[i] && mode->clock <= max[i]) {
949 good = true;
950 break;
951 }
952 }
953 if (!good)
954 mode->status = MODE_CLOCK_RANGE;
955 }
956}
957EXPORT_SYMBOL(drm_mode_validate_clocks);
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972void drm_mode_prune_invalid(struct drm_device *dev,
973 struct list_head *mode_list, bool verbose)
974{
975 struct drm_display_mode *mode, *t;
976
977 list_for_each_entry_safe(mode, t, mode_list, head) {
978 if (mode->status != MODE_OK) {
979 list_del(&mode->head);
980 if (verbose) {
981 drm_mode_debug_printmodeline(mode);
982 DRM_DEBUG_KMS("Not using %s mode %d\n",
983 mode->name, mode->status);
984 }
985 drm_mode_destroy(dev, mode);
986 }
987 }
988}
989EXPORT_SYMBOL(drm_mode_prune_invalid);
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1008{
1009 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1010 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1011 int diff;
1012
1013 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1014 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1015 if (diff)
1016 return diff;
1017 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1018 if (diff)
1019 return diff;
1020 diff = b->clock - a->clock;
1021 return diff;
1022}
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033void drm_mode_sort(struct list_head *mode_list)
1034{
1035 list_sort(NULL, mode_list, drm_mode_compare);
1036}
1037EXPORT_SYMBOL(drm_mode_sort);
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051void drm_mode_connector_list_update(struct drm_connector *connector)
1052{
1053 struct drm_display_mode *mode;
1054 struct drm_display_mode *pmode, *pt;
1055 int found_it;
1056
1057 list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
1058 head) {
1059 found_it = 0;
1060
1061 list_for_each_entry(mode, &connector->modes, head) {
1062 if (drm_mode_equal(pmode, mode)) {
1063 found_it = 1;
1064
1065 mode->status = pmode->status;
1066
1067 mode->type |= pmode->type;
1068 list_del(&pmode->head);
1069 drm_mode_destroy(connector->dev, pmode);
1070 break;
1071 }
1072 }
1073
1074 if (!found_it) {
1075 list_move_tail(&pmode->head, &connector->modes);
1076 }
1077 }
1078}
1079EXPORT_SYMBOL(drm_mode_connector_list_update);
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1095 struct drm_connector *connector,
1096 struct drm_cmdline_mode *mode)
1097{
1098 const char *name;
1099 unsigned int namelen;
1100 bool res_specified = false, bpp_specified = false, refresh_specified = false;
1101 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1102 bool yres_specified = false, cvt = false, rb = false;
1103 bool interlace = false, margins = false, was_digit = false;
1104 int i;
1105 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1106
1107#ifdef CONFIG_FB
1108 if (!mode_option)
1109 mode_option = fb_mode_option;
1110#endif
1111
1112 if (!mode_option) {
1113 mode->specified = false;
1114 return false;
1115 }
1116
1117 name = mode_option;
1118 namelen = strlen(name);
1119 for (i = namelen-1; i >= 0; i--) {
1120 switch (name[i]) {
1121 case '@':
1122 if (!refresh_specified && !bpp_specified &&
1123 !yres_specified && !cvt && !rb && was_digit) {
1124 refresh = simple_strtol(&name[i+1], NULL, 10);
1125 refresh_specified = true;
1126 was_digit = false;
1127 } else
1128 goto done;
1129 break;
1130 case '-':
1131 if (!bpp_specified && !yres_specified && !cvt &&
1132 !rb && was_digit) {
1133 bpp = simple_strtol(&name[i+1], NULL, 10);
1134 bpp_specified = true;
1135 was_digit = false;
1136 } else
1137 goto done;
1138 break;
1139 case 'x':
1140 if (!yres_specified && was_digit) {
1141 yres = simple_strtol(&name[i+1], NULL, 10);
1142 yres_specified = true;
1143 was_digit = false;
1144 } else
1145 goto done;
1146 break;
1147 case '0' ... '9':
1148 was_digit = true;
1149 break;
1150 case 'M':
1151 if (yres_specified || cvt || was_digit)
1152 goto done;
1153 cvt = true;
1154 break;
1155 case 'R':
1156 if (yres_specified || cvt || rb || was_digit)
1157 goto done;
1158 rb = true;
1159 break;
1160 case 'm':
1161 if (cvt || yres_specified || was_digit)
1162 goto done;
1163 margins = true;
1164 break;
1165 case 'i':
1166 if (cvt || yres_specified || was_digit)
1167 goto done;
1168 interlace = true;
1169 break;
1170 case 'e':
1171 if (yres_specified || bpp_specified || refresh_specified ||
1172 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1173 goto done;
1174
1175 force = DRM_FORCE_ON;
1176 break;
1177 case 'D':
1178 if (yres_specified || bpp_specified || refresh_specified ||
1179 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1180 goto done;
1181
1182 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1183 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1184 force = DRM_FORCE_ON;
1185 else
1186 force = DRM_FORCE_ON_DIGITAL;
1187 break;
1188 case 'd':
1189 if (yres_specified || bpp_specified || refresh_specified ||
1190 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1191 goto done;
1192
1193 force = DRM_FORCE_OFF;
1194 break;
1195 default:
1196 goto done;
1197 }
1198 }
1199
1200 if (i < 0 && yres_specified) {
1201 char *ch;
1202 xres = simple_strtol(name, &ch, 10);
1203 if ((ch != NULL) && (*ch == 'x'))
1204 res_specified = true;
1205 else
1206 i = ch - name;
1207 } else if (!yres_specified && was_digit) {
1208
1209 i = 0;
1210 }
1211done:
1212 if (i >= 0) {
1213 printk(KERN_WARNING
1214 "parse error at position %i in video mode '%s'\n",
1215 i, name);
1216 mode->specified = false;
1217 return false;
1218 }
1219
1220 if (res_specified) {
1221 mode->specified = true;
1222 mode->xres = xres;
1223 mode->yres = yres;
1224 }
1225
1226 if (refresh_specified) {
1227 mode->refresh_specified = true;
1228 mode->refresh = refresh;
1229 }
1230
1231 if (bpp_specified) {
1232 mode->bpp_specified = true;
1233 mode->bpp = bpp;
1234 }
1235 mode->rb = rb;
1236 mode->cvt = cvt;
1237 mode->interlace = interlace;
1238 mode->margins = margins;
1239 mode->force = force;
1240
1241 return true;
1242}
1243EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1244
1245struct drm_display_mode *
1246drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1247 struct drm_cmdline_mode *cmd)
1248{
1249 struct drm_display_mode *mode;
1250
1251 if (cmd->cvt)
1252 mode = drm_cvt_mode(dev,
1253 cmd->xres, cmd->yres,
1254 cmd->refresh_specified ? cmd->refresh : 60,
1255 cmd->rb, cmd->interlace,
1256 cmd->margins);
1257 else
1258 mode = drm_gtf_mode(dev,
1259 cmd->xres, cmd->yres,
1260 cmd->refresh_specified ? cmd->refresh : 60,
1261 cmd->interlace,
1262 cmd->margins);
1263 if (!mode)
1264 return NULL;
1265
1266 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1267 return mode;
1268}
1269EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1270