LCOV - code coverage report
Current view: top level - drivers/gpu/drm - drm_modes.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 608 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 39 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright © 1997-2003 by The XFree86 Project, Inc.
       3             :  * Copyright © 2007 Dave Airlie
       4             :  * Copyright © 2007-2008 Intel Corporation
       5             :  *   Jesse Barnes <jesse.barnes@intel.com>
       6             :  * Copyright 2005-2006 Luc Verhaegen
       7             :  * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
       8             :  *
       9             :  * Permission is hereby granted, free of charge, to any person obtaining a
      10             :  * copy of this software and associated documentation files (the "Software"),
      11             :  * to deal in the Software without restriction, including without limitation
      12             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13             :  * and/or sell copies of the Software, and to permit persons to whom the
      14             :  * Software is furnished to do so, subject to the following conditions:
      15             :  *
      16             :  * The above copyright notice and this permission notice shall be included in
      17             :  * all copies or substantial portions of the Software.
      18             :  *
      19             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      22             :  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
      23             :  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      24             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      25             :  * OTHER DEALINGS IN THE SOFTWARE.
      26             :  *
      27             :  * Except as contained in this notice, the name of the copyright holder(s)
      28             :  * and author(s) shall not be used in advertising or otherwise to promote
      29             :  * the sale, use or other dealings in this Software without prior written
      30             :  * authorization from the copyright holder(s) and author(s).
      31             :  */
      32             : 
      33             : #include <linux/ctype.h>
      34             : #include <linux/list.h>
      35             : #include <linux/list_sort.h>
      36             : #include <linux/export.h>
      37             : 
      38             : #include <video/of_display_timing.h>
      39             : #include <video/of_videomode.h>
      40             : #include <video/videomode.h>
      41             : 
      42             : #include <drm/drm_crtc.h>
      43             : #include <drm/drm_device.h>
      44             : #include <drm/drm_modes.h>
      45             : #include <drm/drm_print.h>
      46             : 
      47             : #include "drm_crtc_internal.h"
      48             : 
      49             : /**
      50             :  * drm_mode_debug_printmodeline - print a mode to dmesg
      51             :  * @mode: mode to print
      52             :  *
      53             :  * Describe @mode using DRM_DEBUG.
      54             :  */
      55           0 : void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
      56             : {
      57           0 :         DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
      58           0 : }
      59             : EXPORT_SYMBOL(drm_mode_debug_printmodeline);
      60             : 
      61             : /**
      62             :  * drm_mode_create - create a new display mode
      63             :  * @dev: DRM device
      64             :  *
      65             :  * Create a new, cleared drm_display_mode with kzalloc, allocate an ID for it
      66             :  * and return it.
      67             :  *
      68             :  * Returns:
      69             :  * Pointer to new mode on success, NULL on error.
      70             :  */
      71           0 : struct drm_display_mode *drm_mode_create(struct drm_device *dev)
      72             : {
      73             :         struct drm_display_mode *nmode;
      74             : 
      75           0 :         nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
      76           0 :         if (!nmode)
      77             :                 return NULL;
      78             : 
      79           0 :         return nmode;
      80             : }
      81             : EXPORT_SYMBOL(drm_mode_create);
      82             : 
      83             : /**
      84             :  * drm_mode_destroy - remove a mode
      85             :  * @dev: DRM device
      86             :  * @mode: mode to remove
      87             :  *
      88             :  * Release @mode's unique ID, then free it @mode structure itself using kfree.
      89             :  */
      90           0 : void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
      91             : {
      92           0 :         if (!mode)
      93             :                 return;
      94             : 
      95           0 :         kfree(mode);
      96             : }
      97             : EXPORT_SYMBOL(drm_mode_destroy);
      98             : 
      99             : /**
     100             :  * drm_mode_probed_add - add a mode to a connector's probed_mode list
     101             :  * @connector: connector the new mode
     102             :  * @mode: mode data
     103             :  *
     104             :  * Add @mode to @connector's probed_mode list for later use. This list should
     105             :  * then in a second step get filtered and all the modes actually supported by
     106             :  * the hardware moved to the @connector's modes list.
     107             :  */
     108           0 : void drm_mode_probed_add(struct drm_connector *connector,
     109             :                          struct drm_display_mode *mode)
     110             : {
     111           0 :         WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
     112             : 
     113           0 :         list_add_tail(&mode->head, &connector->probed_modes);
     114           0 : }
     115             : EXPORT_SYMBOL(drm_mode_probed_add);
     116             : 
     117             : /**
     118             :  * drm_cvt_mode -create a modeline based on the CVT algorithm
     119             :  * @dev: drm device
     120             :  * @hdisplay: hdisplay size
     121             :  * @vdisplay: vdisplay size
     122             :  * @vrefresh: vrefresh rate
     123             :  * @reduced: whether to use reduced blanking
     124             :  * @interlaced: whether to compute an interlaced mode
     125             :  * @margins: whether to add margins (borders)
     126             :  *
     127             :  * This function is called to generate the modeline based on CVT algorithm
     128             :  * according to the hdisplay, vdisplay, vrefresh.
     129             :  * It is based from the VESA(TM) Coordinated Video Timing Generator by
     130             :  * Graham Loveridge April 9, 2003 available at
     131             :  * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls
     132             :  *
     133             :  * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
     134             :  * What I have done is to translate it by using integer calculation.
     135             :  *
     136             :  * Returns:
     137             :  * The modeline based on the CVT algorithm stored in a drm_display_mode object.
     138             :  * The display mode object is allocated with drm_mode_create(). Returns NULL
     139             :  * when no mode could be allocated.
     140             :  */
     141           0 : struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
     142             :                                       int vdisplay, int vrefresh,
     143             :                                       bool reduced, bool interlaced, bool margins)
     144             : {
     145             : #define HV_FACTOR                       1000
     146             :         /* 1) top/bottom margin size (% of height) - default: 1.8, */
     147             : #define CVT_MARGIN_PERCENTAGE           18
     148             :         /* 2) character cell horizontal granularity (pixels) - default 8 */
     149             : #define CVT_H_GRANULARITY               8
     150             :         /* 3) Minimum vertical porch (lines) - default 3 */
     151             : #define CVT_MIN_V_PORCH                 3
     152             :         /* 4) Minimum number of vertical back porch lines - default 6 */
     153             : #define CVT_MIN_V_BPORCH                6
     154             :         /* Pixel Clock step (kHz) */
     155             : #define CVT_CLOCK_STEP                  250
     156             :         struct drm_display_mode *drm_mode;
     157             :         unsigned int vfieldrate, hperiod;
     158             :         int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
     159             :         int interlace;
     160             :         u64 tmp;
     161             : 
     162           0 :         if (!hdisplay || !vdisplay)
     163             :                 return NULL;
     164             : 
     165             :         /* allocate the drm_display_mode structure. If failure, we will
     166             :          * return directly
     167             :          */
     168           0 :         drm_mode = drm_mode_create(dev);
     169           0 :         if (!drm_mode)
     170             :                 return NULL;
     171             : 
     172             :         /* the CVT default refresh rate is 60Hz */
     173           0 :         if (!vrefresh)
     174           0 :                 vrefresh = 60;
     175             : 
     176             :         /* the required field fresh rate */
     177           0 :         if (interlaced)
     178           0 :                 vfieldrate = vrefresh * 2;
     179             :         else
     180           0 :                 vfieldrate = vrefresh;
     181             : 
     182             :         /* horizontal pixels */
     183           0 :         hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);
     184             : 
     185             :         /* determine the left&right borders */
     186           0 :         hmargin = 0;
     187           0 :         if (margins) {
     188           0 :                 hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
     189           0 :                 hmargin -= hmargin % CVT_H_GRANULARITY;
     190             :         }
     191             :         /* find the total active pixels */
     192           0 :         drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;
     193             : 
     194             :         /* find the number of lines per field */
     195           0 :         if (interlaced)
     196           0 :                 vdisplay_rnd = vdisplay / 2;
     197             :         else
     198             :                 vdisplay_rnd = vdisplay;
     199             : 
     200             :         /* find the top & bottom borders */
     201           0 :         vmargin = 0;
     202           0 :         if (margins)
     203           0 :                 vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
     204             : 
     205           0 :         drm_mode->vdisplay = vdisplay + 2 * vmargin;
     206             : 
     207             :         /* Interlaced */
     208           0 :         if (interlaced)
     209             :                 interlace = 1;
     210             :         else
     211           0 :                 interlace = 0;
     212             : 
     213             :         /* Determine VSync Width from aspect ratio */
     214           0 :         if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
     215             :                 vsync = 4;
     216           0 :         else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
     217             :                 vsync = 5;
     218           0 :         else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
     219             :                 vsync = 6;
     220           0 :         else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
     221             :                 vsync = 7;
     222           0 :         else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
     223             :                 vsync = 7;
     224             :         else /* custom */
     225           0 :                 vsync = 10;
     226             : 
     227           0 :         if (!reduced) {
     228             :                 /* simplify the GTF calculation */
     229             :                 /* 4) Minimum time of vertical sync + back porch interval (µs)
     230             :                  * default 550.0
     231             :                  */
     232             :                 int tmp1, tmp2;
     233             : #define CVT_MIN_VSYNC_BP        550
     234             :                 /* 3) Nominal HSync width (% of line period) - default 8 */
     235             : #define CVT_HSYNC_PERCENTAGE    8
     236             :                 unsigned int hblank_percentage;
     237             :                 int vsyncandback_porch, __maybe_unused vback_porch, hblank;
     238             : 
     239             :                 /* estimated the horizontal period */
     240           0 :                 tmp1 = HV_FACTOR * 1000000  -
     241           0 :                                 CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
     242           0 :                 tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
     243             :                                 interlace;
     244           0 :                 hperiod = tmp1 * 2 / (tmp2 * vfieldrate);
     245             : 
     246           0 :                 tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
     247             :                 /* 9. Find number of lines in sync + backporch */
     248           0 :                 if (tmp1 < (vsync + CVT_MIN_V_PORCH))
     249           0 :                         vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
     250             :                 else
     251             :                         vsyncandback_porch = tmp1;
     252             :                 /* 10. Find number of lines in back porch */
     253           0 :                 vback_porch = vsyncandback_porch - vsync;
     254           0 :                 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
     255           0 :                                 vsyncandback_porch + CVT_MIN_V_PORCH;
     256             :                 /* 5) Definition of Horizontal blanking time limitation */
     257             :                 /* Gradient (%/kHz) - default 600 */
     258             : #define CVT_M_FACTOR    600
     259             :                 /* Offset (%) - default 40 */
     260             : #define CVT_C_FACTOR    40
     261             :                 /* Blanking time scaling factor - default 128 */
     262             : #define CVT_K_FACTOR    128
     263             :                 /* Scaling factor weighting - default 20 */
     264             : #define CVT_J_FACTOR    20
     265             : #define CVT_M_PRIME     (CVT_M_FACTOR * CVT_K_FACTOR / 256)
     266             : #define CVT_C_PRIME     ((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
     267             :                          CVT_J_FACTOR)
     268             :                 /* 12. Find ideal blanking duty cycle from formula */
     269           0 :                 hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
     270           0 :                                         hperiod / 1000;
     271             :                 /* 13. Blanking time */
     272           0 :                 if (hblank_percentage < 20 * HV_FACTOR)
     273           0 :                         hblank_percentage = 20 * HV_FACTOR;
     274           0 :                 hblank = drm_mode->hdisplay * hblank_percentage /
     275           0 :                          (100 * HV_FACTOR - hblank_percentage);
     276           0 :                 hblank -= hblank % (2 * CVT_H_GRANULARITY);
     277             :                 /* 14. find the total pixels per line */
     278           0 :                 drm_mode->htotal = drm_mode->hdisplay + hblank;
     279           0 :                 drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
     280           0 :                 drm_mode->hsync_start = drm_mode->hsync_end -
     281           0 :                         (drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
     282           0 :                 drm_mode->hsync_start += CVT_H_GRANULARITY -
     283             :                         drm_mode->hsync_start % CVT_H_GRANULARITY;
     284             :                 /* fill the Vsync values */
     285           0 :                 drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
     286           0 :                 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
     287             :         } else {
     288             :                 /* Reduced blanking */
     289             :                 /* Minimum vertical blanking interval time (µs)- default 460 */
     290             : #define CVT_RB_MIN_VBLANK       460
     291             :                 /* Fixed number of clocks for horizontal sync */
     292             : #define CVT_RB_H_SYNC           32
     293             :                 /* Fixed number of clocks for horizontal blanking */
     294             : #define CVT_RB_H_BLANK          160
     295             :                 /* Fixed number of lines for vertical front porch - default 3*/
     296             : #define CVT_RB_VFPORCH          3
     297             :                 int vbilines;
     298             :                 int tmp1, tmp2;
     299             :                 /* 8. Estimate Horizontal period. */
     300           0 :                 tmp1 = HV_FACTOR * 1000000 -
     301           0 :                         CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
     302           0 :                 tmp2 = vdisplay_rnd + 2 * vmargin;
     303           0 :                 hperiod = tmp1 / (tmp2 * vfieldrate);
     304             :                 /* 9. Find number of lines in vertical blanking */
     305           0 :                 vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
     306             :                 /* 10. Check if vertical blanking is sufficient */
     307           0 :                 if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
     308           0 :                         vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
     309             :                 /* 11. Find total number of lines in vertical field */
     310           0 :                 drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
     311             :                 /* 12. Find total number of pixels in a line */
     312           0 :                 drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
     313             :                 /* Fill in HSync values */
     314           0 :                 drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
     315           0 :                 drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
     316             :                 /* Fill in VSync values */
     317           0 :                 drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
     318           0 :                 drm_mode->vsync_end = drm_mode->vsync_start + vsync;
     319             :         }
     320             :         /* 15/13. Find pixel clock frequency (kHz for xf86) */
     321           0 :         tmp = drm_mode->htotal; /* perform intermediate calcs in u64 */
     322           0 :         tmp *= HV_FACTOR * 1000;
     323           0 :         do_div(tmp, hperiod);
     324           0 :         tmp -= drm_mode->clock % CVT_CLOCK_STEP;
     325           0 :         drm_mode->clock = tmp;
     326             :         /* 18/16. Find actual vertical frame frequency */
     327             :         /* ignore - just set the mode flag for interlaced */
     328           0 :         if (interlaced) {
     329           0 :                 drm_mode->vtotal *= 2;
     330           0 :                 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
     331             :         }
     332             :         /* Fill the mode line name */
     333           0 :         drm_mode_set_name(drm_mode);
     334           0 :         if (reduced)
     335           0 :                 drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
     336             :                                         DRM_MODE_FLAG_NVSYNC);
     337             :         else
     338           0 :                 drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
     339             :                                         DRM_MODE_FLAG_NHSYNC);
     340             : 
     341             :         return drm_mode;
     342             : }
     343             : EXPORT_SYMBOL(drm_cvt_mode);
     344             : 
     345             : /**
     346             :  * drm_gtf_mode_complex - create the modeline based on the full GTF algorithm
     347             :  * @dev: drm device
     348             :  * @hdisplay: hdisplay size
     349             :  * @vdisplay: vdisplay size
     350             :  * @vrefresh: vrefresh rate.
     351             :  * @interlaced: whether to compute an interlaced mode
     352             :  * @margins: desired margin (borders) size
     353             :  * @GTF_M: extended GTF formula parameters
     354             :  * @GTF_2C: extended GTF formula parameters
     355             :  * @GTF_K: extended GTF formula parameters
     356             :  * @GTF_2J: extended GTF formula parameters
     357             :  *
     358             :  * GTF feature blocks specify C and J in multiples of 0.5, so we pass them
     359             :  * in here multiplied by two.  For a C of 40, pass in 80.
     360             :  *
     361             :  * Returns:
     362             :  * The modeline based on the full GTF algorithm stored in a drm_display_mode object.
     363             :  * The display mode object is allocated with drm_mode_create(). Returns NULL
     364             :  * when no mode could be allocated.
     365             :  */
     366             : struct drm_display_mode *
     367           0 : drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
     368             :                      int vrefresh, bool interlaced, int margins,
     369             :                      int GTF_M, int GTF_2C, int GTF_K, int GTF_2J)
     370             : {       /* 1) top/bottom margin size (% of height) - default: 1.8, */
     371             : #define GTF_MARGIN_PERCENTAGE           18
     372             :         /* 2) character cell horizontal granularity (pixels) - default 8 */
     373             : #define GTF_CELL_GRAN                   8
     374             :         /* 3) Minimum vertical porch (lines) - default 3 */
     375             : #define GTF_MIN_V_PORCH                 1
     376             :         /* width of vsync in lines */
     377             : #define V_SYNC_RQD                      3
     378             :         /* width of hsync as % of total line */
     379             : #define H_SYNC_PERCENT                  8
     380             :         /* min time of vsync + back porch (microsec) */
     381             : #define MIN_VSYNC_PLUS_BP               550
     382             :         /* C' and M' are part of the Blanking Duty Cycle computation */
     383             : #define GTF_C_PRIME     ((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
     384             : #define GTF_M_PRIME     (GTF_K * GTF_M / 256)
     385             :         struct drm_display_mode *drm_mode;
     386             :         unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
     387             :         int top_margin, bottom_margin;
     388             :         int interlace;
     389             :         unsigned int hfreq_est;
     390             :         int vsync_plus_bp, __maybe_unused vback_porch;
     391             :         unsigned int vtotal_lines, __maybe_unused vfieldrate_est;
     392             :         unsigned int __maybe_unused hperiod;
     393             :         unsigned int vfield_rate, __maybe_unused vframe_rate;
     394             :         int left_margin, right_margin;
     395             :         unsigned int total_active_pixels, ideal_duty_cycle;
     396             :         unsigned int hblank, total_pixels, pixel_freq;
     397             :         int hsync, hfront_porch, vodd_front_porch_lines;
     398             :         unsigned int tmp1, tmp2;
     399             : 
     400           0 :         if (!hdisplay || !vdisplay)
     401             :                 return NULL;
     402             : 
     403           0 :         drm_mode = drm_mode_create(dev);
     404           0 :         if (!drm_mode)
     405             :                 return NULL;
     406             : 
     407             :         /* 1. In order to give correct results, the number of horizontal
     408             :          * pixels requested is first processed to ensure that it is divisible
     409             :          * by the character size, by rounding it to the nearest character
     410             :          * cell boundary:
     411             :          */
     412           0 :         hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
     413           0 :         hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;
     414             : 
     415             :         /* 2. If interlace is requested, the number of vertical lines assumed
     416             :          * by the calculation must be halved, as the computation calculates
     417             :          * the number of vertical lines per field.
     418             :          */
     419           0 :         if (interlaced)
     420           0 :                 vdisplay_rnd = vdisplay / 2;
     421             :         else
     422           0 :                 vdisplay_rnd = vdisplay;
     423             : 
     424             :         /* 3. Find the frame rate required: */
     425           0 :         if (interlaced)
     426           0 :                 vfieldrate_rqd = vrefresh * 2;
     427             :         else
     428           0 :                 vfieldrate_rqd = vrefresh;
     429             : 
     430             :         /* 4. Find number of lines in Top margin: */
     431           0 :         top_margin = 0;
     432           0 :         if (margins)
     433           0 :                 top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
     434             :                                 1000;
     435             :         /* 5. Find number of lines in bottom margin: */
     436           0 :         bottom_margin = top_margin;
     437             : 
     438             :         /* 6. If interlace is required, then set variable interlace: */
     439           0 :         if (interlaced)
     440             :                 interlace = 1;
     441             :         else
     442           0 :                 interlace = 0;
     443             : 
     444             :         /* 7. Estimate the Horizontal frequency */
     445             :         {
     446           0 :                 tmp1 = (1000000  - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
     447           0 :                 tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
     448           0 :                                 2 + interlace;
     449           0 :                 hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
     450             :         }
     451             : 
     452             :         /* 8. Find the number of lines in V sync + back porch */
     453             :         /* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
     454           0 :         vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
     455           0 :         vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
     456             :         /*  9. Find the number of lines in V back porch alone: */
     457           0 :         vback_porch = vsync_plus_bp - V_SYNC_RQD;
     458             :         /*  10. Find the total number of lines in Vertical field period: */
     459           0 :         vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
     460             :                         vsync_plus_bp + GTF_MIN_V_PORCH;
     461             :         /*  11. Estimate the Vertical field frequency: */
     462           0 :         vfieldrate_est = hfreq_est / vtotal_lines;
     463             :         /*  12. Find the actual horizontal period: */
     464           0 :         hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);
     465             : 
     466             :         /*  13. Find the actual Vertical field frequency: */
     467           0 :         vfield_rate = hfreq_est / vtotal_lines;
     468             :         /*  14. Find the Vertical frame frequency: */
     469             :         if (interlaced)
     470             :                 vframe_rate = vfield_rate / 2;
     471             :         else
     472             :                 vframe_rate = vfield_rate;
     473             :         /*  15. Find number of pixels in left margin: */
     474           0 :         if (margins)
     475           0 :                 left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
     476             :                                 1000;
     477             :         else
     478             :                 left_margin = 0;
     479             : 
     480             :         /* 16.Find number of pixels in right margin: */
     481           0 :         right_margin = left_margin;
     482             :         /* 17.Find total number of active pixels in image and left and right */
     483           0 :         total_active_pixels = hdisplay_rnd + left_margin + right_margin;
     484             :         /* 18.Find the ideal blanking duty cycle from blanking duty cycle */
     485           0 :         ideal_duty_cycle = GTF_C_PRIME * 1000 -
     486           0 :                                 (GTF_M_PRIME * 1000000 / hfreq_est);
     487             :         /* 19.Find the number of pixels in the blanking time to the nearest
     488             :          * double character cell: */
     489           0 :         hblank = total_active_pixels * ideal_duty_cycle /
     490           0 :                         (100000 - ideal_duty_cycle);
     491           0 :         hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
     492           0 :         hblank = hblank * 2 * GTF_CELL_GRAN;
     493             :         /* 20.Find total number of pixels: */
     494           0 :         total_pixels = total_active_pixels + hblank;
     495             :         /* 21.Find pixel clock frequency: */
     496           0 :         pixel_freq = total_pixels * hfreq_est / 1000;
     497             :         /* Stage 1 computations are now complete; I should really pass
     498             :          * the results to another function and do the Stage 2 computations,
     499             :          * but I only need a few more values so I'll just append the
     500             :          * computations here for now */
     501             :         /* 17. Find the number of pixels in the horizontal sync period: */
     502           0 :         hsync = H_SYNC_PERCENT * total_pixels / 100;
     503           0 :         hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
     504           0 :         hsync = hsync * GTF_CELL_GRAN;
     505             :         /* 18. Find the number of pixels in horizontal front porch period */
     506           0 :         hfront_porch = hblank / 2 - hsync;
     507             :         /*  36. Find the number of lines in the odd front porch period: */
     508           0 :         vodd_front_porch_lines = GTF_MIN_V_PORCH ;
     509             : 
     510             :         /* finally, pack the results in the mode struct */
     511           0 :         drm_mode->hdisplay = hdisplay_rnd;
     512           0 :         drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
     513           0 :         drm_mode->hsync_end = drm_mode->hsync_start + hsync;
     514           0 :         drm_mode->htotal = total_pixels;
     515           0 :         drm_mode->vdisplay = vdisplay_rnd;
     516           0 :         drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
     517           0 :         drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
     518           0 :         drm_mode->vtotal = vtotal_lines;
     519             : 
     520           0 :         drm_mode->clock = pixel_freq;
     521             : 
     522           0 :         if (interlaced) {
     523           0 :                 drm_mode->vtotal *= 2;
     524           0 :                 drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
     525             :         }
     526             : 
     527           0 :         drm_mode_set_name(drm_mode);
     528           0 :         if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
     529           0 :                 drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
     530             :         else
     531           0 :                 drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
     532             : 
     533             :         return drm_mode;
     534             : }
     535             : EXPORT_SYMBOL(drm_gtf_mode_complex);
     536             : 
     537             : /**
     538             :  * drm_gtf_mode - create the modeline based on the GTF algorithm
     539             :  * @dev: drm device
     540             :  * @hdisplay: hdisplay size
     541             :  * @vdisplay: vdisplay size
     542             :  * @vrefresh: vrefresh rate.
     543             :  * @interlaced: whether to compute an interlaced mode
     544             :  * @margins: desired margin (borders) size
     545             :  *
     546             :  * return the modeline based on GTF algorithm
     547             :  *
     548             :  * This function is to create the modeline based on the GTF algorithm.
     549             :  * Generalized Timing Formula is derived from:
     550             :  *
     551             :  *      GTF Spreadsheet by Andy Morrish (1/5/97)
     552             :  *      available at https://www.vesa.org
     553             :  *
     554             :  * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
     555             :  * What I have done is to translate it by using integer calculation.
     556             :  * I also refer to the function of fb_get_mode in the file of
     557             :  * drivers/video/fbmon.c
     558             :  *
     559             :  * Standard GTF parameters::
     560             :  *
     561             :  *     M = 600
     562             :  *     C = 40
     563             :  *     K = 128
     564             :  *     J = 20
     565             :  *
     566             :  * Returns:
     567             :  * The modeline based on the GTF algorithm stored in a drm_display_mode object.
     568             :  * The display mode object is allocated with drm_mode_create(). Returns NULL
     569             :  * when no mode could be allocated.
     570             :  */
     571             : struct drm_display_mode *
     572           0 : drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
     573             :              bool interlaced, int margins)
     574             : {
     575           0 :         return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
     576             :                                     interlaced, margins,
     577             :                                     600, 40 * 2, 128, 20 * 2);
     578             : }
     579             : EXPORT_SYMBOL(drm_gtf_mode);
     580             : 
     581             : #ifdef CONFIG_VIDEOMODE_HELPERS
     582             : /**
     583             :  * drm_display_mode_from_videomode - fill in @dmode using @vm,
     584             :  * @vm: videomode structure to use as source
     585             :  * @dmode: drm_display_mode structure to use as destination
     586             :  *
     587             :  * Fills out @dmode using the display mode specified in @vm.
     588             :  */
     589             : void drm_display_mode_from_videomode(const struct videomode *vm,
     590             :                                      struct drm_display_mode *dmode)
     591             : {
     592             :         dmode->hdisplay = vm->hactive;
     593             :         dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
     594             :         dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
     595             :         dmode->htotal = dmode->hsync_end + vm->hback_porch;
     596             : 
     597             :         dmode->vdisplay = vm->vactive;
     598             :         dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
     599             :         dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
     600             :         dmode->vtotal = dmode->vsync_end + vm->vback_porch;
     601             : 
     602             :         dmode->clock = vm->pixelclock / 1000;
     603             : 
     604             :         dmode->flags = 0;
     605             :         if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
     606             :                 dmode->flags |= DRM_MODE_FLAG_PHSYNC;
     607             :         else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
     608             :                 dmode->flags |= DRM_MODE_FLAG_NHSYNC;
     609             :         if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
     610             :                 dmode->flags |= DRM_MODE_FLAG_PVSYNC;
     611             :         else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
     612             :                 dmode->flags |= DRM_MODE_FLAG_NVSYNC;
     613             :         if (vm->flags & DISPLAY_FLAGS_INTERLACED)
     614             :                 dmode->flags |= DRM_MODE_FLAG_INTERLACE;
     615             :         if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
     616             :                 dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
     617             :         if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
     618             :                 dmode->flags |= DRM_MODE_FLAG_DBLCLK;
     619             :         drm_mode_set_name(dmode);
     620             : }
     621             : EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
     622             : 
     623             : /**
     624             :  * drm_display_mode_to_videomode - fill in @vm using @dmode,
     625             :  * @dmode: drm_display_mode structure to use as source
     626             :  * @vm: videomode structure to use as destination
     627             :  *
     628             :  * Fills out @vm using the display mode specified in @dmode.
     629             :  */
     630             : void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
     631             :                                    struct videomode *vm)
     632             : {
     633             :         vm->hactive = dmode->hdisplay;
     634             :         vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
     635             :         vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
     636             :         vm->hback_porch = dmode->htotal - dmode->hsync_end;
     637             : 
     638             :         vm->vactive = dmode->vdisplay;
     639             :         vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
     640             :         vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
     641             :         vm->vback_porch = dmode->vtotal - dmode->vsync_end;
     642             : 
     643             :         vm->pixelclock = dmode->clock * 1000;
     644             : 
     645             :         vm->flags = 0;
     646             :         if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
     647             :                 vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
     648             :         else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
     649             :                 vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
     650             :         if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
     651             :                 vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
     652             :         else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
     653             :                 vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
     654             :         if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
     655             :                 vm->flags |= DISPLAY_FLAGS_INTERLACED;
     656             :         if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
     657             :                 vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
     658             :         if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
     659             :                 vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
     660             : }
     661             : EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
     662             : 
     663             : /**
     664             :  * drm_bus_flags_from_videomode - extract information about pixelclk and
     665             :  * DE polarity from videomode and store it in a separate variable
     666             :  * @vm: videomode structure to use
     667             :  * @bus_flags: information about pixelclk, sync and DE polarity will be stored
     668             :  * here
     669             :  *
     670             :  * Sets DRM_BUS_FLAG_DE_(LOW|HIGH),  DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE
     671             :  * and DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
     672             :  * found in @vm
     673             :  */
     674             : void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
     675             : {
     676             :         *bus_flags = 0;
     677             :         if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
     678             :                 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
     679             :         if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
     680             :                 *bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
     681             : 
     682             :         if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
     683             :                 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
     684             :         if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
     685             :                 *bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
     686             : 
     687             :         if (vm->flags & DISPLAY_FLAGS_DE_LOW)
     688             :                 *bus_flags |= DRM_BUS_FLAG_DE_LOW;
     689             :         if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
     690             :                 *bus_flags |= DRM_BUS_FLAG_DE_HIGH;
     691             : }
     692             : EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);
     693             : 
     694             : #ifdef CONFIG_OF
     695             : /**
     696             :  * of_get_drm_display_mode - get a drm_display_mode from devicetree
     697             :  * @np: device_node with the timing specification
     698             :  * @dmode: will be set to the return value
     699             :  * @bus_flags: information about pixelclk, sync and DE polarity
     700             :  * @index: index into the list of display timings in devicetree
     701             :  *
     702             :  * This function is expensive and should only be used, if only one mode is to be
     703             :  * read from DT. To get multiple modes start with of_get_display_timings and
     704             :  * work with that instead.
     705             :  *
     706             :  * Returns:
     707             :  * 0 on success, a negative errno code when no of videomode node was found.
     708             :  */
     709             : int of_get_drm_display_mode(struct device_node *np,
     710             :                             struct drm_display_mode *dmode, u32 *bus_flags,
     711             :                             int index)
     712             : {
     713             :         struct videomode vm;
     714             :         int ret;
     715             : 
     716             :         ret = of_get_videomode(np, &vm, index);
     717             :         if (ret)
     718             :                 return ret;
     719             : 
     720             :         drm_display_mode_from_videomode(&vm, dmode);
     721             :         if (bus_flags)
     722             :                 drm_bus_flags_from_videomode(&vm, bus_flags);
     723             : 
     724             :         pr_debug("%pOF: got %dx%d display mode\n",
     725             :                 np, vm.hactive, vm.vactive);
     726             :         drm_mode_debug_printmodeline(dmode);
     727             : 
     728             :         return 0;
     729             : }
     730             : EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
     731             : 
     732             : /**
     733             :  * of_get_drm_panel_display_mode - get a panel-timing drm_display_mode from devicetree
     734             :  * @np: device_node with the panel-timing specification
     735             :  * @dmode: will be set to the return value
     736             :  * @bus_flags: information about pixelclk, sync and DE polarity
     737             :  *
     738             :  * The mandatory Device Tree properties width-mm and height-mm
     739             :  * are read and set on the display mode.
     740             :  *
     741             :  * Returns:
     742             :  * Zero on success, negative error code on failure.
     743             :  */
     744             : int of_get_drm_panel_display_mode(struct device_node *np,
     745             :                                   struct drm_display_mode *dmode, u32 *bus_flags)
     746             : {
     747             :         u32 width_mm = 0, height_mm = 0;
     748             :         struct display_timing timing;
     749             :         struct videomode vm;
     750             :         int ret;
     751             : 
     752             :         ret = of_get_display_timing(np, "panel-timing", &timing);
     753             :         if (ret)
     754             :                 return ret;
     755             : 
     756             :         videomode_from_timing(&timing, &vm);
     757             : 
     758             :         memset(dmode, 0, sizeof(*dmode));
     759             :         drm_display_mode_from_videomode(&vm, dmode);
     760             :         if (bus_flags)
     761             :                 drm_bus_flags_from_videomode(&vm, bus_flags);
     762             : 
     763             :         ret = of_property_read_u32(np, "width-mm", &width_mm);
     764             :         if (ret)
     765             :                 return ret;
     766             : 
     767             :         ret = of_property_read_u32(np, "height-mm", &height_mm);
     768             :         if (ret)
     769             :                 return ret;
     770             : 
     771             :         dmode->width_mm = width_mm;
     772             :         dmode->height_mm = height_mm;
     773             : 
     774             :         drm_mode_debug_printmodeline(dmode);
     775             : 
     776             :         return 0;
     777             : }
     778             : EXPORT_SYMBOL_GPL(of_get_drm_panel_display_mode);
     779             : #endif /* CONFIG_OF */
     780             : #endif /* CONFIG_VIDEOMODE_HELPERS */
     781             : 
     782             : /**
     783             :  * drm_mode_set_name - set the name on a mode
     784             :  * @mode: name will be set in this mode
     785             :  *
     786             :  * Set the name of @mode to a standard format which is <hdisplay>x<vdisplay>
     787             :  * with an optional 'i' suffix for interlaced modes.
     788             :  */
     789           0 : void drm_mode_set_name(struct drm_display_mode *mode)
     790             : {
     791           0 :         bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
     792             : 
     793           0 :         snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
     794           0 :                  mode->hdisplay, mode->vdisplay,
     795             :                  interlaced ? "i" : "");
     796           0 : }
     797             : EXPORT_SYMBOL(drm_mode_set_name);
     798             : 
     799             : /**
     800             :  * drm_mode_vrefresh - get the vrefresh of a mode
     801             :  * @mode: mode
     802             :  *
     803             :  * Returns:
     804             :  * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the
     805             :  * value first if it is not yet set.
     806             :  */
     807           0 : int drm_mode_vrefresh(const struct drm_display_mode *mode)
     808             : {
     809             :         unsigned int num, den;
     810             : 
     811           0 :         if (mode->htotal == 0 || mode->vtotal == 0)
     812             :                 return 0;
     813             : 
     814           0 :         num = mode->clock;
     815           0 :         den = mode->htotal * mode->vtotal;
     816             : 
     817           0 :         if (mode->flags & DRM_MODE_FLAG_INTERLACE)
     818           0 :                 num *= 2;
     819           0 :         if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
     820           0 :                 den *= 2;
     821           0 :         if (mode->vscan > 1)
     822           0 :                 den *= mode->vscan;
     823             : 
     824           0 :         return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(num, 1000), den);
     825             : }
     826             : EXPORT_SYMBOL(drm_mode_vrefresh);
     827             : 
     828             : /**
     829             :  * drm_mode_get_hv_timing - Fetches hdisplay/vdisplay for given mode
     830             :  * @mode: mode to query
     831             :  * @hdisplay: hdisplay value to fill in
     832             :  * @vdisplay: vdisplay value to fill in
     833             :  *
     834             :  * The vdisplay value will be doubled if the specified mode is a stereo mode of
     835             :  * the appropriate layout.
     836             :  */
     837           0 : void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
     838             :                             int *hdisplay, int *vdisplay)
     839             : {
     840             :         struct drm_display_mode adjusted;
     841             : 
     842           0 :         drm_mode_init(&adjusted, mode);
     843             : 
     844           0 :         drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
     845           0 :         *hdisplay = adjusted.crtc_hdisplay;
     846           0 :         *vdisplay = adjusted.crtc_vdisplay;
     847           0 : }
     848             : EXPORT_SYMBOL(drm_mode_get_hv_timing);
     849             : 
     850             : /**
     851             :  * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
     852             :  * @p: mode
     853             :  * @adjust_flags: a combination of adjustment flags
     854             :  *
     855             :  * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
     856             :  *
     857             :  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
     858             :  *   interlaced modes.
     859             :  * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
     860             :  *   buffers containing two eyes (only adjust the timings when needed, eg. for
     861             :  *   "frame packing" or "side by side full").
     862             :  * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
     863             :  *   be performed for doublescan and vscan > 1 modes respectively.
     864             :  */
     865           0 : void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
     866             : {
     867           0 :         if (!p)
     868             :                 return;
     869             : 
     870           0 :         p->crtc_clock = p->clock;
     871           0 :         p->crtc_hdisplay = p->hdisplay;
     872           0 :         p->crtc_hsync_start = p->hsync_start;
     873           0 :         p->crtc_hsync_end = p->hsync_end;
     874           0 :         p->crtc_htotal = p->htotal;
     875           0 :         p->crtc_hskew = p->hskew;
     876           0 :         p->crtc_vdisplay = p->vdisplay;
     877           0 :         p->crtc_vsync_start = p->vsync_start;
     878           0 :         p->crtc_vsync_end = p->vsync_end;
     879           0 :         p->crtc_vtotal = p->vtotal;
     880             : 
     881           0 :         if (p->flags & DRM_MODE_FLAG_INTERLACE) {
     882           0 :                 if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
     883           0 :                         p->crtc_vdisplay /= 2;
     884           0 :                         p->crtc_vsync_start /= 2;
     885           0 :                         p->crtc_vsync_end /= 2;
     886           0 :                         p->crtc_vtotal /= 2;
     887             :                 }
     888             :         }
     889             : 
     890           0 :         if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
     891           0 :                 if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
     892           0 :                         p->crtc_vdisplay *= 2;
     893           0 :                         p->crtc_vsync_start *= 2;
     894           0 :                         p->crtc_vsync_end *= 2;
     895           0 :                         p->crtc_vtotal *= 2;
     896             :                 }
     897             :         }
     898             : 
     899           0 :         if (!(adjust_flags & CRTC_NO_VSCAN)) {
     900           0 :                 if (p->vscan > 1) {
     901           0 :                         p->crtc_vdisplay *= p->vscan;
     902           0 :                         p->crtc_vsync_start *= p->vscan;
     903           0 :                         p->crtc_vsync_end *= p->vscan;
     904           0 :                         p->crtc_vtotal *= p->vscan;
     905             :                 }
     906             :         }
     907             : 
     908           0 :         if (adjust_flags & CRTC_STEREO_DOUBLE) {
     909           0 :                 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
     910             : 
     911           0 :                 switch (layout) {
     912             :                 case DRM_MODE_FLAG_3D_FRAME_PACKING:
     913           0 :                         p->crtc_clock *= 2;
     914           0 :                         p->crtc_vdisplay += p->crtc_vtotal;
     915           0 :                         p->crtc_vsync_start += p->crtc_vtotal;
     916           0 :                         p->crtc_vsync_end += p->crtc_vtotal;
     917           0 :                         p->crtc_vtotal += p->crtc_vtotal;
     918           0 :                         break;
     919             :                 }
     920             :         }
     921             : 
     922           0 :         p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
     923           0 :         p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
     924           0 :         p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
     925           0 :         p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
     926             : }
     927             : EXPORT_SYMBOL(drm_mode_set_crtcinfo);
     928             : 
     929             : /**
     930             :  * drm_mode_copy - copy the mode
     931             :  * @dst: mode to overwrite
     932             :  * @src: mode to copy
     933             :  *
     934             :  * Copy an existing mode into another mode, preserving the
     935             :  * list head of the destination mode.
     936             :  */
     937           0 : void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
     938             : {
     939           0 :         struct list_head head = dst->head;
     940             : 
     941           0 :         *dst = *src;
     942           0 :         dst->head = head;
     943           0 : }
     944             : EXPORT_SYMBOL(drm_mode_copy);
     945             : 
     946             : /**
     947             :  * drm_mode_init - initialize the mode from another mode
     948             :  * @dst: mode to overwrite
     949             :  * @src: mode to copy
     950             :  *
     951             :  * Copy an existing mode into another mode, zeroing the
     952             :  * list head of the destination mode. Typically used
     953             :  * to guarantee the list head is not left with stack
     954             :  * garbage in on-stack modes.
     955             :  */
     956           0 : void drm_mode_init(struct drm_display_mode *dst, const struct drm_display_mode *src)
     957             : {
     958           0 :         memset(dst, 0, sizeof(*dst));
     959           0 :         drm_mode_copy(dst, src);
     960           0 : }
     961             : EXPORT_SYMBOL(drm_mode_init);
     962             : 
     963             : /**
     964             :  * drm_mode_duplicate - allocate and duplicate an existing mode
     965             :  * @dev: drm_device to allocate the duplicated mode for
     966             :  * @mode: mode to duplicate
     967             :  *
     968             :  * Just allocate a new mode, copy the existing mode into it, and return
     969             :  * a pointer to it.  Used to create new instances of established modes.
     970             :  *
     971             :  * Returns:
     972             :  * Pointer to duplicated mode on success, NULL on error.
     973             :  */
     974           0 : struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
     975             :                                             const struct drm_display_mode *mode)
     976             : {
     977             :         struct drm_display_mode *nmode;
     978             : 
     979           0 :         nmode = drm_mode_create(dev);
     980           0 :         if (!nmode)
     981             :                 return NULL;
     982             : 
     983           0 :         drm_mode_copy(nmode, mode);
     984             : 
     985           0 :         return nmode;
     986             : }
     987             : EXPORT_SYMBOL(drm_mode_duplicate);
     988             : 
     989             : static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
     990             :                                    const struct drm_display_mode *mode2)
     991             : {
     992           0 :         return mode1->hdisplay == mode2->hdisplay &&
     993             :                 mode1->hsync_start == mode2->hsync_start &&
     994             :                 mode1->hsync_end == mode2->hsync_end &&
     995             :                 mode1->htotal == mode2->htotal &&
     996           0 :                 mode1->hskew == mode2->hskew &&
     997             :                 mode1->vdisplay == mode2->vdisplay &&
     998             :                 mode1->vsync_start == mode2->vsync_start &&
     999             :                 mode1->vsync_end == mode2->vsync_end &&
    1000           0 :                 mode1->vtotal == mode2->vtotal &&
    1001             :                 mode1->vscan == mode2->vscan;
    1002             : }
    1003             : 
    1004             : static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
    1005             :                                   const struct drm_display_mode *mode2)
    1006             : {
    1007             :         /*
    1008             :          * do clock check convert to PICOS
    1009             :          * so fb modes get matched the same
    1010             :          */
    1011           0 :         if (mode1->clock && mode2->clock)
    1012           0 :                 return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
    1013             :         else
    1014           0 :                 return mode1->clock == mode2->clock;
    1015             : }
    1016             : 
    1017             : static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
    1018             :                                  const struct drm_display_mode *mode2)
    1019             : {
    1020           0 :         return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
    1021             :                 (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
    1022             : }
    1023             : 
    1024             : static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
    1025             :                                     const struct drm_display_mode *mode2)
    1026             : {
    1027           0 :         return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
    1028             :                 (mode2->flags & DRM_MODE_FLAG_3D_MASK);
    1029             : }
    1030             : 
    1031             : static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
    1032             :                                         const struct drm_display_mode *mode2)
    1033             : {
    1034             :         return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
    1035             : }
    1036             : 
    1037             : /**
    1038             :  * drm_mode_match - test modes for (partial) equality
    1039             :  * @mode1: first mode
    1040             :  * @mode2: second mode
    1041             :  * @match_flags: which parts need to match (DRM_MODE_MATCH_*)
    1042             :  *
    1043             :  * Check to see if @mode1 and @mode2 are equivalent.
    1044             :  *
    1045             :  * Returns:
    1046             :  * True if the modes are (partially) equal, false otherwise.
    1047             :  */
    1048           0 : bool drm_mode_match(const struct drm_display_mode *mode1,
    1049             :                     const struct drm_display_mode *mode2,
    1050             :                     unsigned int match_flags)
    1051             : {
    1052           0 :         if (!mode1 && !mode2)
    1053             :                 return true;
    1054             : 
    1055           0 :         if (!mode1 || !mode2)
    1056             :                 return false;
    1057             : 
    1058           0 :         if (match_flags & DRM_MODE_MATCH_TIMINGS &&
    1059           0 :             !drm_mode_match_timings(mode1, mode2))
    1060             :                 return false;
    1061             : 
    1062           0 :         if (match_flags & DRM_MODE_MATCH_CLOCK &&
    1063           0 :             !drm_mode_match_clock(mode1, mode2))
    1064             :                 return false;
    1065             : 
    1066           0 :         if (match_flags & DRM_MODE_MATCH_FLAGS &&
    1067           0 :             !drm_mode_match_flags(mode1, mode2))
    1068             :                 return false;
    1069             : 
    1070           0 :         if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
    1071           0 :             !drm_mode_match_3d_flags(mode1, mode2))
    1072             :                 return false;
    1073             : 
    1074           0 :         if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
    1075           0 :             !drm_mode_match_aspect_ratio(mode1, mode2))
    1076             :                 return false;
    1077             : 
    1078             :         return true;
    1079             : }
    1080             : EXPORT_SYMBOL(drm_mode_match);
    1081             : 
    1082             : /**
    1083             :  * drm_mode_equal - test modes for equality
    1084             :  * @mode1: first mode
    1085             :  * @mode2: second mode
    1086             :  *
    1087             :  * Check to see if @mode1 and @mode2 are equivalent.
    1088             :  *
    1089             :  * Returns:
    1090             :  * True if the modes are equal, false otherwise.
    1091             :  */
    1092           0 : bool drm_mode_equal(const struct drm_display_mode *mode1,
    1093             :                     const struct drm_display_mode *mode2)
    1094             : {
    1095           0 :         return drm_mode_match(mode1, mode2,
    1096             :                               DRM_MODE_MATCH_TIMINGS |
    1097             :                               DRM_MODE_MATCH_CLOCK |
    1098             :                               DRM_MODE_MATCH_FLAGS |
    1099             :                               DRM_MODE_MATCH_3D_FLAGS|
    1100             :                               DRM_MODE_MATCH_ASPECT_RATIO);
    1101             : }
    1102             : EXPORT_SYMBOL(drm_mode_equal);
    1103             : 
    1104             : /**
    1105             :  * drm_mode_equal_no_clocks - test modes for equality
    1106             :  * @mode1: first mode
    1107             :  * @mode2: second mode
    1108             :  *
    1109             :  * Check to see if @mode1 and @mode2 are equivalent, but
    1110             :  * don't check the pixel clocks.
    1111             :  *
    1112             :  * Returns:
    1113             :  * True if the modes are equal, false otherwise.
    1114             :  */
    1115           0 : bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
    1116             :                               const struct drm_display_mode *mode2)
    1117             : {
    1118           0 :         return drm_mode_match(mode1, mode2,
    1119             :                               DRM_MODE_MATCH_TIMINGS |
    1120             :                               DRM_MODE_MATCH_FLAGS |
    1121             :                               DRM_MODE_MATCH_3D_FLAGS);
    1122             : }
    1123             : EXPORT_SYMBOL(drm_mode_equal_no_clocks);
    1124             : 
    1125             : /**
    1126             :  * drm_mode_equal_no_clocks_no_stereo - test modes for equality
    1127             :  * @mode1: first mode
    1128             :  * @mode2: second mode
    1129             :  *
    1130             :  * Check to see if @mode1 and @mode2 are equivalent, but
    1131             :  * don't check the pixel clocks nor the stereo layout.
    1132             :  *
    1133             :  * Returns:
    1134             :  * True if the modes are equal, false otherwise.
    1135             :  */
    1136           0 : bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
    1137             :                                         const struct drm_display_mode *mode2)
    1138             : {
    1139           0 :         return drm_mode_match(mode1, mode2,
    1140             :                               DRM_MODE_MATCH_TIMINGS |
    1141             :                               DRM_MODE_MATCH_FLAGS);
    1142             : }
    1143             : EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
    1144             : 
    1145             : static enum drm_mode_status
    1146           0 : drm_mode_validate_basic(const struct drm_display_mode *mode)
    1147             : {
    1148           0 :         if (mode->type & ~DRM_MODE_TYPE_ALL)
    1149             :                 return MODE_BAD;
    1150             : 
    1151           0 :         if (mode->flags & ~DRM_MODE_FLAG_ALL)
    1152             :                 return MODE_BAD;
    1153             : 
    1154           0 :         if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
    1155             :                 return MODE_BAD;
    1156             : 
    1157           0 :         if (mode->clock == 0)
    1158             :                 return MODE_CLOCK_LOW;
    1159             : 
    1160           0 :         if (mode->hdisplay == 0 ||
    1161           0 :             mode->hsync_start < mode->hdisplay ||
    1162           0 :             mode->hsync_end < mode->hsync_start ||
    1163           0 :             mode->htotal < mode->hsync_end)
    1164             :                 return MODE_H_ILLEGAL;
    1165             : 
    1166           0 :         if (mode->vdisplay == 0 ||
    1167           0 :             mode->vsync_start < mode->vdisplay ||
    1168           0 :             mode->vsync_end < mode->vsync_start ||
    1169           0 :             mode->vtotal < mode->vsync_end)
    1170             :                 return MODE_V_ILLEGAL;
    1171             : 
    1172           0 :         return MODE_OK;
    1173             : }
    1174             : 
    1175             : /**
    1176             :  * drm_mode_validate_driver - make sure the mode is somewhat sane
    1177             :  * @dev: drm device
    1178             :  * @mode: mode to check
    1179             :  *
    1180             :  * First do basic validation on the mode, and then allow the driver
    1181             :  * to check for device/driver specific limitations via the optional
    1182             :  * &drm_mode_config_helper_funcs.mode_valid hook.
    1183             :  *
    1184             :  * Returns:
    1185             :  * The mode status
    1186             :  */
    1187             : enum drm_mode_status
    1188           0 : drm_mode_validate_driver(struct drm_device *dev,
    1189             :                         const struct drm_display_mode *mode)
    1190             : {
    1191             :         enum drm_mode_status status;
    1192             : 
    1193           0 :         status = drm_mode_validate_basic(mode);
    1194           0 :         if (status != MODE_OK)
    1195             :                 return status;
    1196             : 
    1197           0 :         if (dev->mode_config.funcs->mode_valid)
    1198           0 :                 return dev->mode_config.funcs->mode_valid(dev, mode);
    1199             :         else
    1200             :                 return MODE_OK;
    1201             : }
    1202             : EXPORT_SYMBOL(drm_mode_validate_driver);
    1203             : 
    1204             : /**
    1205             :  * drm_mode_validate_size - make sure modes adhere to size constraints
    1206             :  * @mode: mode to check
    1207             :  * @maxX: maximum width
    1208             :  * @maxY: maximum height
    1209             :  *
    1210             :  * This function is a helper which can be used to validate modes against size
    1211             :  * limitations of the DRM device/connector. If a mode is too big its status
    1212             :  * member is updated with the appropriate validation failure code. The list
    1213             :  * itself is not changed.
    1214             :  *
    1215             :  * Returns:
    1216             :  * The mode status
    1217             :  */
    1218             : enum drm_mode_status
    1219           0 : drm_mode_validate_size(const struct drm_display_mode *mode,
    1220             :                        int maxX, int maxY)
    1221             : {
    1222           0 :         if (maxX > 0 && mode->hdisplay > maxX)
    1223             :                 return MODE_VIRTUAL_X;
    1224             : 
    1225           0 :         if (maxY > 0 && mode->vdisplay > maxY)
    1226             :                 return MODE_VIRTUAL_Y;
    1227             : 
    1228           0 :         return MODE_OK;
    1229             : }
    1230             : EXPORT_SYMBOL(drm_mode_validate_size);
    1231             : 
    1232             : /**
    1233             :  * drm_mode_validate_ycbcr420 - add 'ycbcr420-only' modes only when allowed
    1234             :  * @mode: mode to check
    1235             :  * @connector: drm connector under action
    1236             :  *
    1237             :  * This function is a helper which can be used to filter out any YCBCR420
    1238             :  * only mode, when the source doesn't support it.
    1239             :  *
    1240             :  * Returns:
    1241             :  * The mode status
    1242             :  */
    1243             : enum drm_mode_status
    1244           0 : drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
    1245             :                            struct drm_connector *connector)
    1246             : {
    1247           0 :         if (!connector->ycbcr_420_allowed &&
    1248           0 :             drm_mode_is_420_only(&connector->display_info, mode))
    1249             :                 return MODE_NO_420;
    1250             : 
    1251             :         return MODE_OK;
    1252             : }
    1253             : EXPORT_SYMBOL(drm_mode_validate_ycbcr420);
    1254             : 
    1255             : #define MODE_STATUS(status) [MODE_ ## status + 3] = #status
    1256             : 
    1257             : static const char * const drm_mode_status_names[] = {
    1258             :         MODE_STATUS(OK),
    1259             :         MODE_STATUS(HSYNC),
    1260             :         MODE_STATUS(VSYNC),
    1261             :         MODE_STATUS(H_ILLEGAL),
    1262             :         MODE_STATUS(V_ILLEGAL),
    1263             :         MODE_STATUS(BAD_WIDTH),
    1264             :         MODE_STATUS(NOMODE),
    1265             :         MODE_STATUS(NO_INTERLACE),
    1266             :         MODE_STATUS(NO_DBLESCAN),
    1267             :         MODE_STATUS(NO_VSCAN),
    1268             :         MODE_STATUS(MEM),
    1269             :         MODE_STATUS(VIRTUAL_X),
    1270             :         MODE_STATUS(VIRTUAL_Y),
    1271             :         MODE_STATUS(MEM_VIRT),
    1272             :         MODE_STATUS(NOCLOCK),
    1273             :         MODE_STATUS(CLOCK_HIGH),
    1274             :         MODE_STATUS(CLOCK_LOW),
    1275             :         MODE_STATUS(CLOCK_RANGE),
    1276             :         MODE_STATUS(BAD_HVALUE),
    1277             :         MODE_STATUS(BAD_VVALUE),
    1278             :         MODE_STATUS(BAD_VSCAN),
    1279             :         MODE_STATUS(HSYNC_NARROW),
    1280             :         MODE_STATUS(HSYNC_WIDE),
    1281             :         MODE_STATUS(HBLANK_NARROW),
    1282             :         MODE_STATUS(HBLANK_WIDE),
    1283             :         MODE_STATUS(VSYNC_NARROW),
    1284             :         MODE_STATUS(VSYNC_WIDE),
    1285             :         MODE_STATUS(VBLANK_NARROW),
    1286             :         MODE_STATUS(VBLANK_WIDE),
    1287             :         MODE_STATUS(PANEL),
    1288             :         MODE_STATUS(INTERLACE_WIDTH),
    1289             :         MODE_STATUS(ONE_WIDTH),
    1290             :         MODE_STATUS(ONE_HEIGHT),
    1291             :         MODE_STATUS(ONE_SIZE),
    1292             :         MODE_STATUS(NO_REDUCED),
    1293             :         MODE_STATUS(NO_STEREO),
    1294             :         MODE_STATUS(NO_420),
    1295             :         MODE_STATUS(STALE),
    1296             :         MODE_STATUS(BAD),
    1297             :         MODE_STATUS(ERROR),
    1298             : };
    1299             : 
    1300             : #undef MODE_STATUS
    1301             : 
    1302           0 : const char *drm_get_mode_status_name(enum drm_mode_status status)
    1303             : {
    1304           0 :         int index = status + 3;
    1305             : 
    1306           0 :         if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
    1307             :                 return "";
    1308             : 
    1309           0 :         return drm_mode_status_names[index];
    1310             : }
    1311             : 
    1312             : /**
    1313             :  * drm_mode_prune_invalid - remove invalid modes from mode list
    1314             :  * @dev: DRM device
    1315             :  * @mode_list: list of modes to check
    1316             :  * @verbose: be verbose about it
    1317             :  *
    1318             :  * This helper function can be used to prune a display mode list after
    1319             :  * validation has been completed. All modes whose status is not MODE_OK will be
    1320             :  * removed from the list, and if @verbose the status code and mode name is also
    1321             :  * printed to dmesg.
    1322             :  */
    1323           0 : void drm_mode_prune_invalid(struct drm_device *dev,
    1324             :                             struct list_head *mode_list, bool verbose)
    1325             : {
    1326             :         struct drm_display_mode *mode, *t;
    1327             : 
    1328           0 :         list_for_each_entry_safe(mode, t, mode_list, head) {
    1329           0 :                 if (mode->status != MODE_OK) {
    1330           0 :                         list_del(&mode->head);
    1331           0 :                         if (verbose) {
    1332           0 :                                 drm_mode_debug_printmodeline(mode);
    1333           0 :                                 DRM_DEBUG_KMS("Not using %s mode: %s\n",
    1334             :                                               mode->name,
    1335             :                                               drm_get_mode_status_name(mode->status));
    1336             :                         }
    1337             :                         drm_mode_destroy(dev, mode);
    1338             :                 }
    1339             :         }
    1340           0 : }
    1341             : EXPORT_SYMBOL(drm_mode_prune_invalid);
    1342             : 
    1343             : /**
    1344             :  * drm_mode_compare - compare modes for favorability
    1345             :  * @priv: unused
    1346             :  * @lh_a: list_head for first mode
    1347             :  * @lh_b: list_head for second mode
    1348             :  *
    1349             :  * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
    1350             :  * which is better.
    1351             :  *
    1352             :  * Returns:
    1353             :  * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
    1354             :  * positive if @lh_b is better than @lh_a.
    1355             :  */
    1356           0 : static int drm_mode_compare(void *priv, const struct list_head *lh_a,
    1357             :                             const struct list_head *lh_b)
    1358             : {
    1359           0 :         struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
    1360           0 :         struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
    1361             :         int diff;
    1362             : 
    1363           0 :         diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
    1364           0 :                 ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
    1365           0 :         if (diff)
    1366             :                 return diff;
    1367           0 :         diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
    1368           0 :         if (diff)
    1369             :                 return diff;
    1370             : 
    1371           0 :         diff = drm_mode_vrefresh(b) - drm_mode_vrefresh(a);
    1372           0 :         if (diff)
    1373             :                 return diff;
    1374             : 
    1375           0 :         diff = b->clock - a->clock;
    1376           0 :         return diff;
    1377             : }
    1378             : 
    1379             : /**
    1380             :  * drm_mode_sort - sort mode list
    1381             :  * @mode_list: list of drm_display_mode structures to sort
    1382             :  *
    1383             :  * Sort @mode_list by favorability, moving good modes to the head of the list.
    1384             :  */
    1385           0 : void drm_mode_sort(struct list_head *mode_list)
    1386             : {
    1387           0 :         list_sort(NULL, mode_list, drm_mode_compare);
    1388           0 : }
    1389             : EXPORT_SYMBOL(drm_mode_sort);
    1390             : 
    1391             : /**
    1392             :  * drm_connector_list_update - update the mode list for the connector
    1393             :  * @connector: the connector to update
    1394             :  *
    1395             :  * This moves the modes from the @connector probed_modes list
    1396             :  * to the actual mode list. It compares the probed mode against the current
    1397             :  * list and only adds different/new modes.
    1398             :  *
    1399             :  * This is just a helper functions doesn't validate any modes itself and also
    1400             :  * doesn't prune any invalid modes. Callers need to do that themselves.
    1401             :  */
    1402           0 : void drm_connector_list_update(struct drm_connector *connector)
    1403             : {
    1404             :         struct drm_display_mode *pmode, *pt;
    1405             : 
    1406           0 :         WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
    1407             : 
    1408           0 :         list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
    1409             :                 struct drm_display_mode *mode;
    1410           0 :                 bool found_it = false;
    1411             : 
    1412             :                 /* go through current modes checking for the new probed mode */
    1413           0 :                 list_for_each_entry(mode, &connector->modes, head) {
    1414           0 :                         if (!drm_mode_equal(pmode, mode))
    1415           0 :                                 continue;
    1416             : 
    1417           0 :                         found_it = true;
    1418             : 
    1419             :                         /*
    1420             :                          * If the old matching mode is stale (ie. left over
    1421             :                          * from a previous probe) just replace it outright.
    1422             :                          * Otherwise just merge the type bits between all
    1423             :                          * equal probed modes.
    1424             :                          *
    1425             :                          * If two probed modes are considered equal, pick the
    1426             :                          * actual timings from the one that's marked as
    1427             :                          * preferred (in case the match isn't 100%). If
    1428             :                          * multiple or zero preferred modes are present, favor
    1429             :                          * the mode added to the probed_modes list first.
    1430             :                          */
    1431           0 :                         if (mode->status == MODE_STALE) {
    1432             :                                 drm_mode_copy(mode, pmode);
    1433           0 :                         } else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
    1434           0 :                                    (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
    1435           0 :                                 pmode->type |= mode->type;
    1436             :                                 drm_mode_copy(mode, pmode);
    1437             :                         } else {
    1438           0 :                                 mode->type |= pmode->type;
    1439             :                         }
    1440             : 
    1441           0 :                         list_del(&pmode->head);
    1442           0 :                         drm_mode_destroy(connector->dev, pmode);
    1443             :                         break;
    1444             :                 }
    1445             : 
    1446           0 :                 if (!found_it) {
    1447           0 :                         list_move_tail(&pmode->head, &connector->modes);
    1448             :                 }
    1449             :         }
    1450           0 : }
    1451             : EXPORT_SYMBOL(drm_connector_list_update);
    1452             : 
    1453             : static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
    1454             :                                       struct drm_cmdline_mode *mode)
    1455             : {
    1456             :         unsigned int bpp;
    1457             : 
    1458           0 :         if (str[0] != '-')
    1459             :                 return -EINVAL;
    1460             : 
    1461           0 :         str++;
    1462           0 :         bpp = simple_strtol(str, end_ptr, 10);
    1463           0 :         if (*end_ptr == str)
    1464             :                 return -EINVAL;
    1465             : 
    1466           0 :         mode->bpp = bpp;
    1467           0 :         mode->bpp_specified = true;
    1468             : 
    1469             :         return 0;
    1470             : }
    1471             : 
    1472             : static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
    1473             :                                           struct drm_cmdline_mode *mode)
    1474             : {
    1475             :         unsigned int refresh;
    1476             : 
    1477           0 :         if (str[0] != '@')
    1478             :                 return -EINVAL;
    1479             : 
    1480           0 :         str++;
    1481           0 :         refresh = simple_strtol(str, end_ptr, 10);
    1482           0 :         if (*end_ptr == str)
    1483             :                 return -EINVAL;
    1484             : 
    1485           0 :         mode->refresh = refresh;
    1486           0 :         mode->refresh_specified = true;
    1487             : 
    1488             :         return 0;
    1489             : }
    1490             : 
    1491           0 : static int drm_mode_parse_cmdline_extra(const char *str, int length,
    1492             :                                         bool freestanding,
    1493             :                                         const struct drm_connector *connector,
    1494             :                                         struct drm_cmdline_mode *mode)
    1495             : {
    1496             :         int i;
    1497             : 
    1498           0 :         for (i = 0; i < length; i++) {
    1499           0 :                 switch (str[i]) {
    1500             :                 case 'i':
    1501           0 :                         if (freestanding)
    1502             :                                 return -EINVAL;
    1503             : 
    1504           0 :                         mode->interlace = true;
    1505           0 :                         break;
    1506             :                 case 'm':
    1507           0 :                         if (freestanding)
    1508             :                                 return -EINVAL;
    1509             : 
    1510           0 :                         mode->margins = true;
    1511           0 :                         break;
    1512             :                 case 'D':
    1513           0 :                         if (mode->force != DRM_FORCE_UNSPECIFIED)
    1514             :                                 return -EINVAL;
    1515             : 
    1516           0 :                         if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
    1517             :                             (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
    1518           0 :                                 mode->force = DRM_FORCE_ON;
    1519             :                         else
    1520           0 :                                 mode->force = DRM_FORCE_ON_DIGITAL;
    1521             :                         break;
    1522             :                 case 'd':
    1523           0 :                         if (mode->force != DRM_FORCE_UNSPECIFIED)
    1524             :                                 return -EINVAL;
    1525             : 
    1526           0 :                         mode->force = DRM_FORCE_OFF;
    1527           0 :                         break;
    1528             :                 case 'e':
    1529           0 :                         if (mode->force != DRM_FORCE_UNSPECIFIED)
    1530             :                                 return -EINVAL;
    1531             : 
    1532           0 :                         mode->force = DRM_FORCE_ON;
    1533           0 :                         break;
    1534             :                 default:
    1535             :                         return -EINVAL;
    1536             :                 }
    1537             :         }
    1538             : 
    1539             :         return 0;
    1540             : }
    1541             : 
    1542           0 : static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
    1543             :                                            bool extras,
    1544             :                                            const struct drm_connector *connector,
    1545             :                                            struct drm_cmdline_mode *mode)
    1546             : {
    1547           0 :         const char *str_start = str;
    1548           0 :         bool rb = false, cvt = false;
    1549           0 :         int xres = 0, yres = 0;
    1550             :         int remaining, i;
    1551             :         char *end_ptr;
    1552             : 
    1553           0 :         xres = simple_strtol(str, &end_ptr, 10);
    1554           0 :         if (end_ptr == str)
    1555             :                 return -EINVAL;
    1556             : 
    1557           0 :         if (end_ptr[0] != 'x')
    1558             :                 return -EINVAL;
    1559           0 :         end_ptr++;
    1560             : 
    1561           0 :         str = end_ptr;
    1562           0 :         yres = simple_strtol(str, &end_ptr, 10);
    1563           0 :         if (end_ptr == str)
    1564             :                 return -EINVAL;
    1565             : 
    1566           0 :         remaining = length - (end_ptr - str_start);
    1567           0 :         if (remaining < 0)
    1568             :                 return -EINVAL;
    1569             : 
    1570           0 :         for (i = 0; i < remaining; i++) {
    1571           0 :                 switch (end_ptr[i]) {
    1572             :                 case 'M':
    1573             :                         cvt = true;
    1574             :                         break;
    1575             :                 case 'R':
    1576           0 :                         rb = true;
    1577           0 :                         break;
    1578             :                 default:
    1579             :                         /*
    1580             :                          * Try to pass that to our extras parsing
    1581             :                          * function to handle the case where the
    1582             :                          * extras are directly after the resolution
    1583             :                          */
    1584           0 :                         if (extras) {
    1585           0 :                                 int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
    1586             :                                                                        1,
    1587             :                                                                        false,
    1588             :                                                                        connector,
    1589             :                                                                        mode);
    1590           0 :                                 if (ret)
    1591             :                                         return ret;
    1592             :                         } else {
    1593             :                                 return -EINVAL;
    1594             :                         }
    1595             :                 }
    1596             :         }
    1597             : 
    1598           0 :         mode->xres = xres;
    1599           0 :         mode->yres = yres;
    1600           0 :         mode->cvt = cvt;
    1601           0 :         mode->rb = rb;
    1602             : 
    1603           0 :         return 0;
    1604             : }
    1605             : 
    1606           0 : static int drm_mode_parse_cmdline_int(const char *delim, unsigned int *int_ret)
    1607             : {
    1608             :         const char *value;
    1609             :         char *endp;
    1610             : 
    1611             :         /*
    1612             :          * delim must point to the '=', otherwise it is a syntax error and
    1613             :          * if delim points to the terminating zero, then delim + 1 will point
    1614             :          * past the end of the string.
    1615             :          */
    1616           0 :         if (*delim != '=')
    1617             :                 return -EINVAL;
    1618             : 
    1619           0 :         value = delim + 1;
    1620           0 :         *int_ret = simple_strtol(value, &endp, 10);
    1621             : 
    1622             :         /* Make sure we have parsed something */
    1623           0 :         if (endp == value)
    1624             :                 return -EINVAL;
    1625             : 
    1626           0 :         return 0;
    1627             : }
    1628             : 
    1629           0 : static int drm_mode_parse_panel_orientation(const char *delim,
    1630             :                                             struct drm_cmdline_mode *mode)
    1631             : {
    1632             :         const char *value;
    1633             : 
    1634           0 :         if (*delim != '=')
    1635             :                 return -EINVAL;
    1636             : 
    1637           0 :         value = delim + 1;
    1638           0 :         delim = strchr(value, ',');
    1639           0 :         if (!delim)
    1640           0 :                 delim = value + strlen(value);
    1641             : 
    1642           0 :         if (!strncmp(value, "normal", delim - value))
    1643           0 :                 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
    1644           0 :         else if (!strncmp(value, "upside_down", delim - value))
    1645           0 :                 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
    1646           0 :         else if (!strncmp(value, "left_side_up", delim - value))
    1647           0 :                 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
    1648           0 :         else if (!strncmp(value, "right_side_up", delim - value))
    1649           0 :                 mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
    1650             :         else
    1651             :                 return -EINVAL;
    1652             : 
    1653             :         return 0;
    1654             : }
    1655             : 
    1656           0 : static int drm_mode_parse_cmdline_options(const char *str,
    1657             :                                           bool freestanding,
    1658             :                                           const struct drm_connector *connector,
    1659             :                                           struct drm_cmdline_mode *mode)
    1660             : {
    1661           0 :         unsigned int deg, margin, rotation = 0;
    1662             :         const char *delim, *option, *sep;
    1663             : 
    1664           0 :         option = str;
    1665             :         do {
    1666           0 :                 delim = strchr(option, '=');
    1667           0 :                 if (!delim) {
    1668           0 :                         delim = strchr(option, ',');
    1669             : 
    1670           0 :                         if (!delim)
    1671           0 :                                 delim = option + strlen(option);
    1672             :                 }
    1673             : 
    1674           0 :                 if (!strncmp(option, "rotate", delim - option)) {
    1675           0 :                         if (drm_mode_parse_cmdline_int(delim, &deg))
    1676             :                                 return -EINVAL;
    1677             : 
    1678           0 :                         switch (deg) {
    1679             :                         case 0:
    1680           0 :                                 rotation |= DRM_MODE_ROTATE_0;
    1681           0 :                                 break;
    1682             : 
    1683             :                         case 90:
    1684           0 :                                 rotation |= DRM_MODE_ROTATE_90;
    1685           0 :                                 break;
    1686             : 
    1687             :                         case 180:
    1688           0 :                                 rotation |= DRM_MODE_ROTATE_180;
    1689           0 :                                 break;
    1690             : 
    1691             :                         case 270:
    1692           0 :                                 rotation |= DRM_MODE_ROTATE_270;
    1693           0 :                                 break;
    1694             : 
    1695             :                         default:
    1696             :                                 return -EINVAL;
    1697             :                         }
    1698           0 :                 } else if (!strncmp(option, "reflect_x", delim - option)) {
    1699           0 :                         rotation |= DRM_MODE_REFLECT_X;
    1700           0 :                 } else if (!strncmp(option, "reflect_y", delim - option)) {
    1701           0 :                         rotation |= DRM_MODE_REFLECT_Y;
    1702           0 :                 } else if (!strncmp(option, "margin_right", delim - option)) {
    1703           0 :                         if (drm_mode_parse_cmdline_int(delim, &margin))
    1704             :                                 return -EINVAL;
    1705             : 
    1706           0 :                         mode->tv_margins.right = margin;
    1707           0 :                 } else if (!strncmp(option, "margin_left", delim - option)) {
    1708           0 :                         if (drm_mode_parse_cmdline_int(delim, &margin))
    1709             :                                 return -EINVAL;
    1710             : 
    1711           0 :                         mode->tv_margins.left = margin;
    1712           0 :                 } else if (!strncmp(option, "margin_top", delim - option)) {
    1713           0 :                         if (drm_mode_parse_cmdline_int(delim, &margin))
    1714             :                                 return -EINVAL;
    1715             : 
    1716           0 :                         mode->tv_margins.top = margin;
    1717           0 :                 } else if (!strncmp(option, "margin_bottom", delim - option)) {
    1718           0 :                         if (drm_mode_parse_cmdline_int(delim, &margin))
    1719             :                                 return -EINVAL;
    1720             : 
    1721           0 :                         mode->tv_margins.bottom = margin;
    1722           0 :                 } else if (!strncmp(option, "panel_orientation", delim - option)) {
    1723           0 :                         if (drm_mode_parse_panel_orientation(delim, mode))
    1724             :                                 return -EINVAL;
    1725             :                 } else {
    1726             :                         return -EINVAL;
    1727             :                 }
    1728           0 :                 sep = strchr(delim, ',');
    1729           0 :                 option = sep + 1;
    1730           0 :         } while (sep);
    1731             : 
    1732           0 :         if (rotation && freestanding)
    1733             :                 return -EINVAL;
    1734             : 
    1735           0 :         if (!(rotation & DRM_MODE_ROTATE_MASK))
    1736           0 :                 rotation |= DRM_MODE_ROTATE_0;
    1737             : 
    1738             :         /* Make sure there is exactly one rotation defined */
    1739           0 :         if (!is_power_of_2(rotation & DRM_MODE_ROTATE_MASK))
    1740             :                 return -EINVAL;
    1741             : 
    1742           0 :         mode->rotation_reflection = rotation;
    1743             : 
    1744           0 :         return 0;
    1745             : }
    1746             : 
    1747             : static const char * const drm_named_modes_whitelist[] = {
    1748             :         "NTSC",
    1749             :         "PAL",
    1750             : };
    1751             : 
    1752             : /**
    1753             :  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
    1754             :  * @mode_option: optional per connector mode option
    1755             :  * @connector: connector to parse modeline for
    1756             :  * @mode: preallocated drm_cmdline_mode structure to fill out
    1757             :  *
    1758             :  * This parses @mode_option command line modeline for modes and options to
    1759             :  * configure the connector. If @mode_option is NULL the default command line
    1760             :  * modeline in fb_mode_option will be parsed instead.
    1761             :  *
    1762             :  * This uses the same parameters as the fb modedb.c, except for an extra
    1763             :  * force-enable, force-enable-digital and force-disable bit at the end::
    1764             :  *
    1765             :  *      <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
    1766             :  *
    1767             :  * Additionals options can be provided following the mode, using a comma to
    1768             :  * separate each option. Valid options can be found in
    1769             :  * Documentation/fb/modedb.rst.
    1770             :  *
    1771             :  * The intermediate drm_cmdline_mode structure is required to store additional
    1772             :  * options from the command line modline like the force-enable/disable flag.
    1773             :  *
    1774             :  * Returns:
    1775             :  * True if a valid modeline has been parsed, false otherwise.
    1776             :  */
    1777           0 : bool drm_mode_parse_command_line_for_connector(const char *mode_option,
    1778             :                                                const struct drm_connector *connector,
    1779             :                                                struct drm_cmdline_mode *mode)
    1780             : {
    1781             :         const char *name;
    1782           0 :         bool freestanding = false, parse_extras = false;
    1783           0 :         unsigned int bpp_off = 0, refresh_off = 0, options_off = 0;
    1784           0 :         unsigned int mode_end = 0;
    1785           0 :         const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
    1786           0 :         const char *options_ptr = NULL;
    1787           0 :         char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
    1788             :         int i, len, ret;
    1789             : 
    1790           0 :         memset(mode, 0, sizeof(*mode));
    1791           0 :         mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
    1792             : 
    1793           0 :         if (!mode_option)
    1794             :                 return false;
    1795             : 
    1796           0 :         name = mode_option;
    1797             : 
    1798             :         /* Try to locate the bpp and refresh specifiers, if any */
    1799           0 :         bpp_ptr = strchr(name, '-');
    1800           0 :         if (bpp_ptr)
    1801           0 :                 bpp_off = bpp_ptr - name;
    1802             : 
    1803           0 :         refresh_ptr = strchr(name, '@');
    1804           0 :         if (refresh_ptr)
    1805           0 :                 refresh_off = refresh_ptr - name;
    1806             : 
    1807             :         /* Locate the start of named options */
    1808           0 :         options_ptr = strchr(name, ',');
    1809           0 :         if (options_ptr)
    1810           0 :                 options_off = options_ptr - name;
    1811             : 
    1812             :         /* Locate the end of the name / resolution, and parse it */
    1813           0 :         if (bpp_ptr) {
    1814             :                 mode_end = bpp_off;
    1815           0 :         } else if (refresh_ptr) {
    1816             :                 mode_end = refresh_off;
    1817           0 :         } else if (options_ptr) {
    1818             :                 mode_end = options_off;
    1819             :                 parse_extras = true;
    1820             :         } else {
    1821           0 :                 mode_end = strlen(name);
    1822           0 :                 parse_extras = true;
    1823             :         }
    1824             : 
    1825             :         /* First check for a named mode */
    1826           0 :         for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
    1827           0 :                 ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
    1828           0 :                 if (ret == mode_end) {
    1829           0 :                         if (refresh_ptr)
    1830             :                                 return false; /* named + refresh is invalid */
    1831             : 
    1832           0 :                         strcpy(mode->name, drm_named_modes_whitelist[i]);
    1833           0 :                         mode->specified = true;
    1834           0 :                         break;
    1835             :                 }
    1836             :         }
    1837             : 
    1838             :         /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
    1839           0 :         if (!mode->specified && isdigit(name[0])) {
    1840           0 :                 ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
    1841             :                                                       parse_extras,
    1842             :                                                       connector,
    1843             :                                                       mode);
    1844           0 :                 if (ret)
    1845             :                         return false;
    1846             : 
    1847           0 :                 mode->specified = true;
    1848             :         }
    1849             : 
    1850             :         /* No mode? Check for freestanding extras and/or options */
    1851           0 :         if (!mode->specified) {
    1852           0 :                 unsigned int len = strlen(mode_option);
    1853             : 
    1854           0 :                 if (bpp_ptr || refresh_ptr)
    1855             :                         return false; /* syntax error */
    1856             : 
    1857           0 :                 if (len == 1 || (len >= 2 && mode_option[1] == ','))
    1858             :                         extra_ptr = mode_option;
    1859             :                 else
    1860           0 :                         options_ptr = mode_option - 1;
    1861             : 
    1862             :                 freestanding = true;
    1863             :         }
    1864             : 
    1865           0 :         if (bpp_ptr) {
    1866           0 :                 ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
    1867           0 :                 if (ret)
    1868             :                         return false;
    1869             : 
    1870           0 :                 mode->bpp_specified = true;
    1871             :         }
    1872             : 
    1873           0 :         if (refresh_ptr) {
    1874           0 :                 ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
    1875             :                                                      &refresh_end_ptr, mode);
    1876           0 :                 if (ret)
    1877             :                         return false;
    1878             : 
    1879           0 :                 mode->refresh_specified = true;
    1880             :         }
    1881             : 
    1882             :         /*
    1883             :          * Locate the end of the bpp / refresh, and parse the extras
    1884             :          * if relevant
    1885             :          */
    1886           0 :         if (bpp_ptr && refresh_ptr)
    1887           0 :                 extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
    1888           0 :         else if (bpp_ptr)
    1889           0 :                 extra_ptr = bpp_end_ptr;
    1890           0 :         else if (refresh_ptr)
    1891           0 :                 extra_ptr = refresh_end_ptr;
    1892             : 
    1893           0 :         if (extra_ptr) {
    1894           0 :                 if (options_ptr)
    1895           0 :                         len = options_ptr - extra_ptr;
    1896             :                 else
    1897           0 :                         len = strlen(extra_ptr);
    1898             : 
    1899           0 :                 ret = drm_mode_parse_cmdline_extra(extra_ptr, len, freestanding,
    1900             :                                                    connector, mode);
    1901           0 :                 if (ret)
    1902             :                         return false;
    1903             :         }
    1904             : 
    1905           0 :         if (options_ptr) {
    1906           0 :                 ret = drm_mode_parse_cmdline_options(options_ptr + 1,
    1907             :                                                      freestanding,
    1908             :                                                      connector, mode);
    1909           0 :                 if (ret)
    1910             :                         return false;
    1911             :         }
    1912             : 
    1913             :         return true;
    1914             : }
    1915             : EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
    1916             : 
    1917             : /**
    1918             :  * drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
    1919             :  * @dev: DRM device to create the new mode for
    1920             :  * @cmd: input command line modeline
    1921             :  *
    1922             :  * Returns:
    1923             :  * Pointer to converted mode on success, NULL on error.
    1924             :  */
    1925             : struct drm_display_mode *
    1926           0 : drm_mode_create_from_cmdline_mode(struct drm_device *dev,
    1927             :                                   struct drm_cmdline_mode *cmd)
    1928             : {
    1929             :         struct drm_display_mode *mode;
    1930             : 
    1931           0 :         if (cmd->xres == 0 || cmd->yres == 0)
    1932             :                 return NULL;
    1933             : 
    1934           0 :         if (cmd->cvt)
    1935           0 :                 mode = drm_cvt_mode(dev,
    1936             :                                     cmd->xres, cmd->yres,
    1937           0 :                                     cmd->refresh_specified ? cmd->refresh : 60,
    1938           0 :                                     cmd->rb, cmd->interlace,
    1939           0 :                                     cmd->margins);
    1940             :         else
    1941           0 :                 mode = drm_gtf_mode(dev,
    1942             :                                     cmd->xres, cmd->yres,
    1943           0 :                                     cmd->refresh_specified ? cmd->refresh : 60,
    1944           0 :                                     cmd->interlace,
    1945           0 :                                     cmd->margins);
    1946           0 :         if (!mode)
    1947             :                 return NULL;
    1948             : 
    1949           0 :         mode->type |= DRM_MODE_TYPE_USERDEF;
    1950             :         /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */
    1951           0 :         if (cmd->xres == 1366)
    1952           0 :                 drm_mode_fixup_1366x768(mode);
    1953           0 :         drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
    1954           0 :         return mode;
    1955             : }
    1956             : EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
    1957             : 
    1958             : /**
    1959             :  * drm_mode_convert_to_umode - convert a drm_display_mode into a modeinfo
    1960             :  * @out: drm_mode_modeinfo struct to return to the user
    1961             :  * @in: drm_display_mode to use
    1962             :  *
    1963             :  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
    1964             :  * the user.
    1965             :  */
    1966           0 : void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out,
    1967             :                                const struct drm_display_mode *in)
    1968             : {
    1969           0 :         out->clock = in->clock;
    1970           0 :         out->hdisplay = in->hdisplay;
    1971           0 :         out->hsync_start = in->hsync_start;
    1972           0 :         out->hsync_end = in->hsync_end;
    1973           0 :         out->htotal = in->htotal;
    1974           0 :         out->hskew = in->hskew;
    1975           0 :         out->vdisplay = in->vdisplay;
    1976           0 :         out->vsync_start = in->vsync_start;
    1977           0 :         out->vsync_end = in->vsync_end;
    1978           0 :         out->vtotal = in->vtotal;
    1979           0 :         out->vscan = in->vscan;
    1980           0 :         out->vrefresh = drm_mode_vrefresh(in);
    1981           0 :         out->flags = in->flags;
    1982           0 :         out->type = in->type;
    1983             : 
    1984           0 :         switch (in->picture_aspect_ratio) {
    1985             :         case HDMI_PICTURE_ASPECT_4_3:
    1986           0 :                 out->flags |= DRM_MODE_FLAG_PIC_AR_4_3;
    1987           0 :                 break;
    1988             :         case HDMI_PICTURE_ASPECT_16_9:
    1989           0 :                 out->flags |= DRM_MODE_FLAG_PIC_AR_16_9;
    1990           0 :                 break;
    1991             :         case HDMI_PICTURE_ASPECT_64_27:
    1992           0 :                 out->flags |= DRM_MODE_FLAG_PIC_AR_64_27;
    1993           0 :                 break;
    1994             :         case HDMI_PICTURE_ASPECT_256_135:
    1995           0 :                 out->flags |= DRM_MODE_FLAG_PIC_AR_256_135;
    1996           0 :                 break;
    1997             :         default:
    1998           0 :                 WARN(1, "Invalid aspect ratio (0%x) on mode\n",
    1999             :                      in->picture_aspect_ratio);
    2000             :                 fallthrough;
    2001             :         case HDMI_PICTURE_ASPECT_NONE:
    2002             :                 out->flags |= DRM_MODE_FLAG_PIC_AR_NONE;
    2003           0 :                 break;
    2004             :         }
    2005             : 
    2006           0 :         strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
    2007           0 :         out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
    2008           0 : }
    2009             : 
    2010             : /**
    2011             :  * drm_mode_convert_umode - convert a modeinfo into a drm_display_mode
    2012             :  * @dev: drm device
    2013             :  * @out: drm_display_mode to return to the user
    2014             :  * @in: drm_mode_modeinfo to use
    2015             :  *
    2016             :  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
    2017             :  * the caller.
    2018             :  *
    2019             :  * Returns:
    2020             :  * Zero on success, negative errno on failure.
    2021             :  */
    2022           0 : int drm_mode_convert_umode(struct drm_device *dev,
    2023             :                            struct drm_display_mode *out,
    2024             :                            const struct drm_mode_modeinfo *in)
    2025             : {
    2026           0 :         if (in->clock > INT_MAX || in->vrefresh > INT_MAX)
    2027             :                 return -ERANGE;
    2028             : 
    2029           0 :         out->clock = in->clock;
    2030           0 :         out->hdisplay = in->hdisplay;
    2031           0 :         out->hsync_start = in->hsync_start;
    2032           0 :         out->hsync_end = in->hsync_end;
    2033           0 :         out->htotal = in->htotal;
    2034           0 :         out->hskew = in->hskew;
    2035           0 :         out->vdisplay = in->vdisplay;
    2036           0 :         out->vsync_start = in->vsync_start;
    2037           0 :         out->vsync_end = in->vsync_end;
    2038           0 :         out->vtotal = in->vtotal;
    2039           0 :         out->vscan = in->vscan;
    2040           0 :         out->flags = in->flags;
    2041             :         /*
    2042             :          * Old xf86-video-vmware (possibly others too) used to
    2043             :          * leave 'type' uninitialized. Just ignore any bits we
    2044             :          * don't like. It's a just hint after all, and more
    2045             :          * useful for the kernel->userspace direction anyway.
    2046             :          */
    2047           0 :         out->type = in->type & DRM_MODE_TYPE_ALL;
    2048           0 :         strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
    2049           0 :         out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
    2050             : 
    2051             :         /* Clearing picture aspect ratio bits from out flags,
    2052             :          * as the aspect-ratio information is not stored in
    2053             :          * flags for kernel-mode, but in picture_aspect_ratio.
    2054             :          */
    2055           0 :         out->flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
    2056             : 
    2057           0 :         switch (in->flags & DRM_MODE_FLAG_PIC_AR_MASK) {
    2058             :         case DRM_MODE_FLAG_PIC_AR_4_3:
    2059           0 :                 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3;
    2060           0 :                 break;
    2061             :         case DRM_MODE_FLAG_PIC_AR_16_9:
    2062           0 :                 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9;
    2063           0 :                 break;
    2064             :         case DRM_MODE_FLAG_PIC_AR_64_27:
    2065           0 :                 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27;
    2066           0 :                 break;
    2067             :         case DRM_MODE_FLAG_PIC_AR_256_135:
    2068           0 :                 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135;
    2069           0 :                 break;
    2070             :         case DRM_MODE_FLAG_PIC_AR_NONE:
    2071           0 :                 out->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
    2072           0 :                 break;
    2073             :         default:
    2074             :                 return -EINVAL;
    2075             :         }
    2076             : 
    2077           0 :         out->status = drm_mode_validate_driver(dev, out);
    2078           0 :         if (out->status != MODE_OK)
    2079             :                 return -EINVAL;
    2080             : 
    2081           0 :         drm_mode_set_crtcinfo(out, CRTC_INTERLACE_HALVE_V);
    2082             : 
    2083           0 :         return 0;
    2084             : }
    2085             : 
    2086             : /**
    2087             :  * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
    2088             :  * output format
    2089             :  *
    2090             :  * @display: display under action
    2091             :  * @mode: video mode to be tested.
    2092             :  *
    2093             :  * Returns:
    2094             :  * true if the mode can be supported in YCBCR420 format
    2095             :  * false if not.
    2096             :  */
    2097           0 : bool drm_mode_is_420_only(const struct drm_display_info *display,
    2098             :                           const struct drm_display_mode *mode)
    2099             : {
    2100           0 :         u8 vic = drm_match_cea_mode(mode);
    2101             : 
    2102           0 :         return test_bit(vic, display->hdmi.y420_vdb_modes);
    2103             : }
    2104             : EXPORT_SYMBOL(drm_mode_is_420_only);
    2105             : 
    2106             : /**
    2107             :  * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
    2108             :  * output format also (along with RGB/YCBCR444/422)
    2109             :  *
    2110             :  * @display: display under action.
    2111             :  * @mode: video mode to be tested.
    2112             :  *
    2113             :  * Returns:
    2114             :  * true if the mode can be support YCBCR420 format
    2115             :  * false if not.
    2116             :  */
    2117           0 : bool drm_mode_is_420_also(const struct drm_display_info *display,
    2118             :                           const struct drm_display_mode *mode)
    2119             : {
    2120           0 :         u8 vic = drm_match_cea_mode(mode);
    2121             : 
    2122           0 :         return test_bit(vic, display->hdmi.y420_cmdb_modes);
    2123             : }
    2124             : EXPORT_SYMBOL(drm_mode_is_420_also);
    2125             : /**
    2126             :  * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
    2127             :  * output format
    2128             :  *
    2129             :  * @display: display under action.
    2130             :  * @mode: video mode to be tested.
    2131             :  *
    2132             :  * Returns:
    2133             :  * true if the mode can be supported in YCBCR420 format
    2134             :  * false if not.
    2135             :  */
    2136           0 : bool drm_mode_is_420(const struct drm_display_info *display,
    2137             :                      const struct drm_display_mode *mode)
    2138             : {
    2139           0 :         return drm_mode_is_420_only(display, mode) ||
    2140           0 :                 drm_mode_is_420_also(display, mode);
    2141             : }
    2142             : EXPORT_SYMBOL(drm_mode_is_420);

Generated by: LCOV version 1.14