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/ctype.h>
34#include <linux/list.h>
35#include <linux/list_sort.h>
36#include <linux/export.h>
37
38#include <video/of_videomode.h>
39#include <video/videomode.h>
40
41#include <drm/drm_crtc.h>
42#include <drm/drm_device.h>
43#include <drm/drm_modes.h>
44#include <drm/drm_print.h>
45
46#include "drm_crtc_internal.h"
47
48
49
50
51
52
53
54void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
55{
56 DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
57}
58EXPORT_SYMBOL(drm_mode_debug_printmodeline);
59
60
61
62
63
64
65
66
67
68
69
70struct drm_display_mode *drm_mode_create(struct drm_device *dev)
71{
72 struct drm_display_mode *nmode;
73
74 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
75 if (!nmode)
76 return NULL;
77
78 return nmode;
79}
80EXPORT_SYMBOL(drm_mode_create);
81
82
83
84
85
86
87
88
89void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
90{
91 if (!mode)
92 return;
93
94 kfree(mode);
95}
96EXPORT_SYMBOL(drm_mode_destroy);
97
98
99
100
101
102
103
104
105
106
107void drm_mode_probed_add(struct drm_connector *connector,
108 struct drm_display_mode *mode)
109{
110 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
111
112 list_add_tail(&mode->head, &connector->probed_modes);
113}
114EXPORT_SYMBOL(drm_mode_probed_add);
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
141 int vdisplay, int vrefresh,
142 bool reduced, bool interlaced, bool margins)
143{
144#define HV_FACTOR 1000
145
146#define CVT_MARGIN_PERCENTAGE 18
147
148#define CVT_H_GRANULARITY 8
149
150#define CVT_MIN_V_PORCH 3
151
152#define CVT_MIN_V_BPORCH 6
153
154#define CVT_CLOCK_STEP 250
155 struct drm_display_mode *drm_mode;
156 unsigned int vfieldrate, hperiod;
157 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
158 int interlace;
159 u64 tmp;
160
161 if (!hdisplay || !vdisplay)
162 return NULL;
163
164
165
166
167 drm_mode = drm_mode_create(dev);
168 if (!drm_mode)
169 return NULL;
170
171
172 if (!vrefresh)
173 vrefresh = 60;
174
175
176 if (interlaced)
177 vfieldrate = vrefresh * 2;
178 else
179 vfieldrate = vrefresh;
180
181
182 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
183
184
185 hmargin = 0;
186 if (margins) {
187 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
188 hmargin -= hmargin % CVT_H_GRANULARITY;
189 }
190
191 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
192
193
194 if (interlaced)
195 vdisplay_rnd = vdisplay / 2;
196 else
197 vdisplay_rnd = vdisplay;
198
199
200 vmargin = 0;
201 if (margins)
202 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
203
204 drm_mode->vdisplay = vdisplay + 2 * vmargin;
205
206
207 if (interlaced)
208 interlace = 1;
209 else
210 interlace = 0;
211
212
213 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
214 vsync = 4;
215 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
216 vsync = 5;
217 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
218 vsync = 6;
219 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
220 vsync = 7;
221 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
222 vsync = 7;
223 else
224 vsync = 10;
225
226 if (!reduced) {
227
228
229
230
231 int tmp1, tmp2;
232#define CVT_MIN_VSYNC_BP 550
233
234#define CVT_HSYNC_PERCENTAGE 8
235 unsigned int hblank_percentage;
236 int vsyncandback_porch, __maybe_unused vback_porch, hblank;
237
238
239 tmp1 = HV_FACTOR * 1000000 -
240 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
241 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
242 interlace;
243 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
244
245 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
246
247 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
248 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
249 else
250 vsyncandback_porch = tmp1;
251
252 vback_porch = vsyncandback_porch - vsync;
253 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
254 vsyncandback_porch + CVT_MIN_V_PORCH;
255
256
257#define CVT_M_FACTOR 600
258
259#define CVT_C_FACTOR 40
260
261#define CVT_K_FACTOR 128
262
263#define CVT_J_FACTOR 20
264#define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
265#define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
266 CVT_J_FACTOR)
267
268 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
269 hperiod / 1000;
270
271 if (hblank_percentage < 20 * HV_FACTOR)
272 hblank_percentage = 20 * HV_FACTOR;
273 hblank = drm_mode->hdisplay * hblank_percentage /
274 (100 * HV_FACTOR - hblank_percentage);
275 hblank -= hblank % (2 * CVT_H_GRANULARITY);
276
277 drm_mode->htotal = drm_mode->hdisplay + hblank;
278 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
279 drm_mode->hsync_start = drm_mode->hsync_end -
280 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
281 drm_mode->hsync_start += CVT_H_GRANULARITY -
282 drm_mode->hsync_start % CVT_H_GRANULARITY;
283
284 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
285 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
286 } else {
287
288
289#define CVT_RB_MIN_VBLANK 460
290
291#define CVT_RB_H_SYNC 32
292
293#define CVT_RB_H_BLANK 160
294
295#define CVT_RB_VFPORCH 3
296 int vbilines;
297 int tmp1, tmp2;
298
299 tmp1 = HV_FACTOR * 1000000 -
300 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
301 tmp2 = vdisplay_rnd + 2 * vmargin;
302 hperiod = tmp1 / (tmp2 * vfieldrate);
303
304 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
305
306 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
307 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
308
309 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
310
311 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
312
313 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
314 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
315
316 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
317 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
318 }
319
320 tmp = drm_mode->htotal;
321 tmp *= HV_FACTOR * 1000;
322 do_div(tmp, hperiod);
323 tmp -= drm_mode->clock % CVT_CLOCK_STEP;
324 drm_mode->clock = tmp;
325
326
327 if (interlaced) {
328 drm_mode->vtotal *= 2;
329 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
330 }
331
332 drm_mode_set_name(drm_mode);
333 if (reduced)
334 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
335 DRM_MODE_FLAG_NVSYNC);
336 else
337 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
338 DRM_MODE_FLAG_NHSYNC);
339
340 return drm_mode;
341}
342EXPORT_SYMBOL(drm_cvt_mode);
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365struct drm_display_mode *
366drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
367 int vrefresh, bool interlaced, int margins,
368 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
369{
370#define GTF_MARGIN_PERCENTAGE 18
371
372#define GTF_CELL_GRAN 8
373
374#define GTF_MIN_V_PORCH 1
375
376#define V_SYNC_RQD 3
377
378#define H_SYNC_PERCENT 8
379
380#define MIN_VSYNC_PLUS_BP 550
381
382#define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
383#define GTF_M_PRIME (GTF_K * GTF_M / 256)
384 struct drm_display_mode *drm_mode;
385 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
386 int top_margin, bottom_margin;
387 int interlace;
388 unsigned int hfreq_est;
389 int vsync_plus_bp, __maybe_unused vback_porch;
390 unsigned int vtotal_lines, __maybe_unused vfieldrate_est;
391 unsigned int __maybe_unused hperiod;
392 unsigned int vfield_rate, __maybe_unused vframe_rate;
393 int left_margin, right_margin;
394 unsigned int total_active_pixels, ideal_duty_cycle;
395 unsigned int hblank, total_pixels, pixel_freq;
396 int hsync, hfront_porch, vodd_front_porch_lines;
397 unsigned int tmp1, tmp2;
398
399 if (!hdisplay || !vdisplay)
400 return NULL;
401
402 drm_mode = drm_mode_create(dev);
403 if (!drm_mode)
404 return NULL;
405
406
407
408
409
410
411 hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
412 hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
413
414
415
416
417
418 if (interlaced)
419 vdisplay_rnd = vdisplay / 2;
420 else
421 vdisplay_rnd = vdisplay;
422
423
424 if (interlaced)
425 vfieldrate_rqd = vrefresh * 2;
426 else
427 vfieldrate_rqd = vrefresh;
428
429
430 top_margin = 0;
431 if (margins)
432 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
433 1000;
434
435 bottom_margin = top_margin;
436
437
438 if (interlaced)
439 interlace = 1;
440 else
441 interlace = 0;
442
443
444 {
445 tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
446 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
447 2 + interlace;
448 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
449 }
450
451
452
453 vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
454 vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
455
456 vback_porch = vsync_plus_bp - V_SYNC_RQD;
457
458 vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
459 vsync_plus_bp + GTF_MIN_V_PORCH;
460
461 vfieldrate_est = hfreq_est / vtotal_lines;
462
463 hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
464
465
466 vfield_rate = hfreq_est / vtotal_lines;
467
468 if (interlaced)
469 vframe_rate = vfield_rate / 2;
470 else
471 vframe_rate = vfield_rate;
472
473 if (margins)
474 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
475 1000;
476 else
477 left_margin = 0;
478
479
480 right_margin = left_margin;
481
482 total_active_pixels = hdisplay_rnd + left_margin + right_margin;
483
484 ideal_duty_cycle = GTF_C_PRIME * 1000 -
485 (GTF_M_PRIME * 1000000 / hfreq_est);
486
487
488 hblank = total_active_pixels * ideal_duty_cycle /
489 (100000 - ideal_duty_cycle);
490 hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
491 hblank = hblank * 2 * GTF_CELL_GRAN;
492
493 total_pixels = total_active_pixels + hblank;
494
495 pixel_freq = total_pixels * hfreq_est / 1000;
496
497
498
499
500
501 hsync = H_SYNC_PERCENT * total_pixels / 100;
502 hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
503 hsync = hsync * GTF_CELL_GRAN;
504
505 hfront_porch = hblank / 2 - hsync;
506
507 vodd_front_porch_lines = GTF_MIN_V_PORCH ;
508
509
510 drm_mode->hdisplay = hdisplay_rnd;
511 drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
512 drm_mode->hsync_end = drm_mode->hsync_start + hsync;
513 drm_mode->htotal = total_pixels;
514 drm_mode->vdisplay = vdisplay_rnd;
515 drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
516 drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
517 drm_mode->vtotal = vtotal_lines;
518
519 drm_mode->clock = pixel_freq;
520
521 if (interlaced) {
522 drm_mode->vtotal *= 2;
523 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
524 }
525
526 drm_mode_set_name(drm_mode);
527 if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
528 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
529 else
530 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
531
532 return drm_mode;
533}
534EXPORT_SYMBOL(drm_gtf_mode_complex);
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
568
569
570struct drm_display_mode *
571drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
572 bool interlaced, int margins)
573{
574 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
575 interlaced, margins,
576 600, 40 * 2, 128, 20 * 2);
577}
578EXPORT_SYMBOL(drm_gtf_mode);
579
580#ifdef CONFIG_VIDEOMODE_HELPERS
581
582
583
584
585
586
587
588void drm_display_mode_from_videomode(const struct videomode *vm,
589 struct drm_display_mode *dmode)
590{
591 dmode->hdisplay = vm->hactive;
592 dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
593 dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
594 dmode->htotal = dmode->hsync_end + vm->hback_porch;
595
596 dmode->vdisplay = vm->vactive;
597 dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
598 dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
599 dmode->vtotal = dmode->vsync_end + vm->vback_porch;
600
601 dmode->clock = vm->pixelclock / 1000;
602
603 dmode->flags = 0;
604 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
605 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
606 else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
607 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
608 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
609 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
610 else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
611 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
612 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
613 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
614 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
615 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
616 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
617 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
618 drm_mode_set_name(dmode);
619}
620EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
621
622
623
624
625
626
627
628
629void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
630 struct videomode *vm)
631{
632 vm->hactive = dmode->hdisplay;
633 vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
634 vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
635 vm->hback_porch = dmode->htotal - dmode->hsync_end;
636
637 vm->vactive = dmode->vdisplay;
638 vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
639 vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
640 vm->vback_porch = dmode->vtotal - dmode->vsync_end;
641
642 vm->pixelclock = dmode->clock * 1000;
643
644 vm->flags = 0;
645 if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
646 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
647 else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
648 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
649 if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
650 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
651 else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
652 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
653 if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
654 vm->flags |= DISPLAY_FLAGS_INTERLACED;
655 if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
656 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
657 if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
658 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
659}
660EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
661
662
663
664
665
666
667
668
669
670
671
672
673void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
674{
675 *bus_flags = 0;
676 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
677 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
678 if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
679 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
680
681 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
682 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
683 if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
684 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
685
686 if (vm->flags & DISPLAY_FLAGS_DE_LOW)
687 *bus_flags |= DRM_BUS_FLAG_DE_LOW;
688 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
689 *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
690}
691EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
692
693#ifdef CONFIG_OF
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708int of_get_drm_display_mode(struct device_node *np,
709 struct drm_display_mode *dmode, u32 *bus_flags,
710 int index)
711{
712 struct videomode vm;
713 int ret;
714
715 ret = of_get_videomode(np, &vm, index);
716 if (ret)
717 return ret;
718
719 drm_display_mode_from_videomode(&vm, dmode);
720 if (bus_flags)
721 drm_bus_flags_from_videomode(&vm, bus_flags);
722
723 pr_debug("%pOF: got %dx%d display mode\n",
724 np, vm.hactive, vm.vactive);
725 drm_mode_debug_printmodeline(dmode);
726
727 return 0;
728}
729EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
730#endif
731#endif
732
733
734
735
736
737
738
739
740void drm_mode_set_name(struct drm_display_mode *mode)
741{
742 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
743
744 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
745 mode->hdisplay, mode->vdisplay,
746 interlaced ? "i" : "");
747}
748EXPORT_SYMBOL(drm_mode_set_name);
749
750
751
752
753
754
755
756
757
758int drm_mode_hsync(const struct drm_display_mode *mode)
759{
760 unsigned int calc_val;
761
762 if (mode->hsync)
763 return mode->hsync;
764
765 if (mode->htotal <= 0)
766 return 0;
767
768 calc_val = (mode->clock * 1000) / mode->htotal;
769 calc_val += 500;
770 calc_val /= 1000;
771
772 return calc_val;
773}
774EXPORT_SYMBOL(drm_mode_hsync);
775
776
777
778
779
780
781
782
783
784int drm_mode_vrefresh(const struct drm_display_mode *mode)
785{
786 int refresh = 0;
787
788 if (mode->vrefresh > 0)
789 refresh = mode->vrefresh;
790 else if (mode->htotal > 0 && mode->vtotal > 0) {
791 unsigned int num, den;
792
793 num = mode->clock * 1000;
794 den = mode->htotal * mode->vtotal;
795
796 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
797 num *= 2;
798 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
799 den *= 2;
800 if (mode->vscan > 1)
801 den *= mode->vscan;
802
803 refresh = DIV_ROUND_CLOSEST(num, den);
804 }
805 return refresh;
806}
807EXPORT_SYMBOL(drm_mode_vrefresh);
808
809
810
811
812
813
814
815
816
817
818void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
819 int *hdisplay, int *vdisplay)
820{
821 struct drm_display_mode adjusted = *mode;
822
823 drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
824 *hdisplay = adjusted.crtc_hdisplay;
825 *vdisplay = adjusted.crtc_vdisplay;
826}
827EXPORT_SYMBOL(drm_mode_get_hv_timing);
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
845{
846 if (!p)
847 return;
848
849 p->crtc_clock = p->clock;
850 p->crtc_hdisplay = p->hdisplay;
851 p->crtc_hsync_start = p->hsync_start;
852 p->crtc_hsync_end = p->hsync_end;
853 p->crtc_htotal = p->htotal;
854 p->crtc_hskew = p->hskew;
855 p->crtc_vdisplay = p->vdisplay;
856 p->crtc_vsync_start = p->vsync_start;
857 p->crtc_vsync_end = p->vsync_end;
858 p->crtc_vtotal = p->vtotal;
859
860 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
861 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
862 p->crtc_vdisplay /= 2;
863 p->crtc_vsync_start /= 2;
864 p->crtc_vsync_end /= 2;
865 p->crtc_vtotal /= 2;
866 }
867 }
868
869 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
870 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
871 p->crtc_vdisplay *= 2;
872 p->crtc_vsync_start *= 2;
873 p->crtc_vsync_end *= 2;
874 p->crtc_vtotal *= 2;
875 }
876 }
877
878 if (!(adjust_flags & CRTC_NO_VSCAN)) {
879 if (p->vscan > 1) {
880 p->crtc_vdisplay *= p->vscan;
881 p->crtc_vsync_start *= p->vscan;
882 p->crtc_vsync_end *= p->vscan;
883 p->crtc_vtotal *= p->vscan;
884 }
885 }
886
887 if (adjust_flags & CRTC_STEREO_DOUBLE) {
888 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
889
890 switch (layout) {
891 case DRM_MODE_FLAG_3D_FRAME_PACKING:
892 p->crtc_clock *= 2;
893 p->crtc_vdisplay += p->crtc_vtotal;
894 p->crtc_vsync_start += p->crtc_vtotal;
895 p->crtc_vsync_end += p->crtc_vtotal;
896 p->crtc_vtotal += p->crtc_vtotal;
897 break;
898 }
899 }
900
901 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
902 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
903 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
904 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
905}
906EXPORT_SYMBOL(drm_mode_set_crtcinfo);
907
908
909
910
911
912
913
914
915
916void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
917{
918 struct list_head head = dst->head;
919
920 *dst = *src;
921 dst->head = head;
922}
923EXPORT_SYMBOL(drm_mode_copy);
924
925
926
927
928
929
930
931
932
933
934
935
936struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
937 const struct drm_display_mode *mode)
938{
939 struct drm_display_mode *nmode;
940
941 nmode = drm_mode_create(dev);
942 if (!nmode)
943 return NULL;
944
945 drm_mode_copy(nmode, mode);
946
947 return nmode;
948}
949EXPORT_SYMBOL(drm_mode_duplicate);
950
951static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
952 const struct drm_display_mode *mode2)
953{
954 return mode1->hdisplay == mode2->hdisplay &&
955 mode1->hsync_start == mode2->hsync_start &&
956 mode1->hsync_end == mode2->hsync_end &&
957 mode1->htotal == mode2->htotal &&
958 mode1->hskew == mode2->hskew &&
959 mode1->vdisplay == mode2->vdisplay &&
960 mode1->vsync_start == mode2->vsync_start &&
961 mode1->vsync_end == mode2->vsync_end &&
962 mode1->vtotal == mode2->vtotal &&
963 mode1->vscan == mode2->vscan;
964}
965
966static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
967 const struct drm_display_mode *mode2)
968{
969
970
971
972
973 if (mode1->clock && mode2->clock)
974 return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
975 else
976 return mode1->clock == mode2->clock;
977}
978
979static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
980 const struct drm_display_mode *mode2)
981{
982 return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
983 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
984}
985
986static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
987 const struct drm_display_mode *mode2)
988{
989 return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
990 (mode2->flags & DRM_MODE_FLAG_3D_MASK);
991}
992
993static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
994 const struct drm_display_mode *mode2)
995{
996 return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
997}
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010bool drm_mode_match(const struct drm_display_mode *mode1,
1011 const struct drm_display_mode *mode2,
1012 unsigned int match_flags)
1013{
1014 if (!mode1 && !mode2)
1015 return true;
1016
1017 if (!mode1 || !mode2)
1018 return false;
1019
1020 if (match_flags & DRM_MODE_MATCH_TIMINGS &&
1021 !drm_mode_match_timings(mode1, mode2))
1022 return false;
1023
1024 if (match_flags & DRM_MODE_MATCH_CLOCK &&
1025 !drm_mode_match_clock(mode1, mode2))
1026 return false;
1027
1028 if (match_flags & DRM_MODE_MATCH_FLAGS &&
1029 !drm_mode_match_flags(mode1, mode2))
1030 return false;
1031
1032 if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
1033 !drm_mode_match_3d_flags(mode1, mode2))
1034 return false;
1035
1036 if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
1037 !drm_mode_match_aspect_ratio(mode1, mode2))
1038 return false;
1039
1040 return true;
1041}
1042EXPORT_SYMBOL(drm_mode_match);
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054bool drm_mode_equal(const struct drm_display_mode *mode1,
1055 const struct drm_display_mode *mode2)
1056{
1057 return drm_mode_match(mode1, mode2,
1058 DRM_MODE_MATCH_TIMINGS |
1059 DRM_MODE_MATCH_CLOCK |
1060 DRM_MODE_MATCH_FLAGS |
1061 DRM_MODE_MATCH_3D_FLAGS|
1062 DRM_MODE_MATCH_ASPECT_RATIO);
1063}
1064EXPORT_SYMBOL(drm_mode_equal);
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
1078 const struct drm_display_mode *mode2)
1079{
1080 return drm_mode_match(mode1, mode2,
1081 DRM_MODE_MATCH_TIMINGS |
1082 DRM_MODE_MATCH_FLAGS |
1083 DRM_MODE_MATCH_3D_FLAGS);
1084}
1085EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
1099 const struct drm_display_mode *mode2)
1100{
1101 return drm_mode_match(mode1, mode2,
1102 DRM_MODE_MATCH_TIMINGS |
1103 DRM_MODE_MATCH_FLAGS);
1104}
1105EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1106
1107static enum drm_mode_status
1108drm_mode_validate_basic(const struct drm_display_mode *mode)
1109{
1110 if (mode->type & ~DRM_MODE_TYPE_ALL)
1111 return MODE_BAD;
1112
1113 if (mode->flags & ~DRM_MODE_FLAG_ALL)
1114 return MODE_BAD;
1115
1116 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1117 return MODE_BAD;
1118
1119 if (mode->clock == 0)
1120 return MODE_CLOCK_LOW;
1121
1122 if (mode->hdisplay == 0 ||
1123 mode->hsync_start < mode->hdisplay ||
1124 mode->hsync_end < mode->hsync_start ||
1125 mode->htotal < mode->hsync_end)
1126 return MODE_H_ILLEGAL;
1127
1128 if (mode->vdisplay == 0 ||
1129 mode->vsync_start < mode->vdisplay ||
1130 mode->vsync_end < mode->vsync_start ||
1131 mode->vtotal < mode->vsync_end)
1132 return MODE_V_ILLEGAL;
1133
1134 return MODE_OK;
1135}
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149enum drm_mode_status
1150drm_mode_validate_driver(struct drm_device *dev,
1151 const struct drm_display_mode *mode)
1152{
1153 enum drm_mode_status status;
1154
1155 status = drm_mode_validate_basic(mode);
1156 if (status != MODE_OK)
1157 return status;
1158
1159 if (dev->mode_config.funcs->mode_valid)
1160 return dev->mode_config.funcs->mode_valid(dev, mode);
1161 else
1162 return MODE_OK;
1163}
1164EXPORT_SYMBOL(drm_mode_validate_driver);
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180enum drm_mode_status
1181drm_mode_validate_size(const struct drm_display_mode *mode,
1182 int maxX, int maxY)
1183{
1184 if (maxX > 0 && mode->hdisplay > maxX)
1185 return MODE_VIRTUAL_X;
1186
1187 if (maxY > 0 && mode->vdisplay > maxY)
1188 return MODE_VIRTUAL_Y;
1189
1190 return MODE_OK;
1191}
1192EXPORT_SYMBOL(drm_mode_validate_size);
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205enum drm_mode_status
1206drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
1207 struct drm_connector *connector)
1208{
1209 u8 vic = drm_match_cea_mode(mode);
1210 enum drm_mode_status status = MODE_OK;
1211 struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;
1212
1213 if (test_bit(vic, hdmi->y420_vdb_modes)) {
1214 if (!connector->ycbcr_420_allowed)
1215 status = MODE_NO_420;
1216 }
1217
1218 return status;
1219}
1220EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1221
1222#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1223
1224static const char * const drm_mode_status_names[] = {
1225 MODE_STATUS(OK),
1226 MODE_STATUS(HSYNC),
1227 MODE_STATUS(VSYNC),
1228 MODE_STATUS(H_ILLEGAL),
1229 MODE_STATUS(V_ILLEGAL),
1230 MODE_STATUS(BAD_WIDTH),
1231 MODE_STATUS(NOMODE),
1232 MODE_STATUS(NO_INTERLACE),
1233 MODE_STATUS(NO_DBLESCAN),
1234 MODE_STATUS(NO_VSCAN),
1235 MODE_STATUS(MEM),
1236 MODE_STATUS(VIRTUAL_X),
1237 MODE_STATUS(VIRTUAL_Y),
1238 MODE_STATUS(MEM_VIRT),
1239 MODE_STATUS(NOCLOCK),
1240 MODE_STATUS(CLOCK_HIGH),
1241 MODE_STATUS(CLOCK_LOW),
1242 MODE_STATUS(CLOCK_RANGE),
1243 MODE_STATUS(BAD_HVALUE),
1244 MODE_STATUS(BAD_VVALUE),
1245 MODE_STATUS(BAD_VSCAN),
1246 MODE_STATUS(HSYNC_NARROW),
1247 MODE_STATUS(HSYNC_WIDE),
1248 MODE_STATUS(HBLANK_NARROW),
1249 MODE_STATUS(HBLANK_WIDE),
1250 MODE_STATUS(VSYNC_NARROW),
1251 MODE_STATUS(VSYNC_WIDE),
1252 MODE_STATUS(VBLANK_NARROW),
1253 MODE_STATUS(VBLANK_WIDE),
1254 MODE_STATUS(PANEL),
1255 MODE_STATUS(INTERLACE_WIDTH),
1256 MODE_STATUS(ONE_WIDTH),
1257 MODE_STATUS(ONE_HEIGHT),
1258 MODE_STATUS(ONE_SIZE),
1259 MODE_STATUS(NO_REDUCED),
1260 MODE_STATUS(NO_STEREO),
1261 MODE_STATUS(NO_420),
1262 MODE_STATUS(STALE),
1263 MODE_STATUS(BAD),
1264 MODE_STATUS(ERROR),
1265};
1266
1267#undef MODE_STATUS
1268
1269const char *drm_get_mode_status_name(enum drm_mode_status status)
1270{
1271 int index = status + 3;
1272
1273 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1274 return "";
1275
1276 return drm_mode_status_names[index];
1277}
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290void drm_mode_prune_invalid(struct drm_device *dev,
1291 struct list_head *mode_list, bool verbose)
1292{
1293 struct drm_display_mode *mode, *t;
1294
1295 list_for_each_entry_safe(mode, t, mode_list, head) {
1296 if (mode->status != MODE_OK) {
1297 list_del(&mode->head);
1298 if (verbose) {
1299 drm_mode_debug_printmodeline(mode);
1300 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1301 mode->name,
1302 drm_get_mode_status_name(mode->status));
1303 }
1304 drm_mode_destroy(dev, mode);
1305 }
1306 }
1307}
1308EXPORT_SYMBOL(drm_mode_prune_invalid);
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
1324{
1325 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1326 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1327 int diff;
1328
1329 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1330 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1331 if (diff)
1332 return diff;
1333 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1334 if (diff)
1335 return diff;
1336
1337 diff = b->vrefresh - a->vrefresh;
1338 if (diff)
1339 return diff;
1340
1341 diff = b->clock - a->clock;
1342 return diff;
1343}
1344
1345
1346
1347
1348
1349
1350
1351void drm_mode_sort(struct list_head *mode_list)
1352{
1353 list_sort(NULL, mode_list, drm_mode_compare);
1354}
1355EXPORT_SYMBOL(drm_mode_sort);
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368void drm_connector_list_update(struct drm_connector *connector)
1369{
1370 struct drm_display_mode *pmode, *pt;
1371
1372 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1373
1374 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1375 struct drm_display_mode *mode;
1376 bool found_it = false;
1377
1378
1379 list_for_each_entry(mode, &connector->modes, head) {
1380 if (!drm_mode_equal(pmode, mode))
1381 continue;
1382
1383 found_it = true;
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397 if (mode->status == MODE_STALE) {
1398 drm_mode_copy(mode, pmode);
1399 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1400 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1401 pmode->type |= mode->type;
1402 drm_mode_copy(mode, pmode);
1403 } else {
1404 mode->type |= pmode->type;
1405 }
1406
1407 list_del(&pmode->head);
1408 drm_mode_destroy(connector->dev, pmode);
1409 break;
1410 }
1411
1412 if (!found_it) {
1413 list_move_tail(&pmode->head, &connector->modes);
1414 }
1415 }
1416}
1417EXPORT_SYMBOL(drm_connector_list_update);
1418
1419static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
1420 struct drm_cmdline_mode *mode)
1421{
1422 unsigned int bpp;
1423
1424 if (str[0] != '-')
1425 return -EINVAL;
1426
1427 str++;
1428 bpp = simple_strtol(str, end_ptr, 10);
1429 if (*end_ptr == str)
1430 return -EINVAL;
1431
1432 mode->bpp = bpp;
1433 mode->bpp_specified = true;
1434
1435 return 0;
1436}
1437
1438static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
1439 struct drm_cmdline_mode *mode)
1440{
1441 unsigned int refresh;
1442
1443 if (str[0] != '@')
1444 return -EINVAL;
1445
1446 str++;
1447 refresh = simple_strtol(str, end_ptr, 10);
1448 if (*end_ptr == str)
1449 return -EINVAL;
1450
1451 mode->refresh = refresh;
1452 mode->refresh_specified = true;
1453
1454 return 0;
1455}
1456
1457static int drm_mode_parse_cmdline_extra(const char *str, int length,
1458 bool freestanding,
1459 const struct drm_connector *connector,
1460 struct drm_cmdline_mode *mode)
1461{
1462 int i;
1463
1464 for (i = 0; i < length; i++) {
1465 switch (str[i]) {
1466 case 'i':
1467 if (freestanding)
1468 return -EINVAL;
1469
1470 mode->interlace = true;
1471 break;
1472 case 'm':
1473 if (freestanding)
1474 return -EINVAL;
1475
1476 mode->margins = true;
1477 break;
1478 case 'D':
1479 if (mode->force != DRM_FORCE_UNSPECIFIED)
1480 return -EINVAL;
1481
1482 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1483 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1484 mode->force = DRM_FORCE_ON;
1485 else
1486 mode->force = DRM_FORCE_ON_DIGITAL;
1487 break;
1488 case 'd':
1489 if (mode->force != DRM_FORCE_UNSPECIFIED)
1490 return -EINVAL;
1491
1492 mode->force = DRM_FORCE_OFF;
1493 break;
1494 case 'e':
1495 if (mode->force != DRM_FORCE_UNSPECIFIED)
1496 return -EINVAL;
1497
1498 mode->force = DRM_FORCE_ON;
1499 break;
1500 default:
1501 return -EINVAL;
1502 }
1503 }
1504
1505 return 0;
1506}
1507
1508static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
1509 bool extras,
1510 const struct drm_connector *connector,
1511 struct drm_cmdline_mode *mode)
1512{
1513 const char *str_start = str;
1514 bool rb = false, cvt = false;
1515 int xres = 0, yres = 0;
1516 int remaining, i;
1517 char *end_ptr;
1518
1519 xres = simple_strtol(str, &end_ptr, 10);
1520 if (end_ptr == str)
1521 return -EINVAL;
1522
1523 if (end_ptr[0] != 'x')
1524 return -EINVAL;
1525 end_ptr++;
1526
1527 str = end_ptr;
1528 yres = simple_strtol(str, &end_ptr, 10);
1529 if (end_ptr == str)
1530 return -EINVAL;
1531
1532 remaining = length - (end_ptr - str_start);
1533 if (remaining < 0)
1534 return -EINVAL;
1535
1536 for (i = 0; i < remaining; i++) {
1537 switch (end_ptr[i]) {
1538 case 'M':
1539 cvt = true;
1540 break;
1541 case 'R':
1542 rb = true;
1543 break;
1544 default:
1545
1546
1547
1548
1549
1550 if (extras) {
1551 int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
1552 1,
1553 false,
1554 connector,
1555 mode);
1556 if (ret)
1557 return ret;
1558 } else {
1559 return -EINVAL;
1560 }
1561 }
1562 }
1563
1564 mode->xres = xres;
1565 mode->yres = yres;
1566 mode->cvt = cvt;
1567 mode->rb = rb;
1568
1569 return 0;
1570}
1571
1572static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
1573{
1574 const char *value;
1575 char *endp;
1576
1577
1578
1579
1580
1581
1582 if (*delim != '=')
1583 return -EINVAL;
1584
1585 value = delim + 1;
1586 *int_ret = simple_strtol(value, &endp, 10);
1587
1588
1589 if (endp == value)
1590 return -EINVAL;
1591
1592 return 0;
1593}
1594
1595static int drm_mode_parse_panel_orientation(const char *delim,
1596 struct drm_cmdline_mode *mode)
1597{
1598 const char *value;
1599
1600 if (*delim != '=')
1601 return -EINVAL;
1602
1603 value = delim + 1;
1604 delim = strchr(value, ',');
1605 if (!delim)
1606 delim = value + strlen(value);
1607
1608 if (!strncmp(value, "normal", delim - value))
1609 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
1610 else if (!strncmp(value, "upside_down", delim - value))
1611 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1612 else if (!strncmp(value, "left_side_up", delim - value))
1613 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
1614 else if (!strncmp(value, "right_side_up", delim - value))
1615 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
1616 else
1617 return -EINVAL;
1618
1619 return 0;
1620}
1621
1622static int drm_mode_parse_cmdline_options(const char *str,
1623 bool freestanding,
1624 const struct drm_connector *connector,
1625 struct drm_cmdline_mode *mode)
1626{
1627 unsigned int deg, margin, rotation = 0;
1628 const char *delim, *option, *sep;
1629
1630 option = str;
1631 do {
1632 delim = strchr(option, '=');
1633 if (!delim) {
1634 delim = strchr(option, ',');
1635
1636 if (!delim)
1637 delim = option + strlen(option);
1638 }
1639
1640 if (!strncmp(option, "rotate", delim - option)) {
1641 if (drm_mode_parse_cmdline_int(delim, °))
1642 return -EINVAL;
1643
1644 switch (deg) {
1645 case 0:
1646 rotation |= DRM_MODE_ROTATE_0;
1647 break;
1648
1649 case 90:
1650 rotation |= DRM_MODE_ROTATE_90;
1651 break;
1652
1653 case 180:
1654 rotation |= DRM_MODE_ROTATE_180;
1655 break;
1656
1657 case 270:
1658 rotation |= DRM_MODE_ROTATE_270;
1659 break;
1660
1661 default:
1662 return -EINVAL;
1663 }
1664 } else if (!strncmp(option, "reflect_x", delim - option)) {
1665 rotation |= DRM_MODE_REFLECT_X;
1666 } else if (!strncmp(option, "reflect_y", delim - option)) {
1667 rotation |= DRM_MODE_REFLECT_Y;
1668 } else if (!strncmp(option, "margin_right", delim - option)) {
1669 if (drm_mode_parse_cmdline_int(delim, &margin))
1670 return -EINVAL;
1671
1672 mode->tv_margins.right = margin;
1673 } else if (!strncmp(option, "margin_left", delim - option)) {
1674 if (drm_mode_parse_cmdline_int(delim, &margin))
1675 return -EINVAL;
1676
1677 mode->tv_margins.left = margin;
1678 } else if (!strncmp(option, "margin_top", delim - option)) {
1679 if (drm_mode_parse_cmdline_int(delim, &margin))
1680 return -EINVAL;
1681
1682 mode->tv_margins.top = margin;
1683 } else if (!strncmp(option, "margin_bottom", delim - option)) {
1684 if (drm_mode_parse_cmdline_int(delim, &margin))
1685 return -EINVAL;
1686
1687 mode->tv_margins.bottom = margin;
1688 } else if (!strncmp(option, "panel_orientation", delim - option)) {
1689 if (drm_mode_parse_panel_orientation(delim, mode))
1690 return -EINVAL;
1691 } else {
1692 return -EINVAL;
1693 }
1694 sep = strchr(delim, ',');
1695 option = sep + 1;
1696 } while (sep);
1697
1698 if (rotation && freestanding)
1699 return -EINVAL;
1700
1701 if (!(rotation & DRM_MODE_ROTATE_MASK))
1702 rotation |= DRM_MODE_ROTATE_0;
1703
1704
1705 if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
1706 return -EINVAL;
1707
1708 mode->rotation_reflection = rotation;
1709
1710 return 0;
1711}
1712
1713static const char * const drm_named_modes_whitelist[] = {
1714 "NTSC",
1715 "PAL",
1716};
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1744 const struct drm_connector *connector,
1745 struct drm_cmdline_mode *mode)
1746{
1747 const char *name;
1748 bool freestanding = false, parse_extras = false;
1749 unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
1750 unsigned int mode_end = 0;
1751 const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
1752 const char *options_ptr = NULL;
1753 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
1754 int i, len, ret;
1755
1756 memset(mode, 0, sizeof(*mode));
1757 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1758
1759 if (!mode_option)
1760 return false;
1761
1762 name = mode_option;
1763
1764
1765 bpp_ptr = strchr(name, '-');
1766 if (bpp_ptr)
1767 bpp_off = bpp_ptr - name;
1768
1769 refresh_ptr = strchr(name, '@');
1770 if (refresh_ptr)
1771 refresh_off = refresh_ptr - name;
1772
1773
1774 options_ptr = strchr(name, ',');
1775 if (options_ptr)
1776 options_off = options_ptr - name;
1777
1778
1779 if (bpp_ptr) {
1780 mode_end = bpp_off;
1781 } else if (refresh_ptr) {
1782 mode_end = refresh_off;
1783 } else if (options_ptr) {
1784 mode_end = options_off;
1785 parse_extras = true;
1786 } else {
1787 mode_end = strlen(name);
1788 parse_extras = true;
1789 }
1790
1791
1792 for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
1793 ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
1794 if (ret == mode_end) {
1795 if (refresh_ptr)
1796 return false;
1797
1798 strcpy(mode->name, drm_named_modes_whitelist[i]);
1799 mode->specified = true;
1800 break;
1801 }
1802 }
1803
1804
1805 if (!mode->specified && isdigit(name[0])) {
1806 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
1807 parse_extras,
1808 connector,
1809 mode);
1810 if (ret)
1811 return false;
1812
1813 mode->specified = true;
1814 }
1815
1816
1817 if (!mode->specified) {
1818 unsigned int len = strlen(mode_option);
1819
1820 if (bpp_ptr || refresh_ptr)
1821 return false;
1822
1823 if (len == 1 || (len >= 2 && mode_option[1] == ','))
1824 extra_ptr = mode_option;
1825 else
1826 options_ptr = mode_option - 1;
1827
1828 freestanding = true;
1829 }
1830
1831 if (bpp_ptr) {
1832 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
1833 if (ret)
1834 return false;
1835
1836 mode->bpp_specified = true;
1837 }
1838
1839 if (refresh_ptr) {
1840 ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
1841 &refresh_end_ptr, mode);
1842 if (ret)
1843 return false;
1844
1845 mode->refresh_specified = true;
1846 }
1847
1848
1849
1850
1851
1852 if (bpp_ptr && refresh_ptr)
1853 extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
1854 else if (bpp_ptr)
1855 extra_ptr = bpp_end_ptr;
1856 else if (refresh_ptr)
1857 extra_ptr = refresh_end_ptr;
1858
1859 if (extra_ptr) {
1860 if (options_ptr)
1861 len = options_ptr - extra_ptr;
1862 else
1863 len = strlen(extra_ptr);
1864
1865 ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
1866 connector, mode);
1867 if (ret)
1868 return false;
1869 }
1870
1871 if (options_ptr) {
1872 ret = drm_mode_parse_cmdline_options(options_ptr + 1,
1873 freestanding,
1874 connector, mode);
1875 if (ret)
1876 return false;
1877 }
1878
1879 return true;
1880}
1881EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891struct drm_display_mode *
1892drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1893 struct drm_cmdline_mode *cmd)
1894{
1895 struct drm_display_mode *mode;
1896
1897 if (cmd->cvt)
1898 mode = drm_cvt_mode(dev,
1899 cmd->xres, cmd->yres,
1900 cmd->refresh_specified ? cmd->refresh : 60,
1901 cmd->rb, cmd->interlace,
1902 cmd->margins);
1903 else
1904 mode = drm_gtf_mode(dev,
1905 cmd->xres, cmd->yres,
1906 cmd->refresh_specified ? cmd->refresh : 60,
1907 cmd->interlace,
1908 cmd->margins);
1909 if (!mode)
1910 return NULL;
1911
1912 mode->type |= DRM_MODE_TYPE_USERDEF;
1913
1914 if (cmd->xres == 1366)
1915 drm_mode_fixup_1366x768(mode);
1916 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1917 return mode;
1918}
1919EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1930 const struct drm_display_mode *in)
1931{
1932 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1933 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1934 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1935 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1936 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1937 "timing values too large for mode info\n");
1938
1939 out->clock = in->clock;
1940 out->hdisplay = in->hdisplay;
1941 out->hsync_start = in->hsync_start;
1942 out->hsync_end = in->hsync_end;
1943 out->htotal = in->htotal;
1944 out->hskew = in->hskew;
1945 out->vdisplay = in->vdisplay;
1946 out->vsync_start = in->vsync_start;
1947 out->vsync_end = in->vsync_end;
1948 out->vtotal = in->vtotal;
1949 out->vscan = in->vscan;
1950 out->vrefresh = in->vrefresh;
1951 out->flags = in->flags;
1952 out->type = in->type;
1953
1954 switch (in->picture_aspect_ratio) {
1955 case HDMI_PICTURE_ASPECT_4_3:
1956 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
1957 break;
1958 case HDMI_PICTURE_ASPECT_16_9:
1959 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
1960 break;
1961 case HDMI_PICTURE_ASPECT_64_27:
1962 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
1963 break;
1964 case HDMI_PICTURE_ASPECT_256_135:
1965 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
1966 break;
1967 default:
1968 WARN(1, "Invalid aspect ratio (0%x) on mode\n",
1969 in->picture_aspect_ratio);
1970
1971 case HDMI_PICTURE_ASPECT_NONE:
1972 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
1973 break;
1974 }
1975
1976 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1977 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1978}
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992int drm_mode_convert_umode(struct drm_device *dev,
1993 struct drm_display_mode *out,
1994 const struct drm_mode_modeinfo *in)
1995{
1996 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1997 return -ERANGE;
1998
1999 out->clock = in->clock;
2000 out->hdisplay = in->hdisplay;
2001 out->hsync_start = in->hsync_start;
2002 out->hsync_end = in->hsync_end;
2003 out->htotal = in->htotal;
2004 out->hskew = in->hskew;
2005 out->vdisplay = in->vdisplay;
2006 out->vsync_start = in->vsync_start;
2007 out->vsync_end = in->vsync_end;
2008 out->vtotal = in->vtotal;
2009 out->vscan = in->vscan;
2010 out->vrefresh = in->vrefresh;
2011 out->flags = in->flags;
2012
2013
2014
2015
2016
2017
2018 out->type = in->type & DRM_MODE_TYPE_ALL;
2019 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
2020 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
2021
2022
2023
2024
2025
2026 out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
2027
2028 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
2029 case DRM_MODE_FLAG_PIC_AR_4_3:
2030 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
2031 break;
2032 case DRM_MODE_FLAG_PIC_AR_16_9:
2033 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
2034 break;
2035 case DRM_MODE_FLAG_PIC_AR_64_27:
2036 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
2037 break;
2038 case DRM_MODE_FLAG_PIC_AR_256_135:
2039 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
2040 break;
2041 case DRM_MODE_FLAG_PIC_AR_NONE:
2042 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
2043 break;
2044 default:
2045 return -EINVAL;
2046 }
2047
2048 out->status = drm_mode_validate_driver(dev, out);
2049 if (out->status != MODE_OK)
2050 return -EINVAL;
2051
2052 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
2053
2054 return 0;
2055}
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068bool drm_mode_is_420_only(const struct drm_display_info *display,
2069 const struct drm_display_mode *mode)
2070{
2071 u8 vic = drm_match_cea_mode(mode);
2072
2073 return test_bit(vic, display->hdmi.y420_vdb_modes);
2074}
2075EXPORT_SYMBOL(drm_mode_is_420_only);
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088bool drm_mode_is_420_also(const struct drm_display_info *display,
2089 const struct drm_display_mode *mode)
2090{
2091 u8 vic = drm_match_cea_mode(mode);
2092
2093 return test_bit(vic, display->hdmi.y420_cmdb_modes);
2094}
2095EXPORT_SYMBOL(drm_mode_is_420_also);
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107bool drm_mode_is_420(const struct drm_display_info *display,
2108 const struct drm_display_mode *mode)
2109{
2110 return drm_mode_is_420_only(display, mode) ||
2111 drm_mode_is_420_also(display, mode);
2112}
2113EXPORT_SYMBOL(drm_mode_is_420);
2114