This source file includes following definitions.
- drm_mode_debug_printmodeline
- drm_mode_create
- drm_mode_destroy
- drm_mode_probed_add
- drm_cvt_mode
- drm_gtf_mode_complex
- drm_gtf_mode
- drm_display_mode_from_videomode
- drm_display_mode_to_videomode
- drm_bus_flags_from_videomode
- of_get_drm_display_mode
- drm_mode_set_name
- drm_mode_hsync
- drm_mode_vrefresh
- drm_mode_get_hv_timing
- drm_mode_set_crtcinfo
- drm_mode_copy
- drm_mode_duplicate
- drm_mode_match_timings
- drm_mode_match_clock
- drm_mode_match_flags
- drm_mode_match_3d_flags
- drm_mode_match_aspect_ratio
- drm_mode_match
- drm_mode_equal
- drm_mode_equal_no_clocks
- drm_mode_equal_no_clocks_no_stereo
- drm_mode_validate_basic
- drm_mode_validate_driver
- drm_mode_validate_size
- drm_mode_validate_ycbcr420
- drm_get_mode_status_name
- drm_mode_prune_invalid
- drm_mode_compare
- drm_mode_sort
- drm_connector_list_update
- drm_mode_parse_cmdline_bpp
- drm_mode_parse_cmdline_refresh
- drm_mode_parse_cmdline_extra
- drm_mode_parse_cmdline_res_mode
- drm_mode_parse_cmdline_options
- drm_named_mode_is_in_whitelist
- drm_mode_parse_command_line_for_connector
- drm_mode_create_from_cmdline_mode
- drm_mode_convert_to_umode
- drm_mode_convert_umode
- drm_mode_is_420_only
- drm_mode_is_420_also
- drm_mode_is_420
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
54 void 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 }
58 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
59
60
61
62
63
64
65
66
67
68
69
70 struct 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 }
80 EXPORT_SYMBOL(drm_mode_create);
81
82
83
84
85
86
87
88
89 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
90 {
91 if (!mode)
92 return;
93
94 kfree(mode);
95 }
96 EXPORT_SYMBOL(drm_mode_destroy);
97
98
99
100
101
102
103
104
105
106
107 void 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 }
114 EXPORT_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
140 struct 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 }
342 EXPORT_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
365 struct drm_display_mode *
366 drm_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 }
533 EXPORT_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
569 struct drm_display_mode *
570 drm_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 }
577 EXPORT_SYMBOL(drm_gtf_mode);
578
579 #ifdef CONFIG_VIDEOMODE_HELPERS
580
581
582
583
584
585
586
587 void 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 }
619 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
620
621
622
623
624
625
626
627
628 void 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 }
659 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
660
661
662
663
664
665
666
667
668
669
670
671
672 void 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 }
690 EXPORT_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
707 int 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 }
728 EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
729 #endif
730 #endif
731
732
733
734
735
736
737
738
739 void 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 }
747 EXPORT_SYMBOL(drm_mode_set_name);
748
749
750
751
752
753
754
755
756
757 int 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 }
773 EXPORT_SYMBOL(drm_mode_hsync);
774
775
776
777
778
779
780
781
782
783 int 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 }
806 EXPORT_SYMBOL(drm_mode_vrefresh);
807
808
809
810
811
812
813
814
815
816
817 void 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 }
826 EXPORT_SYMBOL(drm_mode_get_hv_timing);
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843 void 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 }
905 EXPORT_SYMBOL(drm_mode_set_crtcinfo);
906
907
908
909
910
911
912
913
914
915 void 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 }
922 EXPORT_SYMBOL(drm_mode_copy);
923
924
925
926
927
928
929
930
931
932
933
934
935 struct 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 }
948 EXPORT_SYMBOL(drm_mode_duplicate);
949
950 static 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
965 static 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
978 static 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
985 static 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
992 static 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
1009 bool 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 }
1041 EXPORT_SYMBOL(drm_mode_match);
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053 bool 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 }
1063 EXPORT_SYMBOL(drm_mode_equal);
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 bool 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 }
1084 EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097 bool 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 }
1104 EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1105
1106 static enum drm_mode_status
1107 drm_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
1148 enum drm_mode_status
1149 drm_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 }
1163 EXPORT_SYMBOL(drm_mode_validate_driver);
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179 enum drm_mode_status
1180 drm_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 }
1191 EXPORT_SYMBOL(drm_mode_validate_size);
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204 enum drm_mode_status
1205 drm_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 }
1219 EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1220
1221 #define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1222
1223 static 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
1268 const 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
1289 void 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 }
1307 EXPORT_SYMBOL(drm_mode_prune_invalid);
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322 static 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
1350 void drm_mode_sort(struct list_head *mode_list)
1351 {
1352 list_sort(NULL, mode_list, drm_mode_compare);
1353 }
1354 EXPORT_SYMBOL(drm_mode_sort);
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367 void 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 }
1416 EXPORT_SYMBOL(drm_connector_list_update);
1417
1418 static 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
1437 static 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
1456 static 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
1507 static 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
1571 static 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 if (!(rotation & DRM_MODE_ROTATE_MASK))
1676 rotation |= DRM_MODE_ROTATE_0;
1677
1678
1679 if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
1680 return -EINVAL;
1681
1682 mode->rotation_reflection = rotation;
1683
1684 return 0;
1685 }
1686
1687 static const char * const drm_named_modes_whitelist[] = {
1688 "NTSC",
1689 "PAL",
1690 };
1691
1692 static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
1693 {
1694 int i;
1695
1696 for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
1697 if (!strncmp(mode, drm_named_modes_whitelist[i], size))
1698 return true;
1699
1700 return false;
1701 }
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728 bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1729 const struct drm_connector *connector,
1730 struct drm_cmdline_mode *mode)
1731 {
1732 const char *name;
1733 bool named_mode = false, parse_extras = false;
1734 unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
1735 unsigned int mode_end = 0;
1736 char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
1737 char *options_ptr = NULL;
1738 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
1739 int ret;
1740
1741 #ifdef CONFIG_FB
1742 if (!mode_option)
1743 mode_option = fb_mode_option;
1744 #endif
1745
1746 if (!mode_option) {
1747 mode->specified = false;
1748 return false;
1749 }
1750
1751 name = mode_option;
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767 if (!isdigit(name[0]) && name[0] != 'x') {
1768 unsigned int namelen = strlen(name);
1769
1770
1771
1772
1773
1774 if (namelen == 1) {
1775 ret = drm_mode_parse_cmdline_extra(name, namelen, true,
1776 connector, mode);
1777 if (!ret)
1778 return true;
1779 }
1780
1781 named_mode = true;
1782 }
1783
1784
1785 bpp_ptr = strchr(name, '-');
1786 if (bpp_ptr) {
1787 bpp_off = bpp_ptr - name;
1788 mode->bpp_specified = true;
1789 }
1790
1791 refresh_ptr = strchr(name, '@');
1792 if (refresh_ptr) {
1793 if (named_mode)
1794 return false;
1795
1796 refresh_off = refresh_ptr - name;
1797 mode->refresh_specified = true;
1798 }
1799
1800
1801 options_ptr = strchr(name, ',');
1802 if (options_ptr)
1803 options_off = options_ptr - name;
1804
1805
1806 if (bpp_ptr) {
1807 mode_end = bpp_off;
1808 } else if (refresh_ptr) {
1809 mode_end = refresh_off;
1810 } else if (options_ptr) {
1811 mode_end = options_off;
1812 } else {
1813 mode_end = strlen(name);
1814 parse_extras = true;
1815 }
1816
1817 if (named_mode) {
1818 if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
1819 return false;
1820
1821 if (!drm_named_mode_is_in_whitelist(name, mode_end))
1822 return false;
1823
1824 strscpy(mode->name, name, mode_end + 1);
1825 } else {
1826 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
1827 parse_extras,
1828 connector,
1829 mode);
1830 if (ret)
1831 return false;
1832 }
1833 mode->specified = true;
1834
1835 if (bpp_ptr) {
1836 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
1837 if (ret)
1838 return false;
1839 }
1840
1841 if (refresh_ptr) {
1842 ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
1843 &refresh_end_ptr, mode);
1844 if (ret)
1845 return false;
1846 }
1847
1848
1849
1850
1851
1852 if (bpp_ptr && refresh_ptr)
1853 extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
1854 else if (bpp_ptr)
1855 extra_ptr = bpp_end_ptr;
1856 else if (refresh_ptr)
1857 extra_ptr = refresh_end_ptr;
1858
1859 if (extra_ptr &&
1860 extra_ptr != options_ptr) {
1861 int len = strlen(name) - (extra_ptr - name);
1862
1863 ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
1864 connector, mode);
1865 if (ret)
1866 return false;
1867 }
1868
1869 if (options_ptr) {
1870 int len = strlen(name) - (options_ptr - name);
1871
1872 ret = drm_mode_parse_cmdline_options(options_ptr, len,
1873 connector, mode);
1874 if (ret)
1875 return false;
1876 }
1877
1878 return true;
1879 }
1880 EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890 struct drm_display_mode *
1891 drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1892 struct drm_cmdline_mode *cmd)
1893 {
1894 struct drm_display_mode *mode;
1895
1896 if (cmd->cvt)
1897 mode = drm_cvt_mode(dev,
1898 cmd->xres, cmd->yres,
1899 cmd->refresh_specified ? cmd->refresh : 60,
1900 cmd->rb, cmd->interlace,
1901 cmd->margins);
1902 else
1903 mode = drm_gtf_mode(dev,
1904 cmd->xres, cmd->yres,
1905 cmd->refresh_specified ? cmd->refresh : 60,
1906 cmd->interlace,
1907 cmd->margins);
1908 if (!mode)
1909 return NULL;
1910
1911 mode->type |= DRM_MODE_TYPE_USERDEF;
1912
1913 if (cmd->xres == 1366)
1914 drm_mode_fixup_1366x768(mode);
1915 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1916 return mode;
1917 }
1918 EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928 void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1929 const struct drm_display_mode *in)
1930 {
1931 WARN(in->hdisplay > USHRT_MAX || in->hsync_start > USHRT_MAX ||
1932 in->hsync_end > USHRT_MAX || in->htotal > USHRT_MAX ||
1933 in->hskew > USHRT_MAX || in->vdisplay > USHRT_MAX ||
1934 in->vsync_start > USHRT_MAX || in->vsync_end > USHRT_MAX ||
1935 in->vtotal > USHRT_MAX || in->vscan > USHRT_MAX,
1936 "timing values too large for mode info\n");
1937
1938 out->clock = in->clock;
1939 out->hdisplay = in->hdisplay;
1940 out->hsync_start = in->hsync_start;
1941 out->hsync_end = in->hsync_end;
1942 out->htotal = in->htotal;
1943 out->hskew = in->hskew;
1944 out->vdisplay = in->vdisplay;
1945 out->vsync_start = in->vsync_start;
1946 out->vsync_end = in->vsync_end;
1947 out->vtotal = in->vtotal;
1948 out->vscan = in->vscan;
1949 out->vrefresh = in->vrefresh;
1950 out->flags = in->flags;
1951 out->type = in->type;
1952
1953 switch (in->picture_aspect_ratio) {
1954 case HDMI_PICTURE_ASPECT_4_3:
1955 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
1956 break;
1957 case HDMI_PICTURE_ASPECT_16_9:
1958 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
1959 break;
1960 case HDMI_PICTURE_ASPECT_64_27:
1961 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
1962 break;
1963 case HDMI_PICTURE_ASPECT_256_135:
1964 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
1965 break;
1966 default:
1967 WARN(1, "Invalid aspect ratio (0%x) on mode\n",
1968 in->picture_aspect_ratio);
1969
1970 case HDMI_PICTURE_ASPECT_NONE:
1971 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
1972 break;
1973 }
1974
1975 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
1976 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
1977 }
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991 int drm_mode_convert_umode(struct drm_device *dev,
1992 struct drm_display_mode *out,
1993 const struct drm_mode_modeinfo *in)
1994 {
1995 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
1996 return -ERANGE;
1997
1998 out->clock = in->clock;
1999 out->hdisplay = in->hdisplay;
2000 out->hsync_start = in->hsync_start;
2001 out->hsync_end = in->hsync_end;
2002 out->htotal = in->htotal;
2003 out->hskew = in->hskew;
2004 out->vdisplay = in->vdisplay;
2005 out->vsync_start = in->vsync_start;
2006 out->vsync_end = in->vsync_end;
2007 out->vtotal = in->vtotal;
2008 out->vscan = in->vscan;
2009 out->vrefresh = in->vrefresh;
2010 out->flags = in->flags;
2011
2012
2013
2014
2015
2016
2017 out->type = in->type & DRM_MODE_TYPE_ALL;
2018 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
2019 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
2020
2021
2022
2023
2024
2025 out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
2026
2027 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
2028 case DRM_MODE_FLAG_PIC_AR_4_3:
2029 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
2030 break;
2031 case DRM_MODE_FLAG_PIC_AR_16_9:
2032 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
2033 break;
2034 case DRM_MODE_FLAG_PIC_AR_64_27:
2035 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
2036 break;
2037 case DRM_MODE_FLAG_PIC_AR_256_135:
2038 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
2039 break;
2040 case DRM_MODE_FLAG_PIC_AR_NONE:
2041 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
2042 break;
2043 default:
2044 return -EINVAL;
2045 }
2046
2047 out->status = drm_mode_validate_driver(dev, out);
2048 if (out->status != MODE_OK)
2049 return -EINVAL;
2050
2051 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
2052
2053 return 0;
2054 }
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067 bool drm_mode_is_420_only(const struct drm_display_info *display,
2068 const struct drm_display_mode *mode)
2069 {
2070 u8 vic = drm_match_cea_mode(mode);
2071
2072 return test_bit(vic, display->hdmi.y420_vdb_modes);
2073 }
2074 EXPORT_SYMBOL(drm_mode_is_420_only);
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087 bool drm_mode_is_420_also(const struct drm_display_info *display,
2088 const struct drm_display_mode *mode)
2089 {
2090 u8 vic = drm_match_cea_mode(mode);
2091
2092 return test_bit(vic, display->hdmi.y420_cmdb_modes);
2093 }
2094 EXPORT_SYMBOL(drm_mode_is_420_also);
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106 bool drm_mode_is_420(const struct drm_display_info *display,
2107 const struct drm_display_mode *mode)
2108 {
2109 return drm_mode_is_420_only(display, mode) ||
2110 drm_mode_is_420_also(display, mode);
2111 }
2112 EXPORT_SYMBOL(drm_mode_is_420);