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, °))
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);
|