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