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