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