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