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