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 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
539 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
540 drm_mode_set_name(dmode);
541
542 return 0;
543}
544EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
545
546#ifdef CONFIG_OF
547
548
549
550
551
552
553
554
555
556
557int of_get_drm_display_mode(struct device_node *np,
558 struct drm_display_mode *dmode, int index)
559{
560 struct videomode vm;
561 int ret;
562
563 ret = of_get_videomode(np, &vm, index);
564 if (ret)
565 return ret;
566
567 drm_display_mode_from_videomode(&vm, dmode);
568
569 pr_debug("%s: got %dx%d display mode from %s\n",
570 of_node_full_name(np), vm.hactive, vm.vactive, np->name);
571 drm_mode_debug_printmodeline(dmode);
572
573 return 0;
574}
575EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
576#endif
577#endif
578
579
580
581
582
583
584
585
586
587
588void drm_mode_set_name(struct drm_display_mode *mode)
589{
590 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
591
592 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
593 mode->hdisplay, mode->vdisplay,
594 interlaced ? "i" : "");
595}
596EXPORT_SYMBOL(drm_mode_set_name);
597
598
599
600
601
602
603
604
605
606
607
608void drm_mode_list_concat(struct list_head *head, struct list_head *new)
609{
610
611 struct list_head *entry, *tmp;
612
613 list_for_each_safe(entry, tmp, head) {
614 list_move_tail(entry, new);
615 }
616}
617EXPORT_SYMBOL(drm_mode_list_concat);
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633int drm_mode_width(const struct drm_display_mode *mode)
634{
635 return mode->hdisplay;
636
637}
638EXPORT_SYMBOL(drm_mode_width);
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654int drm_mode_height(const struct drm_display_mode *mode)
655{
656 return mode->vdisplay;
657}
658EXPORT_SYMBOL(drm_mode_height);
659
660
661
662
663
664
665
666
667
668int drm_mode_hsync(const struct drm_display_mode *mode)
669{
670 unsigned int calc_val;
671
672 if (mode->hsync)
673 return mode->hsync;
674
675 if (mode->htotal < 0)
676 return 0;
677
678 calc_val = (mode->clock * 1000) / mode->htotal;
679 calc_val += 500;
680 calc_val /= 1000;
681
682 return calc_val;
683}
684EXPORT_SYMBOL(drm_mode_hsync);
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702int drm_mode_vrefresh(const struct drm_display_mode *mode)
703{
704 int refresh = 0;
705 unsigned int calc_val;
706
707 if (mode->vrefresh > 0)
708 refresh = mode->vrefresh;
709 else if (mode->htotal > 0 && mode->vtotal > 0) {
710 int vtotal;
711 vtotal = mode->vtotal;
712
713 calc_val = (mode->clock * 1000);
714 calc_val /= mode->htotal;
715 refresh = (calc_val + vtotal / 2) / vtotal;
716
717 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
718 refresh *= 2;
719 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
720 refresh /= 2;
721 if (mode->vscan > 1)
722 refresh /= mode->vscan;
723 }
724 return refresh;
725}
726EXPORT_SYMBOL(drm_mode_vrefresh);
727
728
729
730
731
732
733
734
735
736
737
738void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
739{
740 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
741 return;
742
743 p->crtc_hdisplay = p->hdisplay;
744 p->crtc_hsync_start = p->hsync_start;
745 p->crtc_hsync_end = p->hsync_end;
746 p->crtc_htotal = p->htotal;
747 p->crtc_hskew = p->hskew;
748 p->crtc_vdisplay = p->vdisplay;
749 p->crtc_vsync_start = p->vsync_start;
750 p->crtc_vsync_end = p->vsync_end;
751 p->crtc_vtotal = p->vtotal;
752
753 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
754 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
755 p->crtc_vdisplay /= 2;
756 p->crtc_vsync_start /= 2;
757 p->crtc_vsync_end /= 2;
758 p->crtc_vtotal /= 2;
759 }
760 }
761
762 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
763 p->crtc_vdisplay *= 2;
764 p->crtc_vsync_start *= 2;
765 p->crtc_vsync_end *= 2;
766 p->crtc_vtotal *= 2;
767 }
768
769 if (p->vscan > 1) {
770 p->crtc_vdisplay *= p->vscan;
771 p->crtc_vsync_start *= p->vscan;
772 p->crtc_vsync_end *= p->vscan;
773 p->crtc_vtotal *= p->vscan;
774 }
775
776 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
777 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
778 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
779 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
780}
781EXPORT_SYMBOL(drm_mode_set_crtcinfo);
782
783
784
785
786
787
788
789
790
791
792
793
794
795void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
796{
797 int id = dst->base.id;
798 struct list_head head = dst->head;
799
800 *dst = *src;
801 dst->base.id = id;
802 dst->head = head;
803}
804EXPORT_SYMBOL(drm_mode_copy);
805
806
807
808
809
810
811
812
813
814
815
816struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
817 const struct drm_display_mode *mode)
818{
819 struct drm_display_mode *nmode;
820
821 nmode = drm_mode_create(dev);
822 if (!nmode)
823 return NULL;
824
825 drm_mode_copy(nmode, mode);
826
827 return nmode;
828}
829EXPORT_SYMBOL(drm_mode_duplicate);
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
845{
846
847
848 if (mode1->clock && mode2->clock) {
849 if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
850 return false;
851 } else if (mode1->clock != mode2->clock)
852 return false;
853
854 return drm_mode_equal_no_clocks(mode1, mode2);
855}
856EXPORT_SYMBOL(drm_mode_equal);
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
873{
874 if (mode1->hdisplay == mode2->hdisplay &&
875 mode1->hsync_start == mode2->hsync_start &&
876 mode1->hsync_end == mode2->hsync_end &&
877 mode1->htotal == mode2->htotal &&
878 mode1->hskew == mode2->hskew &&
879 mode1->vdisplay == mode2->vdisplay &&
880 mode1->vsync_start == mode2->vsync_start &&
881 mode1->vsync_end == mode2->vsync_end &&
882 mode1->vtotal == mode2->vtotal &&
883 mode1->vscan == mode2->vscan &&
884 mode1->flags == mode2->flags)
885 return true;
886
887 return false;
888}
889EXPORT_SYMBOL(drm_mode_equal_no_clocks);
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906void drm_mode_validate_size(struct drm_device *dev,
907 struct list_head *mode_list,
908 int maxX, int maxY, int maxPitch)
909{
910 struct drm_display_mode *mode;
911
912 list_for_each_entry(mode, mode_list, head) {
913 if (maxPitch > 0 && mode->hdisplay > maxPitch)
914 mode->status = MODE_BAD_WIDTH;
915
916 if (maxX > 0 && mode->hdisplay > maxX)
917 mode->status = MODE_VIRTUAL_X;
918
919 if (maxY > 0 && mode->vdisplay > maxY)
920 mode->status = MODE_VIRTUAL_Y;
921 }
922}
923EXPORT_SYMBOL(drm_mode_validate_size);
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941void drm_mode_validate_clocks(struct drm_device *dev,
942 struct list_head *mode_list,
943 int *min, int *max, int n_ranges)
944{
945 struct drm_display_mode *mode;
946 int i;
947
948 list_for_each_entry(mode, mode_list, head) {
949 bool good = false;
950 for (i = 0; i < n_ranges; i++) {
951 if (mode->clock >= min[i] && mode->clock <= max[i]) {
952 good = true;
953 break;
954 }
955 }
956 if (!good)
957 mode->status = MODE_CLOCK_RANGE;
958 }
959}
960EXPORT_SYMBOL(drm_mode_validate_clocks);
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975void drm_mode_prune_invalid(struct drm_device *dev,
976 struct list_head *mode_list, bool verbose)
977{
978 struct drm_display_mode *mode, *t;
979
980 list_for_each_entry_safe(mode, t, mode_list, head) {
981 if (mode->status != MODE_OK) {
982 list_del(&mode->head);
983 if (verbose) {
984 drm_mode_debug_printmodeline(mode);
985 DRM_DEBUG_KMS("Not using %s mode %d\n",
986 mode->name, mode->status);
987 }
988 drm_mode_destroy(dev, mode);
989 }
990 }
991}
992EXPORT_SYMBOL(drm_mode_prune_invalid);
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1011{
1012 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1013 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1014 int diff;
1015
1016 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1017 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1018 if (diff)
1019 return diff;
1020 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1021 if (diff)
1022 return diff;
1023
1024 diff = b->vrefresh - a->vrefresh;
1025 if (diff)
1026 return diff;
1027
1028 diff = b->clock - a->clock;
1029 return diff;
1030}
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041void drm_mode_sort(struct list_head *mode_list)
1042{
1043 list_sort(NULL, mode_list, drm_mode_compare);
1044}
1045EXPORT_SYMBOL(drm_mode_sort);
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059void drm_mode_connector_list_update(struct drm_connector *connector)
1060{
1061 struct drm_display_mode *mode;
1062 struct drm_display_mode *pmode, *pt;
1063 int found_it;
1064
1065 list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
1066 head) {
1067 found_it = 0;
1068
1069 list_for_each_entry(mode, &connector->modes, head) {
1070 if (drm_mode_equal(pmode, mode)) {
1071 found_it = 1;
1072
1073 mode->status = pmode->status;
1074
1075 mode->type |= pmode->type;
1076 list_del(&pmode->head);
1077 drm_mode_destroy(connector->dev, pmode);
1078 break;
1079 }
1080 }
1081
1082 if (!found_it) {
1083 list_move_tail(&pmode->head, &connector->modes);
1084 }
1085 }
1086}
1087EXPORT_SYMBOL(drm_mode_connector_list_update);
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1103 struct drm_connector *connector,
1104 struct drm_cmdline_mode *mode)
1105{
1106 const char *name;
1107 unsigned int namelen;
1108 bool res_specified = false, bpp_specified = false, refresh_specified = false;
1109 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1110 bool yres_specified = false, cvt = false, rb = false;
1111 bool interlace = false, margins = false, was_digit = false;
1112 int i;
1113 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1114
1115#ifdef CONFIG_FB
1116 if (!mode_option)
1117 mode_option = fb_mode_option;
1118#endif
1119
1120 if (!mode_option) {
1121 mode->specified = false;
1122 return false;
1123 }
1124
1125 name = mode_option;
1126 namelen = strlen(name);
1127 for (i = namelen-1; i >= 0; i--) {
1128 switch (name[i]) {
1129 case '@':
1130 if (!refresh_specified && !bpp_specified &&
1131 !yres_specified && !cvt && !rb && was_digit) {
1132 refresh = simple_strtol(&name[i+1], NULL, 10);
1133 refresh_specified = true;
1134 was_digit = false;
1135 } else
1136 goto done;
1137 break;
1138 case '-':
1139 if (!bpp_specified && !yres_specified && !cvt &&
1140 !rb && was_digit) {
1141 bpp = simple_strtol(&name[i+1], NULL, 10);
1142 bpp_specified = true;
1143 was_digit = false;
1144 } else
1145 goto done;
1146 break;
1147 case 'x':
1148 if (!yres_specified && was_digit) {
1149 yres = simple_strtol(&name[i+1], NULL, 10);
1150 yres_specified = true;
1151 was_digit = false;
1152 } else
1153 goto done;
1154 break;
1155 case '0' ... '9':
1156 was_digit = true;
1157 break;
1158 case 'M':
1159 if (yres_specified || cvt || was_digit)
1160 goto done;
1161 cvt = true;
1162 break;
1163 case 'R':
1164 if (yres_specified || cvt || rb || was_digit)
1165 goto done;
1166 rb = true;
1167 break;
1168 case 'm':
1169 if (cvt || yres_specified || was_digit)
1170 goto done;
1171 margins = true;
1172 break;
1173 case 'i':
1174 if (cvt || yres_specified || was_digit)
1175 goto done;
1176 interlace = true;
1177 break;
1178 case 'e':
1179 if (yres_specified || bpp_specified || refresh_specified ||
1180 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1181 goto done;
1182
1183 force = DRM_FORCE_ON;
1184 break;
1185 case 'D':
1186 if (yres_specified || bpp_specified || refresh_specified ||
1187 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1188 goto done;
1189
1190 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1191 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1192 force = DRM_FORCE_ON;
1193 else
1194 force = DRM_FORCE_ON_DIGITAL;
1195 break;
1196 case 'd':
1197 if (yres_specified || bpp_specified || refresh_specified ||
1198 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1199 goto done;
1200
1201 force = DRM_FORCE_OFF;
1202 break;
1203 default:
1204 goto done;
1205 }
1206 }
1207
1208 if (i < 0 && yres_specified) {
1209 char *ch;
1210 xres = simple_strtol(name, &ch, 10);
1211 if ((ch != NULL) && (*ch == 'x'))
1212 res_specified = true;
1213 else
1214 i = ch - name;
1215 } else if (!yres_specified && was_digit) {
1216
1217 i = 0;
1218 }
1219done:
1220 if (i >= 0) {
1221 printk(KERN_WARNING
1222 "parse error at position %i in video mode '%s'\n",
1223 i, name);
1224 mode->specified = false;
1225 return false;
1226 }
1227
1228 if (res_specified) {
1229 mode->specified = true;
1230 mode->xres = xres;
1231 mode->yres = yres;
1232 }
1233
1234 if (refresh_specified) {
1235 mode->refresh_specified = true;
1236 mode->refresh = refresh;
1237 }
1238
1239 if (bpp_specified) {
1240 mode->bpp_specified = true;
1241 mode->bpp = bpp;
1242 }
1243 mode->rb = rb;
1244 mode->cvt = cvt;
1245 mode->interlace = interlace;
1246 mode->margins = margins;
1247 mode->force = force;
1248
1249 return true;
1250}
1251EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1252
1253struct drm_display_mode *
1254drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1255 struct drm_cmdline_mode *cmd)
1256{
1257 struct drm_display_mode *mode;
1258
1259 if (cmd->cvt)
1260 mode = drm_cvt_mode(dev,
1261 cmd->xres, cmd->yres,
1262 cmd->refresh_specified ? cmd->refresh : 60,
1263 cmd->rb, cmd->interlace,
1264 cmd->margins);
1265 else
1266 mode = drm_gtf_mode(dev,
1267 cmd->xres, cmd->yres,
1268 cmd->refresh_specified ? cmd->refresh : 60,
1269 cmd->interlace,
1270 cmd->margins);
1271 if (!mode)
1272 return NULL;
1273
1274 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1275 return mode;
1276}
1277EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1278