Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 1997-2003 by The XFree86 Project, Inc.
0003  * Copyright © 2007 Dave Airlie
0004  * Copyright © 2007-2008 Intel Corporation
0005  *   Jesse Barnes <jesse.barnes@intel.com>
0006  * Copyright 2005-2006 Luc Verhaegen
0007  * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
0008  *
0009  * Permission is hereby granted, free of charge, to any person obtaining a
0010  * copy of this software and associated documentation files (the "Software"),
0011  * to deal in the Software without restriction, including without limitation
0012  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0013  * and/or sell copies of the Software, and to permit persons to whom the
0014  * Software is furnished to do so, subject to the following conditions:
0015  *
0016  * The above copyright notice and this permission notice shall be included in
0017  * all copies or substantial portions of the Software.
0018  *
0019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0020  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0021  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0022  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0023  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0024  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0025  * OTHER DEALINGS IN THE SOFTWARE.
0026  *
0027  * Except as contained in this notice, the name of the copyright holder(s)
0028  * and author(s) shall not be used in advertising or otherwise to promote
0029  * the sale, use or other dealings in this Software without prior written
0030  * authorization from the copyright holder(s) and author(s).
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  * drm_mode_debug_printmodeline - print a mode to dmesg
0053  * @mode: mode to print
0054  *
0055  * Describe @mode using DRM_DEBUG.
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  * drm_mode_create - create a new display mode
0065  * @dev: DRM device
0066  *
0067  * Create a new, cleared drm_display_mode with kzalloc, allocate an ID for it
0068  * and return it.
0069  *
0070  * Returns:
0071  * Pointer to new mode on success, NULL on error.
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  * drm_mode_destroy - remove a mode
0087  * @dev: DRM device
0088  * @mode: mode to remove
0089  *
0090  * Release @mode's unique ID, then free it @mode structure itself using kfree.
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  * drm_mode_probed_add - add a mode to a connector's probed_mode list
0103  * @connector: connector the new mode
0104  * @mode: mode data
0105  *
0106  * Add @mode to @connector's probed_mode list for later use. This list should
0107  * then in a second step get filtered and all the modes actually supported by
0108  * the hardware moved to the @connector's modes list.
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  * drm_cvt_mode -create a modeline based on the CVT algorithm
0121  * @dev: drm device
0122  * @hdisplay: hdisplay size
0123  * @vdisplay: vdisplay size
0124  * @vrefresh: vrefresh rate
0125  * @reduced: whether to use reduced blanking
0126  * @interlaced: whether to compute an interlaced mode
0127  * @margins: whether to add margins (borders)
0128  *
0129  * This function is called to generate the modeline based on CVT algorithm
0130  * according to the hdisplay, vdisplay, vrefresh.
0131  * It is based from the VESA(TM) Coordinated Video Timing Generator by
0132  * Graham Loveridge April 9, 2003 available at
0133  * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
0134  *
0135  * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
0136  * What I have done is to translate it by using integer calculation.
0137  *
0138  * Returns:
0139  * The modeline based on the CVT algorithm stored in a drm_display_mode object.
0140  * The display mode object is allocated with drm_mode_create(). Returns NULL
0141  * when no mode could be allocated.
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     /* 1) top/bottom margin size (% of height) - default: 1.8, */
0149 #define CVT_MARGIN_PERCENTAGE       18
0150     /* 2) character cell horizontal granularity (pixels) - default 8 */
0151 #define CVT_H_GRANULARITY       8
0152     /* 3) Minimum vertical porch (lines) - default 3 */
0153 #define CVT_MIN_V_PORCH         3
0154     /* 4) Minimum number of vertical back porch lines - default 6 */
0155 #define CVT_MIN_V_BPORCH        6
0156     /* Pixel Clock step (kHz) */
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     /* allocate the drm_display_mode structure. If failure, we will
0168      * return directly
0169      */
0170     drm_mode = drm_mode_create(dev);
0171     if (!drm_mode)
0172         return NULL;
0173 
0174     /* the CVT default refresh rate is 60Hz */
0175     if (!vrefresh)
0176         vrefresh = 60;
0177 
0178     /* the required field fresh rate */
0179     if (interlaced)
0180         vfieldrate = vrefresh * 2;
0181     else
0182         vfieldrate = vrefresh;
0183 
0184     /* horizontal pixels */
0185     hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
0186 
0187     /* determine the left&right borders */
0188     hmargin = 0;
0189     if (margins) {
0190         hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
0191         hmargin -= hmargin % CVT_H_GRANULARITY;
0192     }
0193     /* find the total active pixels */
0194     drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
0195 
0196     /* find the number of lines per field */
0197     if (interlaced)
0198         vdisplay_rnd = vdisplay / 2;
0199     else
0200         vdisplay_rnd = vdisplay;
0201 
0202     /* find the top & bottom borders */
0203     vmargin = 0;
0204     if (margins)
0205         vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
0206 
0207     drm_mode->vdisplay = vdisplay + 2 * vmargin;
0208 
0209     /* Interlaced */
0210     if (interlaced)
0211         interlace = 1;
0212     else
0213         interlace = 0;
0214 
0215     /* Determine VSync Width from aspect ratio */
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 /* custom */
0227         vsync = 10;
0228 
0229     if (!reduced) {
0230         /* simplify the GTF calculation */
0231         /* 4) Minimum time of vertical sync + back porch interval (µs)
0232          * default 550.0
0233          */
0234         int tmp1, tmp2;
0235 #define CVT_MIN_VSYNC_BP    550
0236         /* 3) Nominal HSync width (% of line period) - default 8 */
0237 #define CVT_HSYNC_PERCENTAGE    8
0238         unsigned int hblank_percentage;
0239         int vsyncandback_porch, __maybe_unused vback_porch, hblank;
0240 
0241         /* estimated the horizontal period */
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         /* 9. Find number of lines in sync + backporch */
0250         if (tmp1 < (vsync + CVT_MIN_V_PORCH))
0251             vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
0252         else
0253             vsyncandback_porch = tmp1;
0254         /* 10. Find number of lines in back porch */
0255         vback_porch = vsyncandback_porch - vsync;
0256         drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
0257                 vsyncandback_porch + CVT_MIN_V_PORCH;
0258         /* 5) Definition of Horizontal blanking time limitation */
0259         /* Gradient (%/kHz) - default 600 */
0260 #define CVT_M_FACTOR    600
0261         /* Offset (%) - default 40 */
0262 #define CVT_C_FACTOR    40
0263         /* Blanking time scaling factor - default 128 */
0264 #define CVT_K_FACTOR    128
0265         /* Scaling factor weighting - default 20 */
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         /* 12. Find ideal blanking duty cycle from formula */
0271         hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
0272                     hperiod / 1000;
0273         /* 13. Blanking time */
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         /* 14. find the total pixels per line */
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         /* fill the Vsync values */
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         /* Reduced blanking */
0291         /* Minimum vertical blanking interval time (µs)- default 460 */
0292 #define CVT_RB_MIN_VBLANK   460
0293         /* Fixed number of clocks for horizontal sync */
0294 #define CVT_RB_H_SYNC       32
0295         /* Fixed number of clocks for horizontal blanking */
0296 #define CVT_RB_H_BLANK      160
0297         /* Fixed number of lines for vertical front porch - default 3*/
0298 #define CVT_RB_VFPORCH      3
0299         int vbilines;
0300         int tmp1, tmp2;
0301         /* 8. Estimate Horizontal period. */
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         /* 9. Find number of lines in vertical blanking */
0307         vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
0308         /* 10. Check if vertical blanking is sufficient */
0309         if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
0310             vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
0311         /* 11. Find total number of lines in vertical field */
0312         drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
0313         /* 12. Find total number of pixels in a line */
0314         drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
0315         /* Fill in HSync values */
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         /* Fill in VSync values */
0319         drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
0320         drm_mode->vsync_end = drm_mode->vsync_start + vsync;
0321     }
0322     /* 15/13. Find pixel clock frequency (kHz for xf86) */
0323     tmp = drm_mode->htotal; /* perform intermediate calcs in u64 */
0324     tmp *= HV_FACTOR * 1000;
0325     do_div(tmp, hperiod);
0326     tmp -= drm_mode->clock % CVT_CLOCK_STEP;
0327     drm_mode->clock = tmp;
0328     /* 18/16. Find actual vertical frame frequency */
0329     /* ignore - just set the mode flag for interlaced */
0330     if (interlaced) {
0331         drm_mode->vtotal *= 2;
0332         drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
0333     }
0334     /* Fill the mode line name */
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  * drm_gtf_mode_complex - create the modeline based on the full GTF algorithm
0349  * @dev: drm device
0350  * @hdisplay: hdisplay size
0351  * @vdisplay: vdisplay size
0352  * @vrefresh: vrefresh rate.
0353  * @interlaced: whether to compute an interlaced mode
0354  * @margins: desired margin (borders) size
0355  * @GTF_M: extended GTF formula parameters
0356  * @GTF_2C: extended GTF formula parameters
0357  * @GTF_K: extended GTF formula parameters
0358  * @GTF_2J: extended GTF formula parameters
0359  *
0360  * GTF feature blocks specify C and J in multiples of 0.5, so we pass them
0361  * in here multiplied by two.  For a C of 40, pass in 80.
0362  *
0363  * Returns:
0364  * The modeline based on the full GTF algorithm stored in a drm_display_mode object.
0365  * The display mode object is allocated with drm_mode_create(). Returns NULL
0366  * when no mode could be allocated.
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 {   /* 1) top/bottom margin size (% of height) - default: 1.8, */
0373 #define GTF_MARGIN_PERCENTAGE       18
0374     /* 2) character cell horizontal granularity (pixels) - default 8 */
0375 #define GTF_CELL_GRAN           8
0376     /* 3) Minimum vertical porch (lines) - default 3 */
0377 #define GTF_MIN_V_PORCH         1
0378     /* width of vsync in lines */
0379 #define V_SYNC_RQD          3
0380     /* width of hsync as % of total line */
0381 #define H_SYNC_PERCENT          8
0382     /* min time of vsync + back porch (microsec) */
0383 #define MIN_VSYNC_PLUS_BP       550
0384     /* C' and M' are part of the Blanking Duty Cycle computation */
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     /* 1. In order to give correct results, the number of horizontal
0410      * pixels requested is first processed to ensure that it is divisible
0411      * by the character size, by rounding it to the nearest character
0412      * cell boundary:
0413      */
0414     hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
0415     hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
0416 
0417     /* 2. If interlace is requested, the number of vertical lines assumed
0418      * by the calculation must be halved, as the computation calculates
0419      * the number of vertical lines per field.
0420      */
0421     if (interlaced)
0422         vdisplay_rnd = vdisplay / 2;
0423     else
0424         vdisplay_rnd = vdisplay;
0425 
0426     /* 3. Find the frame rate required: */
0427     if (interlaced)
0428         vfieldrate_rqd = vrefresh * 2;
0429     else
0430         vfieldrate_rqd = vrefresh;
0431 
0432     /* 4. Find number of lines in Top margin: */
0433     top_margin = 0;
0434     if (margins)
0435         top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
0436                 1000;
0437     /* 5. Find number of lines in bottom margin: */
0438     bottom_margin = top_margin;
0439 
0440     /* 6. If interlace is required, then set variable interlace: */
0441     if (interlaced)
0442         interlace = 1;
0443     else
0444         interlace = 0;
0445 
0446     /* 7. Estimate the Horizontal frequency */
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     /* 8. Find the number of lines in V sync + back porch */
0455     /* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
0456     vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
0457     vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
0458     /*  9. Find the number of lines in V back porch alone: */
0459     vback_porch = vsync_plus_bp - V_SYNC_RQD;
0460     /*  10. Find the total number of lines in Vertical field period: */
0461     vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
0462             vsync_plus_bp + GTF_MIN_V_PORCH;
0463     /*  11. Estimate the Vertical field frequency: */
0464     vfieldrate_est = hfreq_est / vtotal_lines;
0465     /*  12. Find the actual horizontal period: */
0466     hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
0467 
0468     /*  13. Find the actual Vertical field frequency: */
0469     vfield_rate = hfreq_est / vtotal_lines;
0470     /*  14. Find the Vertical frame frequency: */
0471     if (interlaced)
0472         vframe_rate = vfield_rate / 2;
0473     else
0474         vframe_rate = vfield_rate;
0475     /*  15. Find number of pixels in left margin: */
0476     if (margins)
0477         left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
0478                 1000;
0479     else
0480         left_margin = 0;
0481 
0482     /* 16.Find number of pixels in right margin: */
0483     right_margin = left_margin;
0484     /* 17.Find total number of active pixels in image and left and right */
0485     total_active_pixels = hdisplay_rnd + left_margin + right_margin;
0486     /* 18.Find the ideal blanking duty cycle from blanking duty cycle */
0487     ideal_duty_cycle = GTF_C_PRIME * 1000 -
0488                 (GTF_M_PRIME * 1000000 / hfreq_est);
0489     /* 19.Find the number of pixels in the blanking time to the nearest
0490      * double character cell: */
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     /* 20.Find total number of pixels: */
0496     total_pixels = total_active_pixels + hblank;
0497     /* 21.Find pixel clock frequency: */
0498     pixel_freq = total_pixels * hfreq_est / 1000;
0499     /* Stage 1 computations are now complete; I should really pass
0500      * the results to another function and do the Stage 2 computations,
0501      * but I only need a few more values so I'll just append the
0502      * computations here for now */
0503     /* 17. Find the number of pixels in the horizontal sync period: */
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     /* 18. Find the number of pixels in horizontal front porch period */
0508     hfront_porch = hblank / 2 - hsync;
0509     /*  36. Find the number of lines in the odd front porch period: */
0510     vodd_front_porch_lines = GTF_MIN_V_PORCH ;
0511 
0512     /* finally, pack the results in the mode struct */
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  * drm_gtf_mode - create the modeline based on the GTF algorithm
0541  * @dev: drm device
0542  * @hdisplay: hdisplay size
0543  * @vdisplay: vdisplay size
0544  * @vrefresh: vrefresh rate.
0545  * @interlaced: whether to compute an interlaced mode
0546  * @margins: desired margin (borders) size
0547  *
0548  * return the modeline based on GTF algorithm
0549  *
0550  * This function is to create the modeline based on the GTF algorithm.
0551  * Generalized Timing Formula is derived from:
0552  *
0553  *  GTF Spreadsheet by Andy Morrish (1/5/97)
0554  *  available at https://www.vesa.org
0555  *
0556  * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
0557  * What I have done is to translate it by using integer calculation.
0558  * I also refer to the function of fb_get_mode in the file of
0559  * drivers/video/fbmon.c
0560  *
0561  * Standard GTF parameters::
0562  *
0563  *     M = 600
0564  *     C = 40
0565  *     K = 128
0566  *     J = 20
0567  *
0568  * Returns:
0569  * The modeline based on the GTF algorithm stored in a drm_display_mode object.
0570  * The display mode object is allocated with drm_mode_create(). Returns NULL
0571  * when no mode could be allocated.
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  * drm_display_mode_from_videomode - fill in @dmode using @vm,
0586  * @vm: videomode structure to use as source
0587  * @dmode: drm_display_mode structure to use as destination
0588  *
0589  * Fills out @dmode using the display mode specified in @vm.
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  * drm_display_mode_to_videomode - fill in @vm using @dmode,
0627  * @dmode: drm_display_mode structure to use as source
0628  * @vm: videomode structure to use as destination
0629  *
0630  * Fills out @vm using the display mode specified in @dmode.
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  * drm_bus_flags_from_videomode - extract information about pixelclk and
0667  * DE polarity from videomode and store it in a separate variable
0668  * @vm: videomode structure to use
0669  * @bus_flags: information about pixelclk, sync and DE polarity will be stored
0670  * here
0671  *
0672  * Sets DRM_BUS_FLAG_DE_(LOW|HIGH),  DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE
0673  * and DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
0674  * found in @vm
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  * of_get_drm_display_mode - get a drm_display_mode from devicetree
0699  * @np: device_node with the timing specification
0700  * @dmode: will be set to the return value
0701  * @bus_flags: information about pixelclk, sync and DE polarity
0702  * @index: index into the list of display timings in devicetree
0703  *
0704  * This function is expensive and should only be used, if only one mode is to be
0705  * read from DT. To get multiple modes start with of_get_display_timings and
0706  * work with that instead.
0707  *
0708  * Returns:
0709  * 0 on success, a negative errno code when no of videomode node was found.
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  * of_get_drm_panel_display_mode - get a panel-timing drm_display_mode from devicetree
0736  * @np: device_node with the panel-timing specification
0737  * @dmode: will be set to the return value
0738  * @bus_flags: information about pixelclk, sync and DE polarity
0739  *
0740  * The mandatory Device Tree properties width-mm and height-mm
0741  * are read and set on the display mode.
0742  *
0743  * Returns:
0744  * Zero on success, negative error code on failure.
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 /* CONFIG_OF */
0782 #endif /* CONFIG_VIDEOMODE_HELPERS */
0783 
0784 /**
0785  * drm_mode_set_name - set the name on a mode
0786  * @mode: name will be set in this mode
0787  *
0788  * Set the name of @mode to a standard format which is <hdisplay>x<vdisplay>
0789  * with an optional 'i' suffix for interlaced modes.
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  * drm_mode_vrefresh - get the vrefresh of a mode
0803  * @mode: mode
0804  *
0805  * Returns:
0806  * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the
0807  * value first if it is not yet set.
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  * drm_mode_get_hv_timing - Fetches hdisplay/vdisplay for given mode
0832  * @mode: mode to query
0833  * @hdisplay: hdisplay value to fill in
0834  * @vdisplay: vdisplay value to fill in
0835  *
0836  * The vdisplay value will be doubled if the specified mode is a stereo mode of
0837  * the appropriate layout.
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  * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
0854  * @p: mode
0855  * @adjust_flags: a combination of adjustment flags
0856  *
0857  * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
0858  *
0859  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
0860  *   interlaced modes.
0861  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
0862  *   buffers containing two eyes (only adjust the timings when needed, eg. for
0863  *   "frame packing" or "side by side full").
0864  * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
0865  *   be performed for doublescan and vscan > 1 modes respectively.
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  * drm_mode_copy - copy the mode
0933  * @dst: mode to overwrite
0934  * @src: mode to copy
0935  *
0936  * Copy an existing mode into another mode, preserving the
0937  * list head of the destination mode.
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  * drm_mode_init - initialize the mode from another mode
0950  * @dst: mode to overwrite
0951  * @src: mode to copy
0952  *
0953  * Copy an existing mode into another mode, zeroing the
0954  * list head of the destination mode. Typically used
0955  * to guarantee the list head is not left with stack
0956  * garbage in on-stack modes.
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  * drm_mode_duplicate - allocate and duplicate an existing mode
0967  * @dev: drm_device to allocate the duplicated mode for
0968  * @mode: mode to duplicate
0969  *
0970  * Just allocate a new mode, copy the existing mode into it, and return
0971  * a pointer to it.  Used to create new instances of established modes.
0972  *
0973  * Returns:
0974  * Pointer to duplicated mode on success, NULL on error.
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      * do clock check convert to PICOS
1011      * so fb modes get matched the same
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  * drm_mode_match - test modes for (partial) equality
1041  * @mode1: first mode
1042  * @mode2: second mode
1043  * @match_flags: which parts need to match (DRM_MODE_MATCH_*)
1044  *
1045  * Check to see if @mode1 and @mode2 are equivalent.
1046  *
1047  * Returns:
1048  * True if the modes are (partially) equal, false otherwise.
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  * drm_mode_equal - test modes for equality
1086  * @mode1: first mode
1087  * @mode2: second mode
1088  *
1089  * Check to see if @mode1 and @mode2 are equivalent.
1090  *
1091  * Returns:
1092  * True if the modes are equal, false otherwise.
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  * drm_mode_equal_no_clocks - test modes for equality
1108  * @mode1: first mode
1109  * @mode2: second mode
1110  *
1111  * Check to see if @mode1 and @mode2 are equivalent, but
1112  * don't check the pixel clocks.
1113  *
1114  * Returns:
1115  * True if the modes are equal, false otherwise.
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  * drm_mode_equal_no_clocks_no_stereo - test modes for equality
1129  * @mode1: first mode
1130  * @mode2: second mode
1131  *
1132  * Check to see if @mode1 and @mode2 are equivalent, but
1133  * don't check the pixel clocks nor the stereo layout.
1134  *
1135  * Returns:
1136  * True if the modes are equal, false otherwise.
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  * drm_mode_validate_driver - make sure the mode is somewhat sane
1179  * @dev: drm device
1180  * @mode: mode to check
1181  *
1182  * First do basic validation on the mode, and then allow the driver
1183  * to check for device/driver specific limitations via the optional
1184  * &drm_mode_config_helper_funcs.mode_valid hook.
1185  *
1186  * Returns:
1187  * The mode status
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  * drm_mode_validate_size - make sure modes adhere to size constraints
1208  * @mode: mode to check
1209  * @maxX: maximum width
1210  * @maxY: maximum height
1211  *
1212  * This function is a helper which can be used to validate modes against size
1213  * limitations of the DRM device/connector. If a mode is too big its status
1214  * member is updated with the appropriate validation failure code. The list
1215  * itself is not changed.
1216  *
1217  * Returns:
1218  * The mode status
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  * drm_mode_validate_ycbcr420 - add 'ycbcr420-only' modes only when allowed
1236  * @mode: mode to check
1237  * @connector: drm connector under action
1238  *
1239  * This function is a helper which can be used to filter out any YCBCR420
1240  * only mode, when the source doesn't support it.
1241  *
1242  * Returns:
1243  * The mode status
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  * drm_mode_prune_invalid - remove invalid modes from mode list
1316  * @dev: DRM device
1317  * @mode_list: list of modes to check
1318  * @verbose: be verbose about it
1319  *
1320  * This helper function can be used to prune a display mode list after
1321  * validation has been completed. All modes whose status is not MODE_OK will be
1322  * removed from the list, and if @verbose the status code and mode name is also
1323  * printed to dmesg.
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  * drm_mode_compare - compare modes for favorability
1351  * @priv: unused
1352  * @lh_a: list_head for first mode
1353  * @lh_b: list_head for second mode
1354  *
1355  * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
1356  * which is better.
1357  *
1358  * Returns:
1359  * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
1360  * positive if @lh_b is better than @lh_a.
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  * drm_mode_sort - sort mode list
1387  * @mode_list: list of drm_display_mode structures to sort
1388  *
1389  * Sort @mode_list by favorability, moving good modes to the head of the list.
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  * drm_connector_list_update - update the mode list for the connector
1399  * @connector: the connector to update
1400  *
1401  * This moves the modes from the @connector probed_modes list
1402  * to the actual mode list. It compares the probed mode against the current
1403  * list and only adds different/new modes.
1404  *
1405  * This is just a helper functions doesn't validate any modes itself and also
1406  * doesn't prune any invalid modes. Callers need to do that themselves.
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         /* go through current modes checking for the new probed mode */
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              * If the old matching mode is stale (ie. left over
1427              * from a previous probe) just replace it outright.
1428              * Otherwise just merge the type bits between all
1429              * equal probed modes.
1430              *
1431              * If two probed modes are considered equal, pick the
1432              * actual timings from the one that's marked as
1433              * preferred (in case the match isn't 100%). If
1434              * multiple or zero preferred modes are present, favor
1435              * the mode added to the probed_modes list first.
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              * Try to pass that to our extras parsing
1587              * function to handle the case where the
1588              * extras are directly after the resolution
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      * delim must point to the '=', otherwise it is a syntax error and
1619      * if delim points to the terminating zero, then delim + 1 will point
1620      * past the end of the string.
1621      */
1622     if (*delim != '=')
1623         return -EINVAL;
1624 
1625     value = delim + 1;
1626     *int_ret = simple_strtol(value, &endp, 10);
1627 
1628     /* Make sure we have parsed something */
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, &deg))
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     /* Make sure there is exactly one rotation defined */
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  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
1760  * @mode_option: optional per connector mode option
1761  * @connector: connector to parse modeline for
1762  * @mode: preallocated drm_cmdline_mode structure to fill out
1763  *
1764  * This parses @mode_option command line modeline for modes and options to
1765  * configure the connector. If @mode_option is NULL the default command line
1766  * modeline in fb_mode_option will be parsed instead.
1767  *
1768  * This uses the same parameters as the fb modedb.c, except for an extra
1769  * force-enable, force-enable-digital and force-disable bit at the end::
1770  *
1771  *  <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
1772  *
1773  * Additionals options can be provided following the mode, using a comma to
1774  * separate each option. Valid options can be found in
1775  * Documentation/fb/modedb.rst.
1776  *
1777  * The intermediate drm_cmdline_mode structure is required to store additional
1778  * options from the command line modline like the force-enable/disable flag.
1779  *
1780  * Returns:
1781  * True if a valid modeline has been parsed, false otherwise.
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     /* Try to locate the bpp and refresh specifiers, if any */
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     /* Locate the start of named options */
1814     options_ptr = strchr(name, ',');
1815     if (options_ptr)
1816         options_off = options_ptr - name;
1817 
1818     /* Locate the end of the name / resolution, and parse it */
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     /* First check for a named mode */
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; /* named + refresh is invalid */
1837 
1838             strcpy(mode->name, drm_named_modes_whitelist[i]);
1839             mode->specified = true;
1840             break;
1841         }
1842     }
1843 
1844     /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
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     /* No mode? Check for freestanding extras and/or options */
1857     if (!mode->specified) {
1858         unsigned int len = strlen(mode_option);
1859 
1860         if (bpp_ptr || refresh_ptr)
1861             return false; /* syntax error */
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      * Locate the end of the bpp / refresh, and parse the extras
1890      * if relevant
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  * drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
1925  * @dev: DRM device to create the new mode for
1926  * @cmd: input command line modeline
1927  *
1928  * Returns:
1929  * Pointer to converted mode on success, NULL on error.
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     /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */
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  * drm_mode_convert_to_umode - convert a drm_display_mode into a modeinfo
1966  * @out: drm_mode_modeinfo struct to return to the user
1967  * @in: drm_display_mode to use
1968  *
1969  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
1970  * the user.
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  * drm_mode_convert_umode - convert a modeinfo into a drm_display_mode
2018  * @dev: drm device
2019  * @out: drm_display_mode to return to the user
2020  * @in: drm_mode_modeinfo to use
2021  *
2022  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
2023  * the caller.
2024  *
2025  * Returns:
2026  * Zero on success, negative errno on failure.
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      * Old xf86-video-vmware (possibly others too) used to
2049      * leave 'type' uninitialized. Just ignore any bits we
2050      * don't like. It's a just hint after all, and more
2051      * useful for the kernel->userspace direction anyway.
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     /* Clearing picture aspect ratio bits from out flags,
2058      * as the aspect-ratio information is not stored in
2059      * flags for kernel-mode, but in picture_aspect_ratio.
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  * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
2094  * output format
2095  *
2096  * @display: display under action
2097  * @mode: video mode to be tested.
2098  *
2099  * Returns:
2100  * true if the mode can be supported in YCBCR420 format
2101  * false if not.
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  * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
2114  * output format also (along with RGB/YCBCR444/422)
2115  *
2116  * @display: display under action.
2117  * @mode: video mode to be tested.
2118  *
2119  * Returns:
2120  * true if the mode can be support YCBCR420 format
2121  * false if not.
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  * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
2133  * output format
2134  *
2135  * @display: display under action.
2136  * @mode: video mode to be tested.
2137  *
2138  * Returns:
2139  * true if the mode can be supported in YCBCR420 format
2140  * false if not.
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);