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
619
620
621
622
623
624
625void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
626 struct videomode *vm)
627{
628 vm->hactive = dmode->hdisplay;
629 vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
630 vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
631 vm->hback_porch = dmode->htotal - dmode->hsync_end;
632
633 vm->vactive = dmode->vdisplay;
634 vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
635 vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
636 vm->vback_porch = dmode->vtotal - dmode->vsync_end;
637
638 vm->pixelclock = dmode->clock * 1000;
639
640 vm->flags = 0;
641 if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
642 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
643 else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
644 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
645 if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
646 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
647 else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
648 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
649 if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
650 vm->flags |= DISPLAY_FLAGS_INTERLACED;
651 if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
652 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
653 if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
654 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
655}
656EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
657
658#ifdef CONFIG_OF
659
660
661
662
663
664
665
666
667
668
669
670
671
672int of_get_drm_display_mode(struct device_node *np,
673 struct drm_display_mode *dmode, int index)
674{
675 struct videomode vm;
676 int ret;
677
678 ret = of_get_videomode(np, &vm, index);
679 if (ret)
680 return ret;
681
682 drm_display_mode_from_videomode(&vm, dmode);
683
684 pr_debug("%s: got %dx%d display mode from %s\n",
685 of_node_full_name(np), vm.hactive, vm.vactive, np->name);
686 drm_mode_debug_printmodeline(dmode);
687
688 return 0;
689}
690EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
691#endif
692#endif
693
694
695
696
697
698
699
700
701void drm_mode_set_name(struct drm_display_mode *mode)
702{
703 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
704
705 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
706 mode->hdisplay, mode->vdisplay,
707 interlaced ? "i" : "");
708}
709EXPORT_SYMBOL(drm_mode_set_name);
710
711
712
713
714
715
716
717
718
719int drm_mode_hsync(const struct drm_display_mode *mode)
720{
721 unsigned int calc_val;
722
723 if (mode->hsync)
724 return mode->hsync;
725
726 if (mode->htotal < 0)
727 return 0;
728
729 calc_val = (mode->clock * 1000) / mode->htotal;
730 calc_val += 500;
731 calc_val /= 1000;
732
733 return calc_val;
734}
735EXPORT_SYMBOL(drm_mode_hsync);
736
737
738
739
740
741
742
743
744
745int drm_mode_vrefresh(const struct drm_display_mode *mode)
746{
747 int refresh = 0;
748 unsigned int calc_val;
749
750 if (mode->vrefresh > 0)
751 refresh = mode->vrefresh;
752 else if (mode->htotal > 0 && mode->vtotal > 0) {
753 int vtotal;
754 vtotal = mode->vtotal;
755
756 calc_val = (mode->clock * 1000);
757 calc_val /= mode->htotal;
758 refresh = (calc_val + vtotal / 2) / vtotal;
759
760 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
761 refresh *= 2;
762 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
763 refresh /= 2;
764 if (mode->vscan > 1)
765 refresh /= mode->vscan;
766 }
767 return refresh;
768}
769EXPORT_SYMBOL(drm_mode_vrefresh);
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
787{
788 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
789 return;
790
791 p->crtc_clock = p->clock;
792 p->crtc_hdisplay = p->hdisplay;
793 p->crtc_hsync_start = p->hsync_start;
794 p->crtc_hsync_end = p->hsync_end;
795 p->crtc_htotal = p->htotal;
796 p->crtc_hskew = p->hskew;
797 p->crtc_vdisplay = p->vdisplay;
798 p->crtc_vsync_start = p->vsync_start;
799 p->crtc_vsync_end = p->vsync_end;
800 p->crtc_vtotal = p->vtotal;
801
802 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
803 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
804 p->crtc_vdisplay /= 2;
805 p->crtc_vsync_start /= 2;
806 p->crtc_vsync_end /= 2;
807 p->crtc_vtotal /= 2;
808 }
809 }
810
811 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
812 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
813 p->crtc_vdisplay *= 2;
814 p->crtc_vsync_start *= 2;
815 p->crtc_vsync_end *= 2;
816 p->crtc_vtotal *= 2;
817 }
818 }
819
820 if (!(adjust_flags & CRTC_NO_VSCAN)) {
821 if (p->vscan > 1) {
822 p->crtc_vdisplay *= p->vscan;
823 p->crtc_vsync_start *= p->vscan;
824 p->crtc_vsync_end *= p->vscan;
825 p->crtc_vtotal *= p->vscan;
826 }
827 }
828
829 if (adjust_flags & CRTC_STEREO_DOUBLE) {
830 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
831
832 switch (layout) {
833 case DRM_MODE_FLAG_3D_FRAME_PACKING:
834 p->crtc_clock *= 2;
835 p->crtc_vdisplay += p->crtc_vtotal;
836 p->crtc_vsync_start += p->crtc_vtotal;
837 p->crtc_vsync_end += p->crtc_vtotal;
838 p->crtc_vtotal += p->crtc_vtotal;
839 break;
840 }
841 }
842
843 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
844 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
845 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
846 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
847}
848EXPORT_SYMBOL(drm_mode_set_crtcinfo);
849
850
851
852
853
854
855
856
857
858void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
859{
860 int id = dst->base.id;
861 struct list_head head = dst->head;
862
863 *dst = *src;
864 dst->base.id = id;
865 dst->head = head;
866}
867EXPORT_SYMBOL(drm_mode_copy);
868
869
870
871
872
873
874
875
876
877
878
879
880struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
881 const struct drm_display_mode *mode)
882{
883 struct drm_display_mode *nmode;
884
885 nmode = drm_mode_create(dev);
886 if (!nmode)
887 return NULL;
888
889 drm_mode_copy(nmode, mode);
890
891 return nmode;
892}
893EXPORT_SYMBOL(drm_mode_duplicate);
894
895
896
897
898
899
900
901
902
903
904
905bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
906{
907 if (!mode1 && !mode2)
908 return true;
909
910 if (!mode1 || !mode2)
911 return false;
912
913
914
915 if (mode1->clock && mode2->clock) {
916 if (KHZ2PICOS(mode1->clock) != KHZ2PICOS(mode2->clock))
917 return false;
918 } else if (mode1->clock != mode2->clock)
919 return false;
920
921 return drm_mode_equal_no_clocks(mode1, mode2);
922}
923EXPORT_SYMBOL(drm_mode_equal);
924
925
926
927
928
929
930
931
932
933
934
935
936bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
937{
938 if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) !=
939 (mode2->flags & DRM_MODE_FLAG_3D_MASK))
940 return false;
941
942 return drm_mode_equal_no_clocks_no_stereo(mode1, mode2);
943}
944EXPORT_SYMBOL(drm_mode_equal_no_clocks);
945
946
947
948
949
950
951
952
953
954
955
956
957bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
958 const struct drm_display_mode *mode2)
959{
960 if (mode1->hdisplay == mode2->hdisplay &&
961 mode1->hsync_start == mode2->hsync_start &&
962 mode1->hsync_end == mode2->hsync_end &&
963 mode1->htotal == mode2->htotal &&
964 mode1->hskew == mode2->hskew &&
965 mode1->vdisplay == mode2->vdisplay &&
966 mode1->vsync_start == mode2->vsync_start &&
967 mode1->vsync_end == mode2->vsync_end &&
968 mode1->vtotal == mode2->vtotal &&
969 mode1->vscan == mode2->vscan &&
970 (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
971 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK))
972 return true;
973
974 return false;
975}
976EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
977
978
979
980
981
982
983
984
985
986
987
988enum drm_mode_status
989drm_mode_validate_basic(const struct drm_display_mode *mode)
990{
991 if (mode->clock == 0)
992 return MODE_CLOCK_LOW;
993
994 if (mode->hdisplay == 0 ||
995 mode->hsync_start < mode->hdisplay ||
996 mode->hsync_end < mode->hsync_start ||
997 mode->htotal < mode->hsync_end)
998 return MODE_H_ILLEGAL;
999
1000 if (mode->vdisplay == 0 ||
1001 mode->vsync_start < mode->vdisplay ||
1002 mode->vsync_end < mode->vsync_start ||
1003 mode->vtotal < mode->vsync_end)
1004 return MODE_V_ILLEGAL;
1005
1006 return MODE_OK;
1007}
1008EXPORT_SYMBOL(drm_mode_validate_basic);
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024enum drm_mode_status
1025drm_mode_validate_size(const struct drm_display_mode *mode,
1026 int maxX, int maxY)
1027{
1028 if (maxX > 0 && mode->hdisplay > maxX)
1029 return MODE_VIRTUAL_X;
1030
1031 if (maxY > 0 && mode->vdisplay > maxY)
1032 return MODE_VIRTUAL_Y;
1033
1034 return MODE_OK;
1035}
1036EXPORT_SYMBOL(drm_mode_validate_size);
1037
1038#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1039
1040static const char * const drm_mode_status_names[] = {
1041 MODE_STATUS(OK),
1042 MODE_STATUS(HSYNC),
1043 MODE_STATUS(VSYNC),
1044 MODE_STATUS(H_ILLEGAL),
1045 MODE_STATUS(V_ILLEGAL),
1046 MODE_STATUS(BAD_WIDTH),
1047 MODE_STATUS(NOMODE),
1048 MODE_STATUS(NO_INTERLACE),
1049 MODE_STATUS(NO_DBLESCAN),
1050 MODE_STATUS(NO_VSCAN),
1051 MODE_STATUS(MEM),
1052 MODE_STATUS(VIRTUAL_X),
1053 MODE_STATUS(VIRTUAL_Y),
1054 MODE_STATUS(MEM_VIRT),
1055 MODE_STATUS(NOCLOCK),
1056 MODE_STATUS(CLOCK_HIGH),
1057 MODE_STATUS(CLOCK_LOW),
1058 MODE_STATUS(CLOCK_RANGE),
1059 MODE_STATUS(BAD_HVALUE),
1060 MODE_STATUS(BAD_VVALUE),
1061 MODE_STATUS(BAD_VSCAN),
1062 MODE_STATUS(HSYNC_NARROW),
1063 MODE_STATUS(HSYNC_WIDE),
1064 MODE_STATUS(HBLANK_NARROW),
1065 MODE_STATUS(HBLANK_WIDE),
1066 MODE_STATUS(VSYNC_NARROW),
1067 MODE_STATUS(VSYNC_WIDE),
1068 MODE_STATUS(VBLANK_NARROW),
1069 MODE_STATUS(VBLANK_WIDE),
1070 MODE_STATUS(PANEL),
1071 MODE_STATUS(INTERLACE_WIDTH),
1072 MODE_STATUS(ONE_WIDTH),
1073 MODE_STATUS(ONE_HEIGHT),
1074 MODE_STATUS(ONE_SIZE),
1075 MODE_STATUS(NO_REDUCED),
1076 MODE_STATUS(NO_STEREO),
1077 MODE_STATUS(STALE),
1078 MODE_STATUS(BAD),
1079 MODE_STATUS(ERROR),
1080};
1081
1082#undef MODE_STATUS
1083
1084static const char *drm_get_mode_status_name(enum drm_mode_status status)
1085{
1086 int index = status + 3;
1087
1088 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1089 return "";
1090
1091 return drm_mode_status_names[index];
1092}
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105void drm_mode_prune_invalid(struct drm_device *dev,
1106 struct list_head *mode_list, bool verbose)
1107{
1108 struct drm_display_mode *mode, *t;
1109
1110 list_for_each_entry_safe(mode, t, mode_list, head) {
1111 if (mode->status != MODE_OK) {
1112 list_del(&mode->head);
1113 if (verbose) {
1114 drm_mode_debug_printmodeline(mode);
1115 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1116 mode->name,
1117 drm_get_mode_status_name(mode->status));
1118 }
1119 drm_mode_destroy(dev, mode);
1120 }
1121 }
1122}
1123EXPORT_SYMBOL(drm_mode_prune_invalid);
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1139{
1140 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1141 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1142 int diff;
1143
1144 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1145 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1146 if (diff)
1147 return diff;
1148 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1149 if (diff)
1150 return diff;
1151
1152 diff = b->vrefresh - a->vrefresh;
1153 if (diff)
1154 return diff;
1155
1156 diff = b->clock - a->clock;
1157 return diff;
1158}
1159
1160
1161
1162
1163
1164
1165
1166void drm_mode_sort(struct list_head *mode_list)
1167{
1168 list_sort(NULL, mode_list, drm_mode_compare);
1169}
1170EXPORT_SYMBOL(drm_mode_sort);
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183void drm_mode_connector_list_update(struct drm_connector *connector)
1184{
1185 struct drm_display_mode *pmode, *pt;
1186
1187 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1188
1189 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1190 struct drm_display_mode *mode;
1191 bool found_it = false;
1192
1193
1194 list_for_each_entry(mode, &connector->modes, head) {
1195 if (!drm_mode_equal(pmode, mode))
1196 continue;
1197
1198 found_it = true;
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212 if (mode->status == MODE_STALE) {
1213 drm_mode_copy(mode, pmode);
1214 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1215 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1216 pmode->type |= mode->type;
1217 drm_mode_copy(mode, pmode);
1218 } else {
1219 mode->type |= pmode->type;
1220 }
1221
1222 list_del(&pmode->head);
1223 drm_mode_destroy(connector->dev, pmode);
1224 break;
1225 }
1226
1227 if (!found_it) {
1228 list_move_tail(&pmode->head, &connector->modes);
1229 }
1230 }
1231}
1232EXPORT_SYMBOL(drm_mode_connector_list_update);
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1256 struct drm_connector *connector,
1257 struct drm_cmdline_mode *mode)
1258{
1259 const char *name;
1260 unsigned int namelen;
1261 bool res_specified = false, bpp_specified = false, refresh_specified = false;
1262 unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
1263 bool yres_specified = false, cvt = false, rb = false;
1264 bool interlace = false, margins = false, was_digit = false;
1265 int i;
1266 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
1267
1268#ifdef CONFIG_FB
1269 if (!mode_option)
1270 mode_option = fb_mode_option;
1271#endif
1272
1273 if (!mode_option) {
1274 mode->specified = false;
1275 return false;
1276 }
1277
1278 name = mode_option;
1279 namelen = strlen(name);
1280 for (i = namelen-1; i >= 0; i--) {
1281 switch (name[i]) {
1282 case '@':
1283 if (!refresh_specified && !bpp_specified &&
1284 !yres_specified && !cvt && !rb && was_digit) {
1285 refresh = simple_strtol(&name[i+1], NULL, 10);
1286 refresh_specified = true;
1287 was_digit = false;
1288 } else
1289 goto done;
1290 break;
1291 case '-':
1292 if (!bpp_specified && !yres_specified && !cvt &&
1293 !rb && was_digit) {
1294 bpp = simple_strtol(&name[i+1], NULL, 10);
1295 bpp_specified = true;
1296 was_digit = false;
1297 } else
1298 goto done;
1299 break;
1300 case 'x':
1301 if (!yres_specified && was_digit) {
1302 yres = simple_strtol(&name[i+1], NULL, 10);
1303 yres_specified = true;
1304 was_digit = false;
1305 } else
1306 goto done;
1307 break;
1308 case '0' ... '9':
1309 was_digit = true;
1310 break;
1311 case 'M':
1312 if (yres_specified || cvt || was_digit)
1313 goto done;
1314 cvt = true;
1315 break;
1316 case 'R':
1317 if (yres_specified || cvt || rb || was_digit)
1318 goto done;
1319 rb = true;
1320 break;
1321 case 'm':
1322 if (cvt || yres_specified || was_digit)
1323 goto done;
1324 margins = true;
1325 break;
1326 case 'i':
1327 if (cvt || yres_specified || was_digit)
1328 goto done;
1329 interlace = true;
1330 break;
1331 case 'e':
1332 if (yres_specified || bpp_specified || refresh_specified ||
1333 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1334 goto done;
1335
1336 force = DRM_FORCE_ON;
1337 break;
1338 case 'D':
1339 if (yres_specified || bpp_specified || refresh_specified ||
1340 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1341 goto done;
1342
1343 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1344 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1345 force = DRM_FORCE_ON;
1346 else
1347 force = DRM_FORCE_ON_DIGITAL;
1348 break;
1349 case 'd':
1350 if (yres_specified || bpp_specified || refresh_specified ||
1351 was_digit || (force != DRM_FORCE_UNSPECIFIED))
1352 goto done;
1353
1354 force = DRM_FORCE_OFF;
1355 break;
1356 default:
1357 goto done;
1358 }
1359 }
1360
1361 if (i < 0 && yres_specified) {
1362 char *ch;
1363 xres = simple_strtol(name, &ch, 10);
1364 if ((ch != NULL) && (*ch == 'x'))
1365 res_specified = true;
1366 else
1367 i = ch - name;
1368 } else if (!yres_specified && was_digit) {
1369
1370 i = 0;
1371 }
1372done:
1373 if (i >= 0) {
1374 pr_warn("[drm] parse error at position %i in video mode '%s'\n",
1375 i, name);
1376 mode->specified = false;
1377 return false;
1378 }
1379
1380 if (res_specified) {
1381 mode->specified = true;
1382 mode->xres = xres;
1383 mode->yres = yres;
1384 }
1385
1386 if (refresh_specified) {
1387 mode->refresh_specified = true;
1388 mode->refresh = refresh;
1389 }
1390
1391 if (bpp_specified) {
1392 mode->bpp_specified = true;
1393 mode->bpp = bpp;
1394 }
1395 mode->rb = rb;
1396 mode->cvt = cvt;
1397 mode->interlace = interlace;
1398 mode->margins = margins;
1399 mode->force = force;
1400
1401 return true;
1402}
1403EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413struct drm_display_mode *
1414drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1415 struct drm_cmdline_mode *cmd)
1416{
1417 struct drm_display_mode *mode;
1418
1419 if (cmd->cvt)
1420 mode = drm_cvt_mode(dev,
1421 cmd->xres, cmd->yres,
1422 cmd->refresh_specified ? cmd->refresh : 60,
1423 cmd->rb, cmd->interlace,
1424 cmd->margins);
1425 else
1426 mode = drm_gtf_mode(dev,
1427 cmd->xres, cmd->yres,
1428 cmd->refresh_specified ? cmd->refresh : 60,
1429 cmd->interlace,
1430 cmd->margins);
1431 if (!mode)
1432 return NULL;
1433
1434 mode->type |= DRM_MODE_TYPE_USERDEF;
1435 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1436 return mode;
1437}
1438EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1449 const struct drm_display_mode *in)
1450{
1451 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1452 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1453 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1454 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1455 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1456 "timing values too large for mode info\n");
1457
1458 out->clock = in->clock;
1459 out->hdisplay = in->hdisplay;
1460 out->hsync_start = in->hsync_start;
1461 out->hsync_end = in->hsync_end;
1462 out->htotal = in->htotal;
1463 out->hskew = in->hskew;
1464 out->vdisplay = in->vdisplay;
1465 out->vsync_start = in->vsync_start;
1466 out->vsync_end = in->vsync_end;
1467 out->vtotal = in->vtotal;
1468 out->vscan = in->vscan;
1469 out->vrefresh = in->vrefresh;
1470 out->flags = in->flags;
1471 out->type = in->type;
1472 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1473 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1474}
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487int drm_mode_convert_umode(struct drm_display_mode *out,
1488 const struct drm_mode_modeinfo *in)
1489{
1490 int ret = -EINVAL;
1491
1492 if (in->clock > INT_MAX || in->vrefresh > INT_MAX) {
1493 ret = -ERANGE;
1494 goto out;
1495 }
1496
1497 if ((in->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1498 goto out;
1499
1500 out->clock = in->clock;
1501 out->hdisplay = in->hdisplay;
1502 out->hsync_start = in->hsync_start;
1503 out->hsync_end = in->hsync_end;
1504 out->htotal = in->htotal;
1505 out->hskew = in->hskew;
1506 out->vdisplay = in->vdisplay;
1507 out->vsync_start = in->vsync_start;
1508 out->vsync_end = in->vsync_end;
1509 out->vtotal = in->vtotal;
1510 out->vscan = in->vscan;
1511 out->vrefresh = in->vrefresh;
1512 out->flags = in->flags;
1513 out->type = in->type;
1514 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1515 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1516
1517 out->status = drm_mode_validate_basic(out);
1518 if (out->status != MODE_OK)
1519 goto out;
1520
1521 ret = 0;
1522
1523out:
1524 return ret;
1525}
1526