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