0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/ctype.h>
0034 #include <linux/list.h>
0035 #include <linux/list_sort.h>
0036 #include <linux/export.h>
0037 #include <linux/fb.h>
0038
0039 #include <video/of_display_timing.h>
0040 #include <video/of_videomode.h>
0041 #include <video/videomode.h>
0042
0043 #include <drm/drm_crtc.h>
0044 #include <drm/drm_device.h>
0045 #include <drm/drm_edid.h>
0046 #include <drm/drm_modes.h>
0047 #include <drm/drm_print.h>
0048
0049 #include "drm_crtc_internal.h"
0050
0051
0052
0053
0054
0055
0056
0057 void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
0058 {
0059 DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
0060 }
0061 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 struct drm_display_mode *drm_mode_create(struct drm_device *dev)
0074 {
0075 struct drm_display_mode *nmode;
0076
0077 nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
0078 if (!nmode)
0079 return NULL;
0080
0081 return nmode;
0082 }
0083 EXPORT_SYMBOL(drm_mode_create);
0084
0085
0086
0087
0088
0089
0090
0091
0092 void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
0093 {
0094 if (!mode)
0095 return;
0096
0097 kfree(mode);
0098 }
0099 EXPORT_SYMBOL(drm_mode_destroy);
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 void drm_mode_probed_add(struct drm_connector *connector,
0111 struct drm_display_mode *mode)
0112 {
0113 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
0114
0115 list_add_tail(&mode->head, &connector->probed_modes);
0116 }
0117 EXPORT_SYMBOL(drm_mode_probed_add);
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143 struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
0144 int vdisplay, int vrefresh,
0145 bool reduced, bool interlaced, bool margins)
0146 {
0147 #define HV_FACTOR 1000
0148
0149 #define CVT_MARGIN_PERCENTAGE 18
0150
0151 #define CVT_H_GRANULARITY 8
0152
0153 #define CVT_MIN_V_PORCH 3
0154
0155 #define CVT_MIN_V_BPORCH 6
0156
0157 #define CVT_CLOCK_STEP 250
0158 struct drm_display_mode *drm_mode;
0159 unsigned int vfieldrate, hperiod;
0160 int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
0161 int interlace;
0162 u64 tmp;
0163
0164 if (!hdisplay || !vdisplay)
0165 return NULL;
0166
0167
0168
0169
0170 drm_mode = drm_mode_create(dev);
0171 if (!drm_mode)
0172 return NULL;
0173
0174
0175 if (!vrefresh)
0176 vrefresh = 60;
0177
0178
0179 if (interlaced)
0180 vfieldrate = vrefresh * 2;
0181 else
0182 vfieldrate = vrefresh;
0183
0184
0185 hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
0186
0187
0188 hmargin = 0;
0189 if (margins) {
0190 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
0191 hmargin -= hmargin % CVT_H_GRANULARITY;
0192 }
0193
0194 drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
0195
0196
0197 if (interlaced)
0198 vdisplay_rnd = vdisplay / 2;
0199 else
0200 vdisplay_rnd = vdisplay;
0201
0202
0203 vmargin = 0;
0204 if (margins)
0205 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
0206
0207 drm_mode->vdisplay = vdisplay + 2 * vmargin;
0208
0209
0210 if (interlaced)
0211 interlace = 1;
0212 else
0213 interlace = 0;
0214
0215
0216 if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
0217 vsync = 4;
0218 else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
0219 vsync = 5;
0220 else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
0221 vsync = 6;
0222 else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
0223 vsync = 7;
0224 else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
0225 vsync = 7;
0226 else
0227 vsync = 10;
0228
0229 if (!reduced) {
0230
0231
0232
0233
0234 int tmp1, tmp2;
0235 #define CVT_MIN_VSYNC_BP 550
0236
0237 #define CVT_HSYNC_PERCENTAGE 8
0238 unsigned int hblank_percentage;
0239 int vsyncandback_porch, __maybe_unused vback_porch, hblank;
0240
0241
0242 tmp1 = HV_FACTOR * 1000000 -
0243 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
0244 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
0245 interlace;
0246 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
0247
0248 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
0249
0250 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
0251 vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
0252 else
0253 vsyncandback_porch = tmp1;
0254
0255 vback_porch = vsyncandback_porch - vsync;
0256 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
0257 vsyncandback_porch + CVT_MIN_V_PORCH;
0258
0259
0260 #define CVT_M_FACTOR 600
0261
0262 #define CVT_C_FACTOR 40
0263
0264 #define CVT_K_FACTOR 128
0265
0266 #define CVT_J_FACTOR 20
0267 #define CVT_M_PRIME (CVT_M_FACTOR * CVT_K_FACTOR / 256)
0268 #define CVT_C_PRIME ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
0269 CVT_J_FACTOR)
0270
0271 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
0272 hperiod / 1000;
0273
0274 if (hblank_percentage < 20 * HV_FACTOR)
0275 hblank_percentage = 20 * HV_FACTOR;
0276 hblank = drm_mode->hdisplay * hblank_percentage /
0277 (100 * HV_FACTOR - hblank_percentage);
0278 hblank -= hblank % (2 * CVT_H_GRANULARITY);
0279
0280 drm_mode->htotal = drm_mode->hdisplay + hblank;
0281 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
0282 drm_mode->hsync_start = drm_mode->hsync_end -
0283 (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
0284 drm_mode->hsync_start += CVT_H_GRANULARITY -
0285 drm_mode->hsync_start % CVT_H_GRANULARITY;
0286
0287 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
0288 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
0289 } else {
0290
0291
0292 #define CVT_RB_MIN_VBLANK 460
0293
0294 #define CVT_RB_H_SYNC 32
0295
0296 #define CVT_RB_H_BLANK 160
0297
0298 #define CVT_RB_VFPORCH 3
0299 int vbilines;
0300 int tmp1, tmp2;
0301
0302 tmp1 = HV_FACTOR * 1000000 -
0303 CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
0304 tmp2 = vdisplay_rnd + 2 * vmargin;
0305 hperiod = tmp1 / (tmp2 * vfieldrate);
0306
0307 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
0308
0309 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
0310 vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
0311
0312 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
0313
0314 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
0315
0316 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
0317 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
0318
0319 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
0320 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
0321 }
0322
0323 tmp = drm_mode->htotal;
0324 tmp *= HV_FACTOR * 1000;
0325 do_div(tmp, hperiod);
0326 tmp -= drm_mode->clock % CVT_CLOCK_STEP;
0327 drm_mode->clock = tmp;
0328
0329
0330 if (interlaced) {
0331 drm_mode->vtotal *= 2;
0332 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
0333 }
0334
0335 drm_mode_set_name(drm_mode);
0336 if (reduced)
0337 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
0338 DRM_MODE_FLAG_NVSYNC);
0339 else
0340 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
0341 DRM_MODE_FLAG_NHSYNC);
0342
0343 return drm_mode;
0344 }
0345 EXPORT_SYMBOL(drm_cvt_mode);
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368 struct drm_display_mode *
0369 drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
0370 int vrefresh, bool interlaced, int margins,
0371 int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
0372 {
0373 #define GTF_MARGIN_PERCENTAGE 18
0374
0375 #define GTF_CELL_GRAN 8
0376
0377 #define GTF_MIN_V_PORCH 1
0378
0379 #define V_SYNC_RQD 3
0380
0381 #define H_SYNC_PERCENT 8
0382
0383 #define MIN_VSYNC_PLUS_BP 550
0384
0385 #define GTF_C_PRIME ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
0386 #define GTF_M_PRIME (GTF_K * GTF_M / 256)
0387 struct drm_display_mode *drm_mode;
0388 unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
0389 int top_margin, bottom_margin;
0390 int interlace;
0391 unsigned int hfreq_est;
0392 int vsync_plus_bp, __maybe_unused vback_porch;
0393 unsigned int vtotal_lines, __maybe_unused vfieldrate_est;
0394 unsigned int __maybe_unused hperiod;
0395 unsigned int vfield_rate, __maybe_unused vframe_rate;
0396 int left_margin, right_margin;
0397 unsigned int total_active_pixels, ideal_duty_cycle;
0398 unsigned int hblank, total_pixels, pixel_freq;
0399 int hsync, hfront_porch, vodd_front_porch_lines;
0400 unsigned int tmp1, tmp2;
0401
0402 if (!hdisplay || !vdisplay)
0403 return NULL;
0404
0405 drm_mode = drm_mode_create(dev);
0406 if (!drm_mode)
0407 return NULL;
0408
0409
0410
0411
0412
0413
0414 hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
0415 hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
0416
0417
0418
0419
0420
0421 if (interlaced)
0422 vdisplay_rnd = vdisplay / 2;
0423 else
0424 vdisplay_rnd = vdisplay;
0425
0426
0427 if (interlaced)
0428 vfieldrate_rqd = vrefresh * 2;
0429 else
0430 vfieldrate_rqd = vrefresh;
0431
0432
0433 top_margin = 0;
0434 if (margins)
0435 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
0436 1000;
0437
0438 bottom_margin = top_margin;
0439
0440
0441 if (interlaced)
0442 interlace = 1;
0443 else
0444 interlace = 0;
0445
0446
0447 {
0448 tmp1 = (1000000 - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
0449 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
0450 2 + interlace;
0451 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
0452 }
0453
0454
0455
0456 vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
0457 vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
0458
0459 vback_porch = vsync_plus_bp - V_SYNC_RQD;
0460
0461 vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
0462 vsync_plus_bp + GTF_MIN_V_PORCH;
0463
0464 vfieldrate_est = hfreq_est / vtotal_lines;
0465
0466 hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
0467
0468
0469 vfield_rate = hfreq_est / vtotal_lines;
0470
0471 if (interlaced)
0472 vframe_rate = vfield_rate / 2;
0473 else
0474 vframe_rate = vfield_rate;
0475
0476 if (margins)
0477 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
0478 1000;
0479 else
0480 left_margin = 0;
0481
0482
0483 right_margin = left_margin;
0484
0485 total_active_pixels = hdisplay_rnd + left_margin + right_margin;
0486
0487 ideal_duty_cycle = GTF_C_PRIME * 1000 -
0488 (GTF_M_PRIME * 1000000 / hfreq_est);
0489
0490
0491 hblank = total_active_pixels * ideal_duty_cycle /
0492 (100000 - ideal_duty_cycle);
0493 hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
0494 hblank = hblank * 2 * GTF_CELL_GRAN;
0495
0496 total_pixels = total_active_pixels + hblank;
0497
0498 pixel_freq = total_pixels * hfreq_est / 1000;
0499
0500
0501
0502
0503
0504 hsync = H_SYNC_PERCENT * total_pixels / 100;
0505 hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
0506 hsync = hsync * GTF_CELL_GRAN;
0507
0508 hfront_porch = hblank / 2 - hsync;
0509
0510 vodd_front_porch_lines = GTF_MIN_V_PORCH ;
0511
0512
0513 drm_mode->hdisplay = hdisplay_rnd;
0514 drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
0515 drm_mode->hsync_end = drm_mode->hsync_start + hsync;
0516 drm_mode->htotal = total_pixels;
0517 drm_mode->vdisplay = vdisplay_rnd;
0518 drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
0519 drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
0520 drm_mode->vtotal = vtotal_lines;
0521
0522 drm_mode->clock = pixel_freq;
0523
0524 if (interlaced) {
0525 drm_mode->vtotal *= 2;
0526 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
0527 }
0528
0529 drm_mode_set_name(drm_mode);
0530 if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
0531 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
0532 else
0533 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
0534
0535 return drm_mode;
0536 }
0537 EXPORT_SYMBOL(drm_gtf_mode_complex);
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573 struct drm_display_mode *
0574 drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
0575 bool interlaced, int margins)
0576 {
0577 return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
0578 interlaced, margins,
0579 600, 40 * 2, 128, 20 * 2);
0580 }
0581 EXPORT_SYMBOL(drm_gtf_mode);
0582
0583 #ifdef CONFIG_VIDEOMODE_HELPERS
0584
0585
0586
0587
0588
0589
0590
0591 void drm_display_mode_from_videomode(const struct videomode *vm,
0592 struct drm_display_mode *dmode)
0593 {
0594 dmode->hdisplay = vm->hactive;
0595 dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
0596 dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
0597 dmode->htotal = dmode->hsync_end + vm->hback_porch;
0598
0599 dmode->vdisplay = vm->vactive;
0600 dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
0601 dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
0602 dmode->vtotal = dmode->vsync_end + vm->vback_porch;
0603
0604 dmode->clock = vm->pixelclock / 1000;
0605
0606 dmode->flags = 0;
0607 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
0608 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
0609 else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
0610 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
0611 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
0612 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
0613 else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
0614 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
0615 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
0616 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
0617 if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
0618 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
0619 if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
0620 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
0621 drm_mode_set_name(dmode);
0622 }
0623 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
0624
0625
0626
0627
0628
0629
0630
0631
0632 void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
0633 struct videomode *vm)
0634 {
0635 vm->hactive = dmode->hdisplay;
0636 vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
0637 vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
0638 vm->hback_porch = dmode->htotal - dmode->hsync_end;
0639
0640 vm->vactive = dmode->vdisplay;
0641 vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
0642 vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
0643 vm->vback_porch = dmode->vtotal - dmode->vsync_end;
0644
0645 vm->pixelclock = dmode->clock * 1000;
0646
0647 vm->flags = 0;
0648 if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
0649 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
0650 else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
0651 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
0652 if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
0653 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
0654 else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
0655 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
0656 if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
0657 vm->flags |= DISPLAY_FLAGS_INTERLACED;
0658 if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
0659 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
0660 if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
0661 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
0662 }
0663 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675
0676 void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
0677 {
0678 *bus_flags = 0;
0679 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
0680 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
0681 if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
0682 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
0683
0684 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
0685 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
0686 if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
0687 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
0688
0689 if (vm->flags & DISPLAY_FLAGS_DE_LOW)
0690 *bus_flags |= DRM_BUS_FLAG_DE_LOW;
0691 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
0692 *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
0693 }
0694 EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
0695
0696 #ifdef CONFIG_OF
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711 int of_get_drm_display_mode(struct device_node *np,
0712 struct drm_display_mode *dmode, u32 *bus_flags,
0713 int index)
0714 {
0715 struct videomode vm;
0716 int ret;
0717
0718 ret = of_get_videomode(np, &vm, index);
0719 if (ret)
0720 return ret;
0721
0722 drm_display_mode_from_videomode(&vm, dmode);
0723 if (bus_flags)
0724 drm_bus_flags_from_videomode(&vm, bus_flags);
0725
0726 pr_debug("%pOF: got %dx%d display mode\n",
0727 np, vm.hactive, vm.vactive);
0728 drm_mode_debug_printmodeline(dmode);
0729
0730 return 0;
0731 }
0732 EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746 int of_get_drm_panel_display_mode(struct device_node *np,
0747 struct drm_display_mode *dmode, u32 *bus_flags)
0748 {
0749 u32 width_mm = 0, height_mm = 0;
0750 struct display_timing timing;
0751 struct videomode vm;
0752 int ret;
0753
0754 ret = of_get_display_timing(np, "panel-timing", &timing);
0755 if (ret)
0756 return ret;
0757
0758 videomode_from_timing(&timing, &vm);
0759
0760 memset(dmode, 0, sizeof(*dmode));
0761 drm_display_mode_from_videomode(&vm, dmode);
0762 if (bus_flags)
0763 drm_bus_flags_from_videomode(&vm, bus_flags);
0764
0765 ret = of_property_read_u32(np, "width-mm", &width_mm);
0766 if (ret)
0767 return ret;
0768
0769 ret = of_property_read_u32(np, "height-mm", &height_mm);
0770 if (ret)
0771 return ret;
0772
0773 dmode->width_mm = width_mm;
0774 dmode->height_mm = height_mm;
0775
0776 drm_mode_debug_printmodeline(dmode);
0777
0778 return 0;
0779 }
0780 EXPORT_SYMBOL_GPL(of_get_drm_panel_display_mode);
0781 #endif
0782 #endif
0783
0784
0785
0786
0787
0788
0789
0790
0791 void drm_mode_set_name(struct drm_display_mode *mode)
0792 {
0793 bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
0794
0795 snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
0796 mode->hdisplay, mode->vdisplay,
0797 interlaced ? "i" : "");
0798 }
0799 EXPORT_SYMBOL(drm_mode_set_name);
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809 int drm_mode_vrefresh(const struct drm_display_mode *mode)
0810 {
0811 unsigned int num, den;
0812
0813 if (mode->htotal == 0 || mode->vtotal == 0)
0814 return 0;
0815
0816 num = mode->clock;
0817 den = mode->htotal * mode->vtotal;
0818
0819 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
0820 num *= 2;
0821 if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
0822 den *= 2;
0823 if (mode->vscan > 1)
0824 den *= mode->vscan;
0825
0826 return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den);
0827 }
0828 EXPORT_SYMBOL(drm_mode_vrefresh);
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839 void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
0840 int *hdisplay, int *vdisplay)
0841 {
0842 struct drm_display_mode adjusted;
0843
0844 drm_mode_init(&adjusted, mode);
0845
0846 drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
0847 *hdisplay = adjusted.crtc_hdisplay;
0848 *vdisplay = adjusted.crtc_vdisplay;
0849 }
0850 EXPORT_SYMBOL(drm_mode_get_hv_timing);
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
0868 {
0869 if (!p)
0870 return;
0871
0872 p->crtc_clock = p->clock;
0873 p->crtc_hdisplay = p->hdisplay;
0874 p->crtc_hsync_start = p->hsync_start;
0875 p->crtc_hsync_end = p->hsync_end;
0876 p->crtc_htotal = p->htotal;
0877 p->crtc_hskew = p->hskew;
0878 p->crtc_vdisplay = p->vdisplay;
0879 p->crtc_vsync_start = p->vsync_start;
0880 p->crtc_vsync_end = p->vsync_end;
0881 p->crtc_vtotal = p->vtotal;
0882
0883 if (p->flags & DRM_MODE_FLAG_INTERLACE) {
0884 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
0885 p->crtc_vdisplay /= 2;
0886 p->crtc_vsync_start /= 2;
0887 p->crtc_vsync_end /= 2;
0888 p->crtc_vtotal /= 2;
0889 }
0890 }
0891
0892 if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
0893 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
0894 p->crtc_vdisplay *= 2;
0895 p->crtc_vsync_start *= 2;
0896 p->crtc_vsync_end *= 2;
0897 p->crtc_vtotal *= 2;
0898 }
0899 }
0900
0901 if (!(adjust_flags & CRTC_NO_VSCAN)) {
0902 if (p->vscan > 1) {
0903 p->crtc_vdisplay *= p->vscan;
0904 p->crtc_vsync_start *= p->vscan;
0905 p->crtc_vsync_end *= p->vscan;
0906 p->crtc_vtotal *= p->vscan;
0907 }
0908 }
0909
0910 if (adjust_flags & CRTC_STEREO_DOUBLE) {
0911 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
0912
0913 switch (layout) {
0914 case DRM_MODE_FLAG_3D_FRAME_PACKING:
0915 p->crtc_clock *= 2;
0916 p->crtc_vdisplay += p->crtc_vtotal;
0917 p->crtc_vsync_start += p->crtc_vtotal;
0918 p->crtc_vsync_end += p->crtc_vtotal;
0919 p->crtc_vtotal += p->crtc_vtotal;
0920 break;
0921 }
0922 }
0923
0924 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
0925 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
0926 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
0927 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
0928 }
0929 EXPORT_SYMBOL(drm_mode_set_crtcinfo);
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939 void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
0940 {
0941 struct list_head head = dst->head;
0942
0943 *dst = *src;
0944 dst->head = head;
0945 }
0946 EXPORT_SYMBOL(drm_mode_copy);
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958 void drm_mode_init(struct drm_display_mode *dst, const struct drm_display_mode *src)
0959 {
0960 memset(dst, 0, sizeof(*dst));
0961 drm_mode_copy(dst, src);
0962 }
0963 EXPORT_SYMBOL(drm_mode_init);
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976 struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
0977 const struct drm_display_mode *mode)
0978 {
0979 struct drm_display_mode *nmode;
0980
0981 nmode = drm_mode_create(dev);
0982 if (!nmode)
0983 return NULL;
0984
0985 drm_mode_copy(nmode, mode);
0986
0987 return nmode;
0988 }
0989 EXPORT_SYMBOL(drm_mode_duplicate);
0990
0991 static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
0992 const struct drm_display_mode *mode2)
0993 {
0994 return mode1->hdisplay == mode2->hdisplay &&
0995 mode1->hsync_start == mode2->hsync_start &&
0996 mode1->hsync_end == mode2->hsync_end &&
0997 mode1->htotal == mode2->htotal &&
0998 mode1->hskew == mode2->hskew &&
0999 mode1->vdisplay == mode2->vdisplay &&
1000 mode1->vsync_start == mode2->vsync_start &&
1001 mode1->vsync_end == mode2->vsync_end &&
1002 mode1->vtotal == mode2->vtotal &&
1003 mode1->vscan == mode2->vscan;
1004 }
1005
1006 static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
1007 const struct drm_display_mode *mode2)
1008 {
1009
1010
1011
1012
1013 if (mode1->clock && mode2->clock)
1014 return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
1015 else
1016 return mode1->clock == mode2->clock;
1017 }
1018
1019 static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
1020 const struct drm_display_mode *mode2)
1021 {
1022 return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
1023 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
1024 }
1025
1026 static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
1027 const struct drm_display_mode *mode2)
1028 {
1029 return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
1030 (mode2->flags & DRM_MODE_FLAG_3D_MASK);
1031 }
1032
1033 static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
1034 const struct drm_display_mode *mode2)
1035 {
1036 return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
1037 }
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050 bool drm_mode_match(const struct drm_display_mode *mode1,
1051 const struct drm_display_mode *mode2,
1052 unsigned int match_flags)
1053 {
1054 if (!mode1 && !mode2)
1055 return true;
1056
1057 if (!mode1 || !mode2)
1058 return false;
1059
1060 if (match_flags & DRM_MODE_MATCH_TIMINGS &&
1061 !drm_mode_match_timings(mode1, mode2))
1062 return false;
1063
1064 if (match_flags & DRM_MODE_MATCH_CLOCK &&
1065 !drm_mode_match_clock(mode1, mode2))
1066 return false;
1067
1068 if (match_flags & DRM_MODE_MATCH_FLAGS &&
1069 !drm_mode_match_flags(mode1, mode2))
1070 return false;
1071
1072 if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
1073 !drm_mode_match_3d_flags(mode1, mode2))
1074 return false;
1075
1076 if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
1077 !drm_mode_match_aspect_ratio(mode1, mode2))
1078 return false;
1079
1080 return true;
1081 }
1082 EXPORT_SYMBOL(drm_mode_match);
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094 bool drm_mode_equal(const struct drm_display_mode *mode1,
1095 const struct drm_display_mode *mode2)
1096 {
1097 return drm_mode_match(mode1, mode2,
1098 DRM_MODE_MATCH_TIMINGS |
1099 DRM_MODE_MATCH_CLOCK |
1100 DRM_MODE_MATCH_FLAGS |
1101 DRM_MODE_MATCH_3D_FLAGS|
1102 DRM_MODE_MATCH_ASPECT_RATIO);
1103 }
1104 EXPORT_SYMBOL(drm_mode_equal);
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
1118 const struct drm_display_mode *mode2)
1119 {
1120 return drm_mode_match(mode1, mode2,
1121 DRM_MODE_MATCH_TIMINGS |
1122 DRM_MODE_MATCH_FLAGS |
1123 DRM_MODE_MATCH_3D_FLAGS);
1124 }
1125 EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138 bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
1139 const struct drm_display_mode *mode2)
1140 {
1141 return drm_mode_match(mode1, mode2,
1142 DRM_MODE_MATCH_TIMINGS |
1143 DRM_MODE_MATCH_FLAGS);
1144 }
1145 EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
1146
1147 static enum drm_mode_status
1148 drm_mode_validate_basic(const struct drm_display_mode *mode)
1149 {
1150 if (mode->type & ~DRM_MODE_TYPE_ALL)
1151 return MODE_BAD;
1152
1153 if (mode->flags & ~DRM_MODE_FLAG_ALL)
1154 return MODE_BAD;
1155
1156 if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
1157 return MODE_BAD;
1158
1159 if (mode->clock == 0)
1160 return MODE_CLOCK_LOW;
1161
1162 if (mode->hdisplay == 0 ||
1163 mode->hsync_start < mode->hdisplay ||
1164 mode->hsync_end < mode->hsync_start ||
1165 mode->htotal < mode->hsync_end)
1166 return MODE_H_ILLEGAL;
1167
1168 if (mode->vdisplay == 0 ||
1169 mode->vsync_start < mode->vdisplay ||
1170 mode->vsync_end < mode->vsync_start ||
1171 mode->vtotal < mode->vsync_end)
1172 return MODE_V_ILLEGAL;
1173
1174 return MODE_OK;
1175 }
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189 enum drm_mode_status
1190 drm_mode_validate_driver(struct drm_device *dev,
1191 const struct drm_display_mode *mode)
1192 {
1193 enum drm_mode_status status;
1194
1195 status = drm_mode_validate_basic(mode);
1196 if (status != MODE_OK)
1197 return status;
1198
1199 if (dev->mode_config.funcs->mode_valid)
1200 return dev->mode_config.funcs->mode_valid(dev, mode);
1201 else
1202 return MODE_OK;
1203 }
1204 EXPORT_SYMBOL(drm_mode_validate_driver);
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 enum drm_mode_status
1221 drm_mode_validate_size(const struct drm_display_mode *mode,
1222 int maxX, int maxY)
1223 {
1224 if (maxX > 0 && mode->hdisplay > maxX)
1225 return MODE_VIRTUAL_X;
1226
1227 if (maxY > 0 && mode->vdisplay > maxY)
1228 return MODE_VIRTUAL_Y;
1229
1230 return MODE_OK;
1231 }
1232 EXPORT_SYMBOL(drm_mode_validate_size);
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 enum drm_mode_status
1246 drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
1247 struct drm_connector *connector)
1248 {
1249 if (!connector->ycbcr_420_allowed &&
1250 drm_mode_is_420_only(&connector->display_info, mode))
1251 return MODE_NO_420;
1252
1253 return MODE_OK;
1254 }
1255 EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
1256
1257 #define MODE_STATUS(status) [MODE_ ## status + 3] = #status
1258
1259 static const char * const drm_mode_status_names[] = {
1260 MODE_STATUS(OK),
1261 MODE_STATUS(HSYNC),
1262 MODE_STATUS(VSYNC),
1263 MODE_STATUS(H_ILLEGAL),
1264 MODE_STATUS(V_ILLEGAL),
1265 MODE_STATUS(BAD_WIDTH),
1266 MODE_STATUS(NOMODE),
1267 MODE_STATUS(NO_INTERLACE),
1268 MODE_STATUS(NO_DBLESCAN),
1269 MODE_STATUS(NO_VSCAN),
1270 MODE_STATUS(MEM),
1271 MODE_STATUS(VIRTUAL_X),
1272 MODE_STATUS(VIRTUAL_Y),
1273 MODE_STATUS(MEM_VIRT),
1274 MODE_STATUS(NOCLOCK),
1275 MODE_STATUS(CLOCK_HIGH),
1276 MODE_STATUS(CLOCK_LOW),
1277 MODE_STATUS(CLOCK_RANGE),
1278 MODE_STATUS(BAD_HVALUE),
1279 MODE_STATUS(BAD_VVALUE),
1280 MODE_STATUS(BAD_VSCAN),
1281 MODE_STATUS(HSYNC_NARROW),
1282 MODE_STATUS(HSYNC_WIDE),
1283 MODE_STATUS(HBLANK_NARROW),
1284 MODE_STATUS(HBLANK_WIDE),
1285 MODE_STATUS(VSYNC_NARROW),
1286 MODE_STATUS(VSYNC_WIDE),
1287 MODE_STATUS(VBLANK_NARROW),
1288 MODE_STATUS(VBLANK_WIDE),
1289 MODE_STATUS(PANEL),
1290 MODE_STATUS(INTERLACE_WIDTH),
1291 MODE_STATUS(ONE_WIDTH),
1292 MODE_STATUS(ONE_HEIGHT),
1293 MODE_STATUS(ONE_SIZE),
1294 MODE_STATUS(NO_REDUCED),
1295 MODE_STATUS(NO_STEREO),
1296 MODE_STATUS(NO_420),
1297 MODE_STATUS(STALE),
1298 MODE_STATUS(BAD),
1299 MODE_STATUS(ERROR),
1300 };
1301
1302 #undef MODE_STATUS
1303
1304 const char *drm_get_mode_status_name(enum drm_mode_status status)
1305 {
1306 int index = status + 3;
1307
1308 if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
1309 return "";
1310
1311 return drm_mode_status_names[index];
1312 }
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325 void drm_mode_prune_invalid(struct drm_device *dev,
1326 struct list_head *mode_list, bool verbose)
1327 {
1328 struct drm_display_mode *mode, *t;
1329
1330 list_for_each_entry_safe(mode, t, mode_list, head) {
1331 if (mode->status != MODE_OK) {
1332 list_del(&mode->head);
1333 if (mode->type & DRM_MODE_TYPE_USERDEF) {
1334 drm_warn(dev, "User-defined mode not supported: "
1335 DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
1336 }
1337 if (verbose) {
1338 drm_mode_debug_printmodeline(mode);
1339 DRM_DEBUG_KMS("Not using %s mode: %s\n",
1340 mode->name,
1341 drm_get_mode_status_name(mode->status));
1342 }
1343 drm_mode_destroy(dev, mode);
1344 }
1345 }
1346 }
1347 EXPORT_SYMBOL(drm_mode_prune_invalid);
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362 static int drm_mode_compare(void *priv, const struct list_head *lh_a,
1363 const struct list_head *lh_b)
1364 {
1365 struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
1366 struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
1367 int diff;
1368
1369 diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
1370 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
1371 if (diff)
1372 return diff;
1373 diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
1374 if (diff)
1375 return diff;
1376
1377 diff = drm_mode_vrefresh(b) - drm_mode_vrefresh(a);
1378 if (diff)
1379 return diff;
1380
1381 diff = b->clock - a->clock;
1382 return diff;
1383 }
1384
1385
1386
1387
1388
1389
1390
1391 void drm_mode_sort(struct list_head *mode_list)
1392 {
1393 list_sort(NULL, mode_list, drm_mode_compare);
1394 }
1395 EXPORT_SYMBOL(drm_mode_sort);
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 void drm_connector_list_update(struct drm_connector *connector)
1409 {
1410 struct drm_display_mode *pmode, *pt;
1411
1412 WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
1413
1414 list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
1415 struct drm_display_mode *mode;
1416 bool found_it = false;
1417
1418
1419 list_for_each_entry(mode, &connector->modes, head) {
1420 if (!drm_mode_equal(pmode, mode))
1421 continue;
1422
1423 found_it = true;
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437 if (mode->status == MODE_STALE) {
1438 drm_mode_copy(mode, pmode);
1439 } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
1440 (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1441 pmode->type |= mode->type;
1442 drm_mode_copy(mode, pmode);
1443 } else {
1444 mode->type |= pmode->type;
1445 }
1446
1447 list_del(&pmode->head);
1448 drm_mode_destroy(connector->dev, pmode);
1449 break;
1450 }
1451
1452 if (!found_it) {
1453 list_move_tail(&pmode->head, &connector->modes);
1454 }
1455 }
1456 }
1457 EXPORT_SYMBOL(drm_connector_list_update);
1458
1459 static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
1460 struct drm_cmdline_mode *mode)
1461 {
1462 unsigned int bpp;
1463
1464 if (str[0] != '-')
1465 return -EINVAL;
1466
1467 str++;
1468 bpp = simple_strtol(str, end_ptr, 10);
1469 if (*end_ptr == str)
1470 return -EINVAL;
1471
1472 mode->bpp = bpp;
1473 mode->bpp_specified = true;
1474
1475 return 0;
1476 }
1477
1478 static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
1479 struct drm_cmdline_mode *mode)
1480 {
1481 unsigned int refresh;
1482
1483 if (str[0] != '@')
1484 return -EINVAL;
1485
1486 str++;
1487 refresh = simple_strtol(str, end_ptr, 10);
1488 if (*end_ptr == str)
1489 return -EINVAL;
1490
1491 mode->refresh = refresh;
1492 mode->refresh_specified = true;
1493
1494 return 0;
1495 }
1496
1497 static int drm_mode_parse_cmdline_extra(const char *str, int length,
1498 bool freestanding,
1499 const struct drm_connector *connector,
1500 struct drm_cmdline_mode *mode)
1501 {
1502 int i;
1503
1504 for (i = 0; i < length; i++) {
1505 switch (str[i]) {
1506 case 'i':
1507 if (freestanding)
1508 return -EINVAL;
1509
1510 mode->interlace = true;
1511 break;
1512 case 'm':
1513 if (freestanding)
1514 return -EINVAL;
1515
1516 mode->margins = true;
1517 break;
1518 case 'D':
1519 if (mode->force != DRM_FORCE_UNSPECIFIED)
1520 return -EINVAL;
1521
1522 if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
1523 (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
1524 mode->force = DRM_FORCE_ON;
1525 else
1526 mode->force = DRM_FORCE_ON_DIGITAL;
1527 break;
1528 case 'd':
1529 if (mode->force != DRM_FORCE_UNSPECIFIED)
1530 return -EINVAL;
1531
1532 mode->force = DRM_FORCE_OFF;
1533 break;
1534 case 'e':
1535 if (mode->force != DRM_FORCE_UNSPECIFIED)
1536 return -EINVAL;
1537
1538 mode->force = DRM_FORCE_ON;
1539 break;
1540 default:
1541 return -EINVAL;
1542 }
1543 }
1544
1545 return 0;
1546 }
1547
1548 static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
1549 bool extras,
1550 const struct drm_connector *connector,
1551 struct drm_cmdline_mode *mode)
1552 {
1553 const char *str_start = str;
1554 bool rb = false, cvt = false;
1555 int xres = 0, yres = 0;
1556 int remaining, i;
1557 char *end_ptr;
1558
1559 xres = simple_strtol(str, &end_ptr, 10);
1560 if (end_ptr == str)
1561 return -EINVAL;
1562
1563 if (end_ptr[0] != 'x')
1564 return -EINVAL;
1565 end_ptr++;
1566
1567 str = end_ptr;
1568 yres = simple_strtol(str, &end_ptr, 10);
1569 if (end_ptr == str)
1570 return -EINVAL;
1571
1572 remaining = length - (end_ptr - str_start);
1573 if (remaining < 0)
1574 return -EINVAL;
1575
1576 for (i = 0; i < remaining; i++) {
1577 switch (end_ptr[i]) {
1578 case 'M':
1579 cvt = true;
1580 break;
1581 case 'R':
1582 rb = true;
1583 break;
1584 default:
1585
1586
1587
1588
1589
1590 if (extras) {
1591 int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
1592 1,
1593 false,
1594 connector,
1595 mode);
1596 if (ret)
1597 return ret;
1598 } else {
1599 return -EINVAL;
1600 }
1601 }
1602 }
1603
1604 mode->xres = xres;
1605 mode->yres = yres;
1606 mode->cvt = cvt;
1607 mode->rb = rb;
1608
1609 return 0;
1610 }
1611
1612 static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
1613 {
1614 const char *value;
1615 char *endp;
1616
1617
1618
1619
1620
1621
1622 if (*delim != '=')
1623 return -EINVAL;
1624
1625 value = delim + 1;
1626 *int_ret = simple_strtol(value, &endp, 10);
1627
1628
1629 if (endp == value)
1630 return -EINVAL;
1631
1632 return 0;
1633 }
1634
1635 static int drm_mode_parse_panel_orientation(const char *delim,
1636 struct drm_cmdline_mode *mode)
1637 {
1638 const char *value;
1639
1640 if (*delim != '=')
1641 return -EINVAL;
1642
1643 value = delim + 1;
1644 delim = strchr(value, ',');
1645 if (!delim)
1646 delim = value + strlen(value);
1647
1648 if (!strncmp(value, "normal", delim - value))
1649 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
1650 else if (!strncmp(value, "upside_down", delim - value))
1651 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
1652 else if (!strncmp(value, "left_side_up", delim - value))
1653 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
1654 else if (!strncmp(value, "right_side_up", delim - value))
1655 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
1656 else
1657 return -EINVAL;
1658
1659 return 0;
1660 }
1661
1662 static int drm_mode_parse_cmdline_options(const char *str,
1663 bool freestanding,
1664 const struct drm_connector *connector,
1665 struct drm_cmdline_mode *mode)
1666 {
1667 unsigned int deg, margin, rotation = 0;
1668 const char *delim, *option, *sep;
1669
1670 option = str;
1671 do {
1672 delim = strchr(option, '=');
1673 if (!delim) {
1674 delim = strchr(option, ',');
1675
1676 if (!delim)
1677 delim = option + strlen(option);
1678 }
1679
1680 if (!strncmp(option, "rotate", delim - option)) {
1681 if (drm_mode_parse_cmdline_int(delim, °))
1682 return -EINVAL;
1683
1684 switch (deg) {
1685 case 0:
1686 rotation |= DRM_MODE_ROTATE_0;
1687 break;
1688
1689 case 90:
1690 rotation |= DRM_MODE_ROTATE_90;
1691 break;
1692
1693 case 180:
1694 rotation |= DRM_MODE_ROTATE_180;
1695 break;
1696
1697 case 270:
1698 rotation |= DRM_MODE_ROTATE_270;
1699 break;
1700
1701 default:
1702 return -EINVAL;
1703 }
1704 } else if (!strncmp(option, "reflect_x", delim - option)) {
1705 rotation |= DRM_MODE_REFLECT_X;
1706 } else if (!strncmp(option, "reflect_y", delim - option)) {
1707 rotation |= DRM_MODE_REFLECT_Y;
1708 } else if (!strncmp(option, "margin_right", delim - option)) {
1709 if (drm_mode_parse_cmdline_int(delim, &margin))
1710 return -EINVAL;
1711
1712 mode->tv_margins.right = margin;
1713 } else if (!strncmp(option, "margin_left", delim - option)) {
1714 if (drm_mode_parse_cmdline_int(delim, &margin))
1715 return -EINVAL;
1716
1717 mode->tv_margins.left = margin;
1718 } else if (!strncmp(option, "margin_top", delim - option)) {
1719 if (drm_mode_parse_cmdline_int(delim, &margin))
1720 return -EINVAL;
1721
1722 mode->tv_margins.top = margin;
1723 } else if (!strncmp(option, "margin_bottom", delim - option)) {
1724 if (drm_mode_parse_cmdline_int(delim, &margin))
1725 return -EINVAL;
1726
1727 mode->tv_margins.bottom = margin;
1728 } else if (!strncmp(option, "panel_orientation", delim - option)) {
1729 if (drm_mode_parse_panel_orientation(delim, mode))
1730 return -EINVAL;
1731 } else {
1732 return -EINVAL;
1733 }
1734 sep = strchr(delim, ',');
1735 option = sep + 1;
1736 } while (sep);
1737
1738 if (rotation && freestanding)
1739 return -EINVAL;
1740
1741 if (!(rotation & DRM_MODE_ROTATE_MASK))
1742 rotation |= DRM_MODE_ROTATE_0;
1743
1744
1745 if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
1746 return -EINVAL;
1747
1748 mode->rotation_reflection = rotation;
1749
1750 return 0;
1751 }
1752
1753 static const char * const drm_named_modes_whitelist[] = {
1754 "NTSC",
1755 "PAL",
1756 };
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783 bool drm_mode_parse_command_line_for_connector(const char *mode_option,
1784 const struct drm_connector *connector,
1785 struct drm_cmdline_mode *mode)
1786 {
1787 const char *name;
1788 bool freestanding = false, parse_extras = false;
1789 unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
1790 unsigned int mode_end = 0;
1791 const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
1792 const char *options_ptr = NULL;
1793 char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
1794 int i, len, ret;
1795
1796 memset(mode, 0, sizeof(*mode));
1797 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
1798
1799 if (!mode_option)
1800 return false;
1801
1802 name = mode_option;
1803
1804
1805 bpp_ptr = strchr(name, '-');
1806 if (bpp_ptr)
1807 bpp_off = bpp_ptr - name;
1808
1809 refresh_ptr = strchr(name, '@');
1810 if (refresh_ptr)
1811 refresh_off = refresh_ptr - name;
1812
1813
1814 options_ptr = strchr(name, ',');
1815 if (options_ptr)
1816 options_off = options_ptr - name;
1817
1818
1819 if (bpp_ptr) {
1820 mode_end = bpp_off;
1821 } else if (refresh_ptr) {
1822 mode_end = refresh_off;
1823 } else if (options_ptr) {
1824 mode_end = options_off;
1825 parse_extras = true;
1826 } else {
1827 mode_end = strlen(name);
1828 parse_extras = true;
1829 }
1830
1831
1832 for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
1833 ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
1834 if (ret == mode_end) {
1835 if (refresh_ptr)
1836 return false;
1837
1838 strcpy(mode->name, drm_named_modes_whitelist[i]);
1839 mode->specified = true;
1840 break;
1841 }
1842 }
1843
1844
1845 if (!mode->specified && isdigit(name[0])) {
1846 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
1847 parse_extras,
1848 connector,
1849 mode);
1850 if (ret)
1851 return false;
1852
1853 mode->specified = true;
1854 }
1855
1856
1857 if (!mode->specified) {
1858 unsigned int len = strlen(mode_option);
1859
1860 if (bpp_ptr || refresh_ptr)
1861 return false;
1862
1863 if (len == 1 || (len >= 2 && mode_option[1] == ','))
1864 extra_ptr = mode_option;
1865 else
1866 options_ptr = mode_option - 1;
1867
1868 freestanding = true;
1869 }
1870
1871 if (bpp_ptr) {
1872 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
1873 if (ret)
1874 return false;
1875
1876 mode->bpp_specified = true;
1877 }
1878
1879 if (refresh_ptr) {
1880 ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
1881 &refresh_end_ptr, mode);
1882 if (ret)
1883 return false;
1884
1885 mode->refresh_specified = true;
1886 }
1887
1888
1889
1890
1891
1892 if (bpp_ptr && refresh_ptr)
1893 extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
1894 else if (bpp_ptr)
1895 extra_ptr = bpp_end_ptr;
1896 else if (refresh_ptr)
1897 extra_ptr = refresh_end_ptr;
1898
1899 if (extra_ptr) {
1900 if (options_ptr)
1901 len = options_ptr - extra_ptr;
1902 else
1903 len = strlen(extra_ptr);
1904
1905 ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
1906 connector, mode);
1907 if (ret)
1908 return false;
1909 }
1910
1911 if (options_ptr) {
1912 ret = drm_mode_parse_cmdline_options(options_ptr + 1,
1913 freestanding,
1914 connector, mode);
1915 if (ret)
1916 return false;
1917 }
1918
1919 return true;
1920 }
1921 EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931 struct drm_display_mode *
1932 drm_mode_create_from_cmdline_mode(struct drm_device *dev,
1933 struct drm_cmdline_mode *cmd)
1934 {
1935 struct drm_display_mode *mode;
1936
1937 if (cmd->xres == 0 || cmd->yres == 0)
1938 return NULL;
1939
1940 if (cmd->cvt)
1941 mode = drm_cvt_mode(dev,
1942 cmd->xres, cmd->yres,
1943 cmd->refresh_specified ? cmd->refresh : 60,
1944 cmd->rb, cmd->interlace,
1945 cmd->margins);
1946 else
1947 mode = drm_gtf_mode(dev,
1948 cmd->xres, cmd->yres,
1949 cmd->refresh_specified ? cmd->refresh : 60,
1950 cmd->interlace,
1951 cmd->margins);
1952 if (!mode)
1953 return NULL;
1954
1955 mode->type |= DRM_MODE_TYPE_USERDEF;
1956
1957 if (cmd->xres == 1366)
1958 drm_mode_fixup_1366x768(mode);
1959 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1960 return mode;
1961 }
1962 EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972 void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
1973 const struct drm_display_mode *in)
1974 {
1975 out->clock = in->clock;
1976 out->hdisplay = in->hdisplay;
1977 out->hsync_start = in->hsync_start;
1978 out->hsync_end = in->hsync_end;
1979 out->htotal = in->htotal;
1980 out->hskew = in->hskew;
1981 out->vdisplay = in->vdisplay;
1982 out->vsync_start = in->vsync_start;
1983 out->vsync_end = in->vsync_end;
1984 out->vtotal = in->vtotal;
1985 out->vscan = in->vscan;
1986 out->vrefresh = drm_mode_vrefresh(in);
1987 out->flags = in->flags;
1988 out->type = in->type;
1989
1990 switch (in->picture_aspect_ratio) {
1991 case HDMI_PICTURE_ASPECT_4_3:
1992 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
1993 break;
1994 case HDMI_PICTURE_ASPECT_16_9:
1995 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
1996 break;
1997 case HDMI_PICTURE_ASPECT_64_27:
1998 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
1999 break;
2000 case HDMI_PICTURE_ASPECT_256_135:
2001 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
2002 break;
2003 default:
2004 WARN(1, "Invalid aspect ratio (0%x) on mode\n",
2005 in->picture_aspect_ratio);
2006 fallthrough;
2007 case HDMI_PICTURE_ASPECT_NONE:
2008 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
2009 break;
2010 }
2011
2012 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
2013 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
2014 }
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028 int drm_mode_convert_umode(struct drm_device *dev,
2029 struct drm_display_mode *out,
2030 const struct drm_mode_modeinfo *in)
2031 {
2032 if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
2033 return -ERANGE;
2034
2035 out->clock = in->clock;
2036 out->hdisplay = in->hdisplay;
2037 out->hsync_start = in->hsync_start;
2038 out->hsync_end = in->hsync_end;
2039 out->htotal = in->htotal;
2040 out->hskew = in->hskew;
2041 out->vdisplay = in->vdisplay;
2042 out->vsync_start = in->vsync_start;
2043 out->vsync_end = in->vsync_end;
2044 out->vtotal = in->vtotal;
2045 out->vscan = in->vscan;
2046 out->flags = in->flags;
2047
2048
2049
2050
2051
2052
2053 out->type = in->type & DRM_MODE_TYPE_ALL;
2054 strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
2055 out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
2056
2057
2058
2059
2060
2061 out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
2062
2063 switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
2064 case DRM_MODE_FLAG_PIC_AR_4_3:
2065 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
2066 break;
2067 case DRM_MODE_FLAG_PIC_AR_16_9:
2068 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
2069 break;
2070 case DRM_MODE_FLAG_PIC_AR_64_27:
2071 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
2072 break;
2073 case DRM_MODE_FLAG_PIC_AR_256_135:
2074 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
2075 break;
2076 case DRM_MODE_FLAG_PIC_AR_NONE:
2077 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
2078 break;
2079 default:
2080 return -EINVAL;
2081 }
2082
2083 out->status = drm_mode_validate_driver(dev, out);
2084 if (out->status != MODE_OK)
2085 return -EINVAL;
2086
2087 drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
2088
2089 return 0;
2090 }
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103 bool drm_mode_is_420_only(const struct drm_display_info *display,
2104 const struct drm_display_mode *mode)
2105 {
2106 u8 vic = drm_match_cea_mode(mode);
2107
2108 return test_bit(vic, display->hdmi.y420_vdb_modes);
2109 }
2110 EXPORT_SYMBOL(drm_mode_is_420_only);
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123 bool drm_mode_is_420_also(const struct drm_display_info *display,
2124 const struct drm_display_mode *mode)
2125 {
2126 u8 vic = drm_match_cea_mode(mode);
2127
2128 return test_bit(vic, display->hdmi.y420_cmdb_modes);
2129 }
2130 EXPORT_SYMBOL(drm_mode_is_420_also);
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142 bool drm_mode_is_420(const struct drm_display_info *display,
2143 const struct drm_display_mode *mode)
2144 {
2145 return drm_mode_is_420_only(display, mode) ||
2146 drm_mode_is_420_also(display, mode);
2147 }
2148 EXPORT_SYMBOL(drm_mode_is_420);