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