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_vrefresh(const struct drm_display_mode *mode)
759{
760 unsigned int num, den;
761
762 if (mode->htotal == 0 || mode->vtotal == 0)
763 return 0;
764
765 num = mode->clock;
766 den = mode->htotal * mode->vtotal;
767
768 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
769 num *= 2;
770 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
771 den *= 2;
772 if (mode->vscan > 1)
773 den *= mode->vscan;
774
775 return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den);
776}
777EXPORT_SYMBOL(drm_mode_vrefresh);
778
779
780
781
782
783
784
785
786
787
788void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
789 int *hdisplay, int *vdisplay)
790{
791 struct drm_display_mode adjusted = *mode;
792
793 drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
794 *hdisplay = adjusted.crtc_hdisplay;
795 *vdisplay = adjusted.crtc_vdisplay;
796}
797EXPORT_SYMBOL(drm_mode_get_hv_timing);
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
815{
816 if (!p)
817 return;
818
819 p->crtc_clock = p->clock;
820 p->crtc_hdisplay = p->hdisplay;
821 p->crtc_hsync_start = p->hsync_start;
822 p->crtc_hsync_end = p->hsync_end;
823 p->crtc_htotal = p->htotal;
824 p->crtc_hskew = p->hskew;
825 p->crtc_vdisplay = p->vdisplay;
826 p->crtc_vsync_start = p->vsync_start;
827 p->crtc_vsync_end = p->vsync_end;
828 p->crtc_vtotal = p->vtotal;
829
830 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
831 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
832 p->crtc_vdisplay /= 2;
833 p->crtc_vsync_start /= 2;
834 p->crtc_vsync_end /= 2;
835 p->crtc_vtotal /= 2;
836 }
837 }
838
839 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
840 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
841 p->crtc_vdisplay *= 2;
842 p->crtc_vsync_start *= 2;
843 p->crtc_vsync_end *= 2;
844 p->crtc_vtotal *= 2;
845 }
846 }
847
848 if (!(adjust_flags & CRTC_NO_VSCAN)) {
849 if (p->vscan > 1) {
850 p->crtc_vdisplay *= p->vscan;
851 p->crtc_vsync_start *= p->vscan;
852 p->crtc_vsync_end *= p->vscan;
853 p->crtc_vtotal *= p->vscan;
854 }
855 }
856
857 if (adjust_flags & CRTC_STEREO_DOUBLE) {
858 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
859
860 switch (layout) {
861 case DRM_MODE_FLAG_3D_FRAME_PACKING:
862 p->crtc_clock *= 2;
863 p->crtc_vdisplay += p->crtc_vtotal;
864 p->crtc_vsync_start += p->crtc_vtotal;
865 p->crtc_vsync_end += p->crtc_vtotal;
866 p->crtc_vtotal += p->crtc_vtotal;
867 break;
868 }
869 }
870
871 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
872 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
873 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
874 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
875}
876EXPORT_SYMBOL(drm_mode_set_crtcinfo);
877
878
879
880
881
882
883
884
885
886void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
887{
888 struct list_head head = dst->head;
889
890 *dst = *src;
891 dst->head = head;
892}
893EXPORT_SYMBOL(drm_mode_copy);
894
895
896
897
898
899
900
901
902
903
904
905
906struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
907 const struct drm_display_mode *mode)
908{
909 struct drm_display_mode *nmode;
910
911 nmode = drm_mode_create(dev);
912 if (!nmode)
913 return NULL;
914
915 drm_mode_copy(nmode, mode);
916
917 return nmode;
918}
919EXPORT_SYMBOL(drm_mode_duplicate);
920
921static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
922 const struct drm_display_mode *mode2)
923{
924 return mode1->hdisplay == mode2->hdisplay &&
925 mode1->hsync_start == mode2->hsync_start &&
926 mode1->hsync_end == mode2->hsync_end &&
927 mode1->htotal == mode2->htotal &&
928 mode1->hskew == mode2->hskew &&
929 mode1->vdisplay == mode2->vdisplay &&
930 mode1->vsync_start == mode2->vsync_start &&
931 mode1->vsync_end == mode2->vsync_end &&
932 mode1->vtotal == mode2->vtotal &&
933 mode1->vscan == mode2->vscan;
934}
935
936static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
937 const struct drm_display_mode *mode2)
938{
939
940
941
942
943 if (mode1->clock && mode2->clock)
944 return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
945 else
946 return mode1->clock == mode2->clock;
947}
948
949static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
950 const struct drm_display_mode *mode2)
951{
952 return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
953 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
954}
955
956static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
957 const struct drm_display_mode *mode2)
958{
959 return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
960 (mode2->flags & DRM_MODE_FLAG_3D_MASK);
961}
962
963static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
964 const struct drm_display_mode *mode2)
965{
966 return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
967}
968
969
970
971
972
973
974
975
976
977
978
979
980bool drm_mode_match(const struct drm_display_mode *mode1,
981 const struct drm_display_mode *mode2,
982 unsigned int match_flags)
983{
984 if (!mode1 && !mode2)
985 return true;
986
987 if (!mode1 || !mode2)
988 return false;
989
990 if (match_flags & DRM_MODE_MATCH_TIMINGS &&
991 !drm_mode_match_timings(mode1, mode2))
992 return false;
993
994 if (match_flags & DRM_MODE_MATCH_CLOCK &&
995 !drm_mode_match_clock(mode1, mode2))
996 return false;
997
998 if (match_flags & DRM_MODE_MATCH_FLAGS &&
999 !drm_mode_match_flags(mode1, mode2))
1000 return false;
1001
1002 if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
1003 !drm_mode_match_3d_flags(mode1, mode2))
1004 return false;
1005
1006 if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
1007 !drm_mode_match_aspect_ratio(mode1, mode2))
1008 return false;
1009
1010 return true;
1011}
1012EXPORT_SYMBOL(drm_mode_match);
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024bool drm_mode_equal(const struct drm_display_mode *mode1,
1025 const struct drm_display_mode *mode2)
1026{
1027 return drm_mode_match(mode1, mode2,
1028 DRM_MODE_MATCH_TIMINGS |
1029 DRM_MODE_MATCH_CLOCK |
1030 DRM_MODE_MATCH_FLAGS |
1031 DRM_MODE_MATCH_3D_FLAGS|
1032 DRM_MODE_MATCH_ASPECT_RATIO);
1033}
1034EXPORT_SYMBOL(drm_mode_equal);
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
1048 const struct drm_display_mode *mode2)
1049{
1050 return drm_mode_match(mode1, mode2,
1051 DRM_MODE_MATCH_TIMINGS |
1052 DRM_MODE_MATCH_FLAGS |
1053 DRM_MODE_MATCH_3D_FLAGS);
1054}
1055EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
1069 const struct drm_display_mode *mode2)
1070{
1071 return drm_mode_match(mode1, mode2,
1072 DRM_MODE_MATCH_TIMINGS |
1073 DRM_MODE_MATCH_FLAGS);
1074}
1075EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1076
1077static enum drm_mode_status
1078drm_mode_validate_basic(const struct drm_display_mode *mode)
1079{
1080 if (mode->type & ~DRM_MODE_TYPE_ALL)
1081 return MODE_BAD;
1082
1083 if (mode->flags & ~DRM_MODE_FLAG_ALL)
1084 return MODE_BAD;
1085
1086 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1087 return MODE_BAD;
1088
1089 if (mode->clock == 0)
1090 return MODE_CLOCK_LOW;
1091
1092 if (mode->hdisplay == 0 ||
1093 mode->hsync_start < mode->hdisplay ||
1094 mode->hsync_end < mode->hsync_start ||
1095 mode->htotal < mode->hsync_end)
1096 return MODE_H_ILLEGAL;
1097
1098 if (mode->vdisplay == 0 ||
1099 mode->vsync_start < mode->vdisplay ||
1100 mode->vsync_end < mode->vsync_start ||
1101 mode->vtotal < mode->vsync_end)
1102 return MODE_V_ILLEGAL;
1103
1104 return MODE_OK;
1105}
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119enum drm_mode_status
1120drm_mode_validate_driver(struct drm_device *dev,
1121 const struct drm_display_mode *mode)
1122{
1123 enum drm_mode_status status;
1124
1125 status = drm_mode_validate_basic(mode);
1126 if (status != MODE_OK)
1127 return status;
1128
1129 if (dev->mode_config.funcs->mode_valid)
1130 return dev->mode_config.funcs->mode_valid(dev, mode);
1131 else
1132 return MODE_OK;
1133}
1134EXPORT_SYMBOL(drm_mode_validate_driver);
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150enum drm_mode_status
1151drm_mode_validate_size(const struct drm_display_mode *mode,
1152 int maxX, int maxY)
1153{
1154 if (maxX > 0 && mode->hdisplay > maxX)
1155 return MODE_VIRTUAL_X;
1156
1157 if (maxY > 0 && mode->vdisplay > maxY)
1158 return MODE_VIRTUAL_Y;
1159
1160 return MODE_OK;
1161}
1162EXPORT_SYMBOL(drm_mode_validate_size);
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175enum drm_mode_status
1176drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
1177 struct drm_connector *connector)
1178{
1179 if (!connector->ycbcr_420_allowed &&
1180 drm_mode_is_420_only(&connector->display_info, mode))
1181 return MODE_NO_420;
1182
1183 return MODE_OK;
1184}
1185EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1186
1187#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1188
1189static const char * const drm_mode_status_names[] = {
1190 MODE_STATUS(OK),
1191 MODE_STATUS(HSYNC),
1192 MODE_STATUS(VSYNC),
1193 MODE_STATUS(H_ILLEGAL),
1194 MODE_STATUS(V_ILLEGAL),
1195 MODE_STATUS(BAD_WIDTH),
1196 MODE_STATUS(NOMODE),
1197 MODE_STATUS(NO_INTERLACE),
1198 MODE_STATUS(NO_DBLESCAN),
1199 MODE_STATUS(NO_VSCAN),
1200 MODE_STATUS(MEM),
1201 MODE_STATUS(VIRTUAL_X),
1202 MODE_STATUS(VIRTUAL_Y),
1203 MODE_STATUS(MEM_VIRT),
1204 MODE_STATUS(NOCLOCK),
1205 MODE_STATUS(CLOCK_HIGH),
1206 MODE_STATUS(CLOCK_LOW),
1207 MODE_STATUS(CLOCK_RANGE),
1208 MODE_STATUS(BAD_HVALUE),
1209 MODE_STATUS(BAD_VVALUE),
1210 MODE_STATUS(BAD_VSCAN),
1211 MODE_STATUS(HSYNC_NARROW),
1212 MODE_STATUS(HSYNC_WIDE),
1213 MODE_STATUS(HBLANK_NARROW),
1214 MODE_STATUS(HBLANK_WIDE),
1215 MODE_STATUS(VSYNC_NARROW),
1216 MODE_STATUS(VSYNC_WIDE),
1217 MODE_STATUS(VBLANK_NARROW),
1218 MODE_STATUS(VBLANK_WIDE),
1219 MODE_STATUS(PANEL),
1220 MODE_STATUS(INTERLACE_WIDTH),
1221 MODE_STATUS(ONE_WIDTH),
1222 MODE_STATUS(ONE_HEIGHT),
1223 MODE_STATUS(ONE_SIZE),
1224 MODE_STATUS(NO_REDUCED),
1225 MODE_STATUS(NO_STEREO),
1226 MODE_STATUS(NO_420),
1227 MODE_STATUS(STALE),
1228 MODE_STATUS(BAD),
1229 MODE_STATUS(ERROR),
1230};
1231
1232#undef MODE_STATUS
1233
1234const char *drm_get_mode_status_name(enum drm_mode_status status)
1235{
1236 int index = status + 3;
1237
1238 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1239 return "";
1240
1241 return drm_mode_status_names[index];
1242}
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255void drm_mode_prune_invalid(struct drm_device *dev,
1256 struct list_head *mode_list, bool verbose)
1257{
1258 struct drm_display_mode *mode, *t;
1259
1260 list_for_each_entry_safe(mode, t, mode_list, head) {
1261 if (mode->status != MODE_OK) {
1262 list_del(&mode->head);
1263 if (verbose) {
1264 drm_mode_debug_printmodeline(mode);
1265 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1266 mode->name,
1267 drm_get_mode_status_name(mode->status));
1268 }
1269 drm_mode_destroy(dev, mode);
1270 }
1271 }
1272}
1273EXPORT_SYMBOL(drm_mode_prune_invalid);
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288static int drm_mode_compare(void *priv, const struct list_head *lh_a,
1289 const struct list_head *lh_b)
1290{
1291 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1292 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1293 int diff;
1294
1295 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1296 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1297 if (diff)
1298 return diff;
1299 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1300 if (diff)
1301 return diff;
1302
1303 diff = drm_mode_vrefresh(b) - drm_mode_vrefresh(a);
1304 if (diff)
1305 return diff;
1306
1307 diff = b->clock - a->clock;
1308 return diff;
1309}
1310
1311
1312
1313
1314
1315
1316
1317void drm_mode_sort(struct list_head *mode_list)
1318{
1319 list_sort(NULL, mode_list, drm_mode_compare);
1320}
1321EXPORT_SYMBOL(drm_mode_sort);
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334void drm_connector_list_update(struct drm_connector *connector)
1335{
1336 struct drm_display_mode *pmode, *pt;
1337
1338 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1339
1340 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1341 struct drm_display_mode *mode;
1342 bool found_it = false;
1343
1344
1345 list_for_each_entry(mode, &connector->modes, head) {
1346 if (!drm_mode_equal(pmode, mode))
1347 continue;
1348
1349 found_it = true;
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363 if (mode->status == MODE_STALE) {
1364 drm_mode_copy(mode, pmode);
1365 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1366 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1367 pmode->type |= mode->type;
1368 drm_mode_copy(mode, pmode);
1369 } else {
1370 mode->type |= pmode->type;
1371 }
1372
1373 list_del(&pmode->head);
1374 drm_mode_destroy(connector->dev, pmode);
1375 break;
1376 }
1377
1378 if (!found_it) {
1379 list_move_tail(&pmode->head, &connector->modes);
1380 }
1381 }
1382}
1383EXPORT_SYMBOL(drm_connector_list_update);
1384
1385static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
1386 struct drm_cmdline_mode *mode)
1387{
1388 unsigned int bpp;
1389
1390 if (str[0] != '-')
1391 return -EINVAL;
1392
1393 str++;
1394 bpp = simple_strtol(str, end_ptr, 10);
1395 if (*end_ptr == str)
1396 return -EINVAL;
1397
1398 mode->bpp = bpp;
1399 mode->bpp_specified = true;
1400
1401 return 0;
1402}
1403
1404static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
1405 struct drm_cmdline_mode *mode)
1406{
1407 unsigned int refresh;
1408
1409 if (str[0] != '@')
1410 return -EINVAL;
1411
1412 str++;
1413 refresh = simple_strtol(str, end_ptr, 10);
1414 if (*end_ptr == str)
1415 return -EINVAL;
1416
1417 mode->refresh = refresh;
1418 mode->refresh_specified = true;
1419
1420 return 0;
1421}
1422
1423static int drm_mode_parse_cmdline_extra(const char *str, int length,
1424 bool freestanding,
1425 const struct drm_connector *connector,
1426 struct drm_cmdline_mode *mode)
1427{
1428 int i;
1429
1430 for (i = 0; i < length; i++) {
1431 switch (str[i]) {
1432 case 'i':
1433 if (freestanding)
1434 return -EINVAL;
1435
1436 mode->interlace = true;
1437 break;
1438 case 'm':
1439 if (freestanding)
1440 return -EINVAL;
1441
1442 mode->margins = true;
1443 break;
1444 case 'D':
1445 if (mode->force != DRM_FORCE_UNSPECIFIED)
1446 return -EINVAL;
1447
1448 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1449 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1450 mode->force = DRM_FORCE_ON;
1451 else
1452 mode->force = DRM_FORCE_ON_DIGITAL;
1453 break;
1454 case 'd':
1455 if (mode->force != DRM_FORCE_UNSPECIFIED)
1456 return -EINVAL;
1457
1458 mode->force = DRM_FORCE_OFF;
1459 break;
1460 case 'e':
1461 if (mode->force != DRM_FORCE_UNSPECIFIED)
1462 return -EINVAL;
1463
1464 mode->force = DRM_FORCE_ON;
1465 break;
1466 default:
1467 return -EINVAL;
1468 }
1469 }
1470
1471 return 0;
1472}
1473
1474static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
1475 bool extras,
1476 const struct drm_connector *connector,
1477 struct drm_cmdline_mode *mode)
1478{
1479 const char *str_start = str;
1480 bool rb = false, cvt = false;
1481 int xres = 0, yres = 0;
1482 int remaining, i;
1483 char *end_ptr;
1484
1485 xres = simple_strtol(str, &end_ptr, 10);
1486 if (end_ptr == str)
1487 return -EINVAL;
1488
1489 if (end_ptr[0] != 'x')
1490 return -EINVAL;
1491 end_ptr++;
1492
1493 str = end_ptr;
1494 yres = simple_strtol(str, &end_ptr, 10);
1495 if (end_ptr == str)
1496 return -EINVAL;
1497
1498 remaining = length - (end_ptr - str_start);
1499 if (remaining < 0)
1500 return -EINVAL;
1501
1502 for (i = 0; i < remaining; i++) {
1503 switch (end_ptr[i]) {
1504 case 'M':
1505 cvt = true;
1506 break;
1507 case 'R':
1508 rb = true;
1509 break;
1510 default:
1511
1512
1513
1514
1515
1516 if (extras) {
1517 int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
1518 1,
1519 false,
1520 connector,
1521 mode);
1522 if (ret)
1523 return ret;
1524 } else {
1525 return -EINVAL;
1526 }
1527 }
1528 }
1529
1530 mode->xres = xres;
1531 mode->yres = yres;
1532 mode->cvt = cvt;
1533 mode->rb = rb;
1534
1535 return 0;
1536}
1537
1538static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
1539{
1540 const char *value;
1541 char *endp;
1542
1543
1544
1545
1546
1547
1548 if (*delim != '=')
1549 return -EINVAL;
1550
1551 value = delim + 1;
1552 *int_ret = simple_strtol(value, &endp, 10);
1553
1554
1555 if (endp == value)
1556 return -EINVAL;
1557
1558 return 0;
1559}
1560
1561static int drm_mode_parse_panel_orientation(const char *delim,
1562 struct drm_cmdline_mode *mode)
1563{
1564 const char *value;
1565
1566 if (*delim != '=')
1567 return -EINVAL;
1568
1569 value = delim + 1;
1570 delim = strchr(value, ',');
1571 if (!delim)
1572 delim = value + strlen(value);
1573
1574 if (!strncmp(value, "normal", delim - value))
1575 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
1576 else if (!strncmp(value, "upside_down", delim - value))
1577 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1578 else if (!strncmp(value, "left_side_up", delim - value))
1579 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
1580 else if (!strncmp(value, "right_side_up", delim - value))
1581 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
1582 else
1583 return -EINVAL;
1584
1585 return 0;
1586}
1587
1588static int drm_mode_parse_cmdline_options(const char *str,
1589 bool freestanding,
1590 const struct drm_connector *connector,
1591 struct drm_cmdline_mode *mode)
1592{
1593 unsigned int deg, margin, rotation = 0;
1594 const char *delim, *option, *sep;
1595
1596 option = str;
1597 do {
1598 delim = strchr(option, '=');
1599 if (!delim) {
1600 delim = strchr(option, ',');
1601
1602 if (!delim)
1603 delim = option + strlen(option);
1604 }
1605
1606 if (!strncmp(option, "rotate", delim - option)) {
1607 if (drm_mode_parse_cmdline_int(delim, °))
1608 return -EINVAL;
1609
1610 switch (deg) {
1611 case 0:
1612 rotation |= DRM_MODE_ROTATE_0;
1613 break;
1614
1615 case 90:
1616 rotation |= DRM_MODE_ROTATE_90;
1617 break;
1618
1619 case 180:
1620 rotation |= DRM_MODE_ROTATE_180;
1621 break;
1622
1623 case 270:
1624 rotation |= DRM_MODE_ROTATE_270;
1625 break;
1626
1627 default:
1628 return -EINVAL;
1629 }
1630 } else if (!strncmp(option, "reflect_x", delim - option)) {
1631 rotation |= DRM_MODE_REFLECT_X;
1632 } else if (!strncmp(option, "reflect_y", delim - option)) {
1633 rotation |= DRM_MODE_REFLECT_Y;
1634 } else if (!strncmp(option, "margin_right", delim - option)) {
1635 if (drm_mode_parse_cmdline_int(delim, &margin))
1636 return -EINVAL;
1637
1638 mode->tv_margins.right = margin;
1639 } else if (!strncmp(option, "margin_left", delim - option)) {
1640 if (drm_mode_parse_cmdline_int(delim, &margin))
1641 return -EINVAL;
1642
1643 mode->tv_margins.left = margin;
1644 } else if (!strncmp(option, "margin_top", delim - option)) {
1645 if (drm_mode_parse_cmdline_int(delim, &margin))
1646 return -EINVAL;
1647
1648 mode->tv_margins.top = margin;
1649 } else if (!strncmp(option, "margin_bottom", delim - option)) {
1650 if (drm_mode_parse_cmdline_int(delim, &margin))
1651 return -EINVAL;
1652
1653 mode->tv_margins.bottom = margin;
1654 } else if (!strncmp(option, "panel_orientation", delim - option)) {
1655 if (drm_mode_parse_panel_orientation(delim, mode))
1656 return -EINVAL;
1657 } else {
1658 return -EINVAL;
1659 }
1660 sep = strchr(delim, ',');
1661 option = sep + 1;
1662 } while (sep);
1663
1664 if (rotation && freestanding)
1665 return -EINVAL;
1666
1667 if (!(rotation & DRM_MODE_ROTATE_MASK))
1668 rotation |= DRM_MODE_ROTATE_0;
1669
1670
1671 if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
1672 return -EINVAL;
1673
1674 mode->rotation_reflection = rotation;
1675
1676 return 0;
1677}
1678
1679static const char * const drm_named_modes_whitelist[] = {
1680 "NTSC",
1681 "PAL",
1682};
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1710 const struct drm_connector *connector,
1711 struct drm_cmdline_mode *mode)
1712{
1713 const char *name;
1714 bool freestanding = false, parse_extras = false;
1715 unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
1716 unsigned int mode_end = 0;
1717 const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
1718 const char *options_ptr = NULL;
1719 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
1720 int i, len, ret;
1721
1722 memset(mode, 0, sizeof(*mode));
1723 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1724
1725 if (!mode_option)
1726 return false;
1727
1728 name = mode_option;
1729
1730
1731 bpp_ptr = strchr(name, '-');
1732 if (bpp_ptr)
1733 bpp_off = bpp_ptr - name;
1734
1735 refresh_ptr = strchr(name, '@');
1736 if (refresh_ptr)
1737 refresh_off = refresh_ptr - name;
1738
1739
1740 options_ptr = strchr(name, ',');
1741 if (options_ptr)
1742 options_off = options_ptr - name;
1743
1744
1745 if (bpp_ptr) {
1746 mode_end = bpp_off;
1747 } else if (refresh_ptr) {
1748 mode_end = refresh_off;
1749 } else if (options_ptr) {
1750 mode_end = options_off;
1751 parse_extras = true;
1752 } else {
1753 mode_end = strlen(name);
1754 parse_extras = true;
1755 }
1756
1757
1758 for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
1759 ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
1760 if (ret == mode_end) {
1761 if (refresh_ptr)
1762 return false;
1763
1764 strcpy(mode->name, drm_named_modes_whitelist[i]);
1765 mode->specified = true;
1766 break;
1767 }
1768 }
1769
1770
1771 if (!mode->specified && isdigit(name[0])) {
1772 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
1773 parse_extras,
1774 connector,
1775 mode);
1776 if (ret)
1777 return false;
1778
1779 mode->specified = true;
1780 }
1781
1782
1783 if (!mode->specified) {
1784 unsigned int len = strlen(mode_option);
1785
1786 if (bpp_ptr || refresh_ptr)
1787 return false;
1788
1789 if (len == 1 || (len >= 2 && mode_option[1] == ','))
1790 extra_ptr = mode_option;
1791 else
1792 options_ptr = mode_option - 1;
1793
1794 freestanding = true;
1795 }
1796
1797 if (bpp_ptr) {
1798 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
1799 if (ret)
1800 return false;
1801
1802 mode->bpp_specified = true;
1803 }
1804
1805 if (refresh_ptr) {
1806 ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
1807 &refresh_end_ptr, mode);
1808 if (ret)
1809 return false;
1810
1811 mode->refresh_specified = true;
1812 }
1813
1814
1815
1816
1817
1818 if (bpp_ptr && refresh_ptr)
1819 extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
1820 else if (bpp_ptr)
1821 extra_ptr = bpp_end_ptr;
1822 else if (refresh_ptr)
1823 extra_ptr = refresh_end_ptr;
1824
1825 if (extra_ptr) {
1826 if (options_ptr)
1827 len = options_ptr - extra_ptr;
1828 else
1829 len = strlen(extra_ptr);
1830
1831 ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
1832 connector, mode);
1833 if (ret)
1834 return false;
1835 }
1836
1837 if (options_ptr) {
1838 ret = drm_mode_parse_cmdline_options(options_ptr + 1,
1839 freestanding,
1840 connector, mode);
1841 if (ret)
1842 return false;
1843 }
1844
1845 return true;
1846}
1847EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857struct drm_display_mode *
1858drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1859 struct drm_cmdline_mode *cmd)
1860{
1861 struct drm_display_mode *mode;
1862
1863 if (cmd->xres == 0 || cmd->yres == 0)
1864 return NULL;
1865
1866 if (cmd->cvt)
1867 mode = drm_cvt_mode(dev,
1868 cmd->xres, cmd->yres,
1869 cmd->refresh_specified ? cmd->refresh : 60,
1870 cmd->rb, cmd->interlace,
1871 cmd->margins);
1872 else
1873 mode = drm_gtf_mode(dev,
1874 cmd->xres, cmd->yres,
1875 cmd->refresh_specified ? cmd->refresh : 60,
1876 cmd->interlace,
1877 cmd->margins);
1878 if (!mode)
1879 return NULL;
1880
1881 mode->type |= DRM_MODE_TYPE_USERDEF;
1882
1883 if (cmd->xres == 1366)
1884 drm_mode_fixup_1366x768(mode);
1885 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1886 return mode;
1887}
1888EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1899 const struct drm_display_mode *in)
1900{
1901 out->clock = in->clock;
1902 out->hdisplay = in->hdisplay;
1903 out->hsync_start = in->hsync_start;
1904 out->hsync_end = in->hsync_end;
1905 out->htotal = in->htotal;
1906 out->hskew = in->hskew;
1907 out->vdisplay = in->vdisplay;
1908 out->vsync_start = in->vsync_start;
1909 out->vsync_end = in->vsync_end;
1910 out->vtotal = in->vtotal;
1911 out->vscan = in->vscan;
1912 out->vrefresh = drm_mode_vrefresh(in);
1913 out->flags = in->flags;
1914 out->type = in->type;
1915
1916 switch (in->picture_aspect_ratio) {
1917 case HDMI_PICTURE_ASPECT_4_3:
1918 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
1919 break;
1920 case HDMI_PICTURE_ASPECT_16_9:
1921 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
1922 break;
1923 case HDMI_PICTURE_ASPECT_64_27:
1924 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
1925 break;
1926 case HDMI_PICTURE_ASPECT_256_135:
1927 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
1928 break;
1929 default:
1930 WARN(1, "Invalid aspect ratio (0%x) on mode\n",
1931 in->picture_aspect_ratio);
1932 fallthrough;
1933 case HDMI_PICTURE_ASPECT_NONE:
1934 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
1935 break;
1936 }
1937
1938 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1939 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1940}
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954int drm_mode_convert_umode(struct drm_device *dev,
1955 struct drm_display_mode *out,
1956 const struct drm_mode_modeinfo *in)
1957{
1958 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1959 return -ERANGE;
1960
1961 out->clock = in->clock;
1962 out->hdisplay = in->hdisplay;
1963 out->hsync_start = in->hsync_start;
1964 out->hsync_end = in->hsync_end;
1965 out->htotal = in->htotal;
1966 out->hskew = in->hskew;
1967 out->vdisplay = in->vdisplay;
1968 out->vsync_start = in->vsync_start;
1969 out->vsync_end = in->vsync_end;
1970 out->vtotal = in->vtotal;
1971 out->vscan = in->vscan;
1972 out->flags = in->flags;
1973
1974
1975
1976
1977
1978
1979 out->type = in->type & DRM_MODE_TYPE_ALL;
1980 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1981 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1982
1983
1984
1985
1986
1987 out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
1988
1989 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
1990 case DRM_MODE_FLAG_PIC_AR_4_3:
1991 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
1992 break;
1993 case DRM_MODE_FLAG_PIC_AR_16_9:
1994 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
1995 break;
1996 case DRM_MODE_FLAG_PIC_AR_64_27:
1997 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
1998 break;
1999 case DRM_MODE_FLAG_PIC_AR_256_135:
2000 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
2001 break;
2002 case DRM_MODE_FLAG_PIC_AR_NONE:
2003 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
2004 break;
2005 default:
2006 return -EINVAL;
2007 }
2008
2009 out->status = drm_mode_validate_driver(dev, out);
2010 if (out->status != MODE_OK)
2011 return -EINVAL;
2012
2013 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
2014
2015 return 0;
2016}
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029bool drm_mode_is_420_only(const struct drm_display_info *display,
2030 const struct drm_display_mode *mode)
2031{
2032 u8 vic = drm_match_cea_mode(mode);
2033
2034 return test_bit(vic, display->hdmi.y420_vdb_modes);
2035}
2036EXPORT_SYMBOL(drm_mode_is_420_only);
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049bool drm_mode_is_420_also(const struct drm_display_info *display,
2050 const struct drm_display_mode *mode)
2051{
2052 u8 vic = drm_match_cea_mode(mode);
2053
2054 return test_bit(vic, display->hdmi.y420_cmdb_modes);
2055}
2056EXPORT_SYMBOL(drm_mode_is_420_also);
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068bool drm_mode_is_420(const struct drm_display_info *display,
2069 const struct drm_display_mode *mode)
2070{
2071 return drm_mode_is_420_only(display, mode) ||
2072 drm_mode_is_420_also(display, mode);
2073}
2074EXPORT_SYMBOL(drm_mode_is_420);
2075