drm_modes.c 59.2 KB
Newer Older
Dave Airlie's avatar
Dave Airlie committed
1
2
3
4
5
/*
 * Copyright © 1997-2003 by The XFree86 Project, Inc.
 * Copyright © 2007 Dave Airlie
 * Copyright © 2007-2008 Intel Corporation
 *   Jesse Barnes <jesse.barnes@intel.com>
6
 * Copyright 2005-2006 Luc Verhaegen
7
 * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
Dave Airlie's avatar
Dave Airlie committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of the copyright holder(s)
 * and author(s) shall not be used in advertising or otherwise to promote
 * the sale, use or other dealings in this Software without prior written
 * authorization from the copyright holder(s) and author(s).
 */

33
#include <linux/ctype.h>
Dave Airlie's avatar
Dave Airlie committed
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
42

#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
43
#include <drm/drm_modes.h>
44
#include <drm/drm_print.h>
Dave Airlie's avatar
Dave Airlie committed
45

46
47
#include "drm_crtc_internal.h"

Dave Airlie's avatar
Dave Airlie committed
48
/**
49
 * drm_mode_debug_printmodeline - print a mode to dmesg
Dave Airlie's avatar
Dave Airlie committed
50
51
52
53
 * @mode: mode to print
 *
 * Describe @mode using DRM_DEBUG.
 */
54
void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
Dave Airlie's avatar
Dave Airlie committed
55
{
56
	DRM_DEBUG_KMS("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
Dave Airlie's avatar
Dave Airlie committed
57
58
59
}
EXPORT_SYMBOL(drm_mode_debug_printmodeline);

60
61
62
63
/**
 * drm_mode_create - create a new display mode
 * @dev: DRM device
 *
64
65
 * Create a new, cleared drm_display_mode with kzalloc, allocate an ID for it
 * and return it.
66
 *
67
 * Returns:
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 * Pointer to new mode on success, NULL on error.
 */
struct drm_display_mode *drm_mode_create(struct drm_device *dev)
{
	struct drm_display_mode *nmode;

	nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
	if (!nmode)
		return NULL;

	return nmode;
}
EXPORT_SYMBOL(drm_mode_create);

/**
 * drm_mode_destroy - remove a mode
 * @dev: DRM device
 * @mode: mode to remove
 *
87
 * Release @mode's unique ID, then free it @mode structure itself using kfree.
88
89
90
91
92
93
94
95
96
97
98
 */
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
{
	if (!mode)
		return;

	kfree(mode);
}
EXPORT_SYMBOL(drm_mode_destroy);

/**
99
 * drm_mode_probed_add - add a mode to a connector's probed_mode list
100
101
102
 * @connector: connector the new mode
 * @mode: mode data
 *
103
104
105
 * Add @mode to @connector's probed_mode list for later use. This list should
 * then in a second step get filtered and all the modes actually supported by
 * the hardware moved to the @connector's modes list.
106
107
108
109
110
111
112
113
114
115
 */
void drm_mode_probed_add(struct drm_connector *connector,
			 struct drm_display_mode *mode)
{
	WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));

	list_add_tail(&mode->head, &connector->probed_modes);
}
EXPORT_SYMBOL(drm_mode_probed_add);

116
/**
117
118
 * drm_cvt_mode -create a modeline based on the CVT algorithm
 * @dev: drm device
119
120
 * @hdisplay: hdisplay size
 * @vdisplay: vdisplay size
121
122
123
124
 * @vrefresh: vrefresh rate
 * @reduced: whether to use reduced blanking
 * @interlaced: whether to compute an interlaced mode
 * @margins: whether to add margins (borders)
125
126
127
128
129
 *
 * This function is called to generate the modeline based on CVT algorithm
 * according to the hdisplay, vdisplay, vrefresh.
 * It is based from the VESA(TM) Coordinated Video Timing Generator by
 * Graham Loveridge April 9, 2003 available at
130
 * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls 
131
132
133
 *
 * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
 * What I have done is to translate it by using integer calculation.
134
135
136
137
138
 *
 * Returns:
 * The modeline based on the CVT algorithm stored in a drm_display_mode object.
 * The display mode object is allocated with drm_mode_create(). Returns NULL
 * when no mode could be allocated.
139
140
141
 */
struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
				      int vdisplay, int vrefresh,
142
				      bool reduced, bool interlaced, bool margins)
143
{
144
#define HV_FACTOR			1000
145
146
147
148
149
150
151
152
153
154
155
156
157
158
	/* 1) top/bottom margin size (% of height) - default: 1.8, */
#define	CVT_MARGIN_PERCENTAGE		18
	/* 2) character cell horizontal granularity (pixels) - default 8 */
#define	CVT_H_GRANULARITY		8
	/* 3) Minimum vertical porch (lines) - default 3 */
#define	CVT_MIN_V_PORCH			3
	/* 4) Minimum number of vertical back porch lines - default 6 */
#define	CVT_MIN_V_BPORCH		6
	/* Pixel Clock step (kHz) */
#define CVT_CLOCK_STEP			250
	struct drm_display_mode *drm_mode;
	unsigned int vfieldrate, hperiod;
	int hdisplay_rnd, hmargin, vdisplay_rnd, vmargin, vsync;
	int interlace;
159
	u64 tmp;
160

161
162
163
	if (!hdisplay || !vdisplay)
		return NULL;

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
	/* allocate the drm_display_mode structure. If failure, we will
	 * return directly
	 */
	drm_mode = drm_mode_create(dev);
	if (!drm_mode)
		return NULL;

	/* the CVT default refresh rate is 60Hz */
	if (!vrefresh)
		vrefresh = 60;

	/* the required field fresh rate */
	if (interlaced)
		vfieldrate = vrefresh * 2;
	else
		vfieldrate = vrefresh;

	/* horizontal pixels */
	hdisplay_rnd = hdisplay - (hdisplay % CVT_H_GRANULARITY);

	/* determine the left&right borders */
	hmargin = 0;
	if (margins) {
		hmargin = hdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;
		hmargin -= hmargin % CVT_H_GRANULARITY;
	}
	/* find the total active pixels */
	drm_mode->hdisplay = hdisplay_rnd + 2 * hmargin;

	/* find the number of lines per field */
	if (interlaced)
		vdisplay_rnd = vdisplay / 2;
	else
		vdisplay_rnd = vdisplay;

	/* find the top & bottom borders */
	vmargin = 0;
	if (margins)
		vmargin = vdisplay_rnd * CVT_MARGIN_PERCENTAGE / 1000;

204
	drm_mode->vdisplay = vdisplay + 2 * vmargin;
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

	/* Interlaced */
	if (interlaced)
		interlace = 1;
	else
		interlace = 0;

	/* Determine VSync Width from aspect ratio */
	if (!(vdisplay % 3) && ((vdisplay * 4 / 3) == hdisplay))
		vsync = 4;
	else if (!(vdisplay % 9) && ((vdisplay * 16 / 9) == hdisplay))
		vsync = 5;
	else if (!(vdisplay % 10) && ((vdisplay * 16 / 10) == hdisplay))
		vsync = 6;
	else if (!(vdisplay % 4) && ((vdisplay * 5 / 4) == hdisplay))
		vsync = 7;
	else if (!(vdisplay % 9) && ((vdisplay * 15 / 9) == hdisplay))
		vsync = 7;
	else /* custom */
		vsync = 10;

	if (!reduced) {
		/* simplify the GTF calculation */
		/* 4) Minimum time of vertical sync + back porch interval (µs)
		 * default 550.0
		 */
		int tmp1, tmp2;
#define CVT_MIN_VSYNC_BP	550
		/* 3) Nominal HSync width (% of line period) - default 8 */
#define CVT_HSYNC_PERCENTAGE	8
		unsigned int hblank_percentage;
		int vsyncandback_porch, vback_porch, hblank;

		/* estimated the horizontal period */
		tmp1 = HV_FACTOR * 1000000  -
				CVT_MIN_VSYNC_BP * HV_FACTOR * vfieldrate;
		tmp2 = (vdisplay_rnd + 2 * vmargin + CVT_MIN_V_PORCH) * 2 +
				interlace;
		hperiod = tmp1 * 2 / (tmp2 * vfieldrate);

		tmp1 = CVT_MIN_VSYNC_BP * HV_FACTOR / hperiod + 1;
		/* 9. Find number of lines in sync + backporch */
		if (tmp1 < (vsync + CVT_MIN_V_PORCH))
			vsyncandback_porch = vsync + CVT_MIN_V_PORCH;
		else
			vsyncandback_porch = tmp1;
		/* 10. Find number of lines in back porch */
		vback_porch = vsyncandback_porch - vsync;
		drm_mode->vtotal = vdisplay_rnd + 2 * vmargin +
				vsyncandback_porch + CVT_MIN_V_PORCH;
		/* 5) Definition of Horizontal blanking time limitation */
		/* Gradient (%/kHz) - default 600 */
#define CVT_M_FACTOR	600
		/* Offset (%) - default 40 */
#define CVT_C_FACTOR	40
		/* Blanking time scaling factor - default 128 */
#define CVT_K_FACTOR	128
		/* Scaling factor weighting - default 20 */
#define CVT_J_FACTOR	20
#define CVT_M_PRIME	(CVT_M_FACTOR * CVT_K_FACTOR / 256)
#define CVT_C_PRIME	((CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
			 CVT_J_FACTOR)
		/* 12. Find ideal blanking duty cycle from formula */
		hblank_percentage = CVT_C_PRIME * HV_FACTOR - CVT_M_PRIME *
					hperiod / 1000;
		/* 13. Blanking time */
		if (hblank_percentage < 20 * HV_FACTOR)
			hblank_percentage = 20 * HV_FACTOR;
		hblank = drm_mode->hdisplay * hblank_percentage /
			 (100 * HV_FACTOR - hblank_percentage);
		hblank -= hblank % (2 * CVT_H_GRANULARITY);
276
		/* 14. find the total pixels per line */
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
		drm_mode->htotal = drm_mode->hdisplay + hblank;
		drm_mode->hsync_end = drm_mode->hdisplay + hblank / 2;
		drm_mode->hsync_start = drm_mode->hsync_end -
			(drm_mode->htotal * CVT_HSYNC_PERCENTAGE) / 100;
		drm_mode->hsync_start += CVT_H_GRANULARITY -
			drm_mode->hsync_start % CVT_H_GRANULARITY;
		/* fill the Vsync values */
		drm_mode->vsync_start = drm_mode->vdisplay + CVT_MIN_V_PORCH;
		drm_mode->vsync_end = drm_mode->vsync_start + vsync;
	} else {
		/* Reduced blanking */
		/* Minimum vertical blanking interval time (µs)- default 460 */
#define CVT_RB_MIN_VBLANK	460
		/* Fixed number of clocks for horizontal sync */
#define CVT_RB_H_SYNC		32
		/* Fixed number of clocks for horizontal blanking */
#define CVT_RB_H_BLANK		160
		/* Fixed number of lines for vertical front porch - default 3*/
#define CVT_RB_VFPORCH		3
		int vbilines;
		int tmp1, tmp2;
		/* 8. Estimate Horizontal period. */
		tmp1 = HV_FACTOR * 1000000 -
			CVT_RB_MIN_VBLANK * HV_FACTOR * vfieldrate;
		tmp2 = vdisplay_rnd + 2 * vmargin;
		hperiod = tmp1 / (tmp2 * vfieldrate);
		/* 9. Find number of lines in vertical blanking */
		vbilines = CVT_RB_MIN_VBLANK * HV_FACTOR / hperiod + 1;
		/* 10. Check if vertical blanking is sufficient */
		if (vbilines < (CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH))
			vbilines = CVT_RB_VFPORCH + vsync + CVT_MIN_V_BPORCH;
		/* 11. Find total number of lines in vertical field */
		drm_mode->vtotal = vdisplay_rnd + 2 * vmargin + vbilines;
		/* 12. Find total number of pixels in a line */
		drm_mode->htotal = drm_mode->hdisplay + CVT_RB_H_BLANK;
		/* Fill in HSync values */
		drm_mode->hsync_end = drm_mode->hdisplay + CVT_RB_H_BLANK / 2;
314
315
316
317
		drm_mode->hsync_start = drm_mode->hsync_end - CVT_RB_H_SYNC;
		/* Fill in VSync values */
		drm_mode->vsync_start = drm_mode->vdisplay + CVT_RB_VFPORCH;
		drm_mode->vsync_end = drm_mode->vsync_start + vsync;
318
319
	}
	/* 15/13. Find pixel clock frequency (kHz for xf86) */
320
321
322
323
324
	tmp = drm_mode->htotal; /* perform intermediate calcs in u64 */
	tmp *= HV_FACTOR * 1000;
	do_div(tmp, hperiod);
	tmp -= drm_mode->clock % CVT_CLOCK_STEP;
	drm_mode->clock = tmp;
325
326
	/* 18/16. Find actual vertical frame frequency */
	/* ignore - just set the mode flag for interlaced */
327
	if (interlaced) {
328
		drm_mode->vtotal *= 2;
329
330
		drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
	}
331
332
333
334
335
336
337
338
339
	/* Fill the mode line name */
	drm_mode_set_name(drm_mode);
	if (reduced)
		drm_mode->flags |= (DRM_MODE_FLAG_PHSYNC |
					DRM_MODE_FLAG_NVSYNC);
	else
		drm_mode->flags |= (DRM_MODE_FLAG_PVSYNC |
					DRM_MODE_FLAG_NHSYNC);

340
	return drm_mode;
341
342
343
}
EXPORT_SYMBOL(drm_cvt_mode);

344
/**
345
346
347
348
349
350
351
 * drm_gtf_mode_complex - create the modeline based on the full GTF algorithm
 * @dev: drm device
 * @hdisplay: hdisplay size
 * @vdisplay: vdisplay size
 * @vrefresh: vrefresh rate.
 * @interlaced: whether to compute an interlaced mode
 * @margins: desired margin (borders) size
352
353
354
355
 * @GTF_M: extended GTF formula parameters
 * @GTF_2C: extended GTF formula parameters
 * @GTF_K: extended GTF formula parameters
 * @GTF_2J: extended GTF formula parameters
356
 *
357
358
 * GTF feature blocks specify C and J in multiples of 0.5, so we pass them
 * in here multiplied by two.  For a C of 40, pass in 80.
359
360
361
362
363
 *
 * Returns:
 * The modeline based on the full GTF algorithm stored in a drm_display_mode object.
 * The display mode object is allocated with drm_mode_create(). Returns NULL
 * when no mode could be allocated.
364
 */
365
366
367
368
369
struct drm_display_mode *
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)
{	/* 1) top/bottom margin size (% of height) - default: 1.8, */
370
371
372
373
374
375
376
377
378
379
380
381
#define	GTF_MARGIN_PERCENTAGE		18
	/* 2) character cell horizontal granularity (pixels) - default 8 */
#define	GTF_CELL_GRAN			8
	/* 3) Minimum vertical porch (lines) - default 3 */
#define	GTF_MIN_V_PORCH			1
	/* width of vsync in lines */
#define V_SYNC_RQD			3
	/* width of hsync as % of total line */
#define H_SYNC_PERCENT			8
	/* min time of vsync + back porch (microsec) */
#define MIN_VSYNC_PLUS_BP		550
	/* C' and M' are part of the Blanking Duty Cycle computation */
382
383
#define GTF_C_PRIME	((((GTF_2C - GTF_2J) * GTF_K / 256) + GTF_2J) / 2)
#define GTF_M_PRIME	(GTF_K * GTF_M / 256)
384
385
386
387
388
389
390
391
392
393
394
395
396
397
	struct drm_display_mode *drm_mode;
	unsigned int hdisplay_rnd, vdisplay_rnd, vfieldrate_rqd;
	int top_margin, bottom_margin;
	int interlace;
	unsigned int hfreq_est;
	int vsync_plus_bp, vback_porch;
	unsigned int vtotal_lines, vfieldrate_est, hperiod;
	unsigned int vfield_rate, vframe_rate;
	int left_margin, right_margin;
	unsigned int total_active_pixels, ideal_duty_cycle;
	unsigned int hblank, total_pixels, pixel_freq;
	int hsync, hfront_porch, vodd_front_porch_lines;
	unsigned int tmp1, tmp2;

398
399
400
	if (!hdisplay || !vdisplay)
		return NULL;

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
	drm_mode = drm_mode_create(dev);
	if (!drm_mode)
		return NULL;

	/* 1. In order to give correct results, the number of horizontal
	 * pixels requested is first processed to ensure that it is divisible
	 * by the character size, by rounding it to the nearest character
	 * cell boundary:
	 */
	hdisplay_rnd = (hdisplay + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
	hdisplay_rnd = hdisplay_rnd * GTF_CELL_GRAN;

	/* 2. If interlace is requested, the number of vertical lines assumed
	 * by the calculation must be halved, as the computation calculates
	 * the number of vertical lines per field.
	 */
	if (interlaced)
		vdisplay_rnd = vdisplay / 2;
	else
		vdisplay_rnd = vdisplay;

	/* 3. Find the frame rate required: */
	if (interlaced)
		vfieldrate_rqd = vrefresh * 2;
	else
		vfieldrate_rqd = vrefresh;

	/* 4. Find number of lines in Top margin: */
	top_margin = 0;
	if (margins)
		top_margin = (vdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
				1000;
	/* 5. Find number of lines in bottom margin: */
	bottom_margin = top_margin;

	/* 6. If interlace is required, then set variable interlace: */
	if (interlaced)
		interlace = 1;
	else
		interlace = 0;

	/* 7. Estimate the Horizontal frequency */
	{
		tmp1 = (1000000  - MIN_VSYNC_PLUS_BP * vfieldrate_rqd) / 500;
		tmp2 = (vdisplay_rnd + 2 * top_margin + GTF_MIN_V_PORCH) *
				2 + interlace;
		hfreq_est = (tmp2 * 1000 * vfieldrate_rqd) / tmp1;
	}

	/* 8. Find the number of lines in V sync + back porch */
	/* [V SYNC+BP] = RINT(([MIN VSYNC+BP] * hfreq_est / 1000000)) */
	vsync_plus_bp = MIN_VSYNC_PLUS_BP * hfreq_est / 1000;
	vsync_plus_bp = (vsync_plus_bp + 500) / 1000;
	/*  9. Find the number of lines in V back porch alone: */
	vback_porch = vsync_plus_bp - V_SYNC_RQD;
	/*  10. Find the total number of lines in Vertical field period: */
	vtotal_lines = vdisplay_rnd + top_margin + bottom_margin +
			vsync_plus_bp + GTF_MIN_V_PORCH;
	/*  11. Estimate the Vertical field frequency: */
	vfieldrate_est = hfreq_est / vtotal_lines;
	/*  12. Find the actual horizontal period: */
	hperiod = 1000000 / (vfieldrate_rqd * vtotal_lines);

	/*  13. Find the actual Vertical field frequency: */
	vfield_rate = hfreq_est / vtotal_lines;
	/*  14. Find the Vertical frame frequency: */
	if (interlaced)
		vframe_rate = vfield_rate / 2;
	else
		vframe_rate = vfield_rate;
	/*  15. Find number of pixels in left margin: */
	if (margins)
		left_margin = (hdisplay_rnd * GTF_MARGIN_PERCENTAGE + 500) /
				1000;
	else
		left_margin = 0;

	/* 16.Find number of pixels in right margin: */
	right_margin = left_margin;
	/* 17.Find total number of active pixels in image and left and right */
	total_active_pixels = hdisplay_rnd + left_margin + right_margin;
	/* 18.Find the ideal blanking duty cycle from blanking duty cycle */
	ideal_duty_cycle = GTF_C_PRIME * 1000 -
				(GTF_M_PRIME * 1000000 / hfreq_est);
	/* 19.Find the number of pixels in the blanking time to the nearest
	 * double character cell: */
	hblank = total_active_pixels * ideal_duty_cycle /
			(100000 - ideal_duty_cycle);
	hblank = (hblank + GTF_CELL_GRAN) / (2 * GTF_CELL_GRAN);
	hblank = hblank * 2 * GTF_CELL_GRAN;
	/* 20.Find total number of pixels: */
	total_pixels = total_active_pixels + hblank;
	/* 21.Find pixel clock frequency: */
	pixel_freq = total_pixels * hfreq_est / 1000;
	/* Stage 1 computations are now complete; I should really pass
	 * the results to another function and do the Stage 2 computations,
	 * but I only need a few more values so I'll just append the
	 * computations here for now */
	/* 17. Find the number of pixels in the horizontal sync period: */
	hsync = H_SYNC_PERCENT * total_pixels / 100;
	hsync = (hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN;
	hsync = hsync * GTF_CELL_GRAN;
	/* 18. Find the number of pixels in horizontal front porch period */
	hfront_porch = hblank / 2 - hsync;
	/*  36. Find the number of lines in the odd front porch period: */
	vodd_front_porch_lines = GTF_MIN_V_PORCH ;

	/* finally, pack the results in the mode struct */
	drm_mode->hdisplay = hdisplay_rnd;
	drm_mode->hsync_start = hdisplay_rnd + hfront_porch;
	drm_mode->hsync_end = drm_mode->hsync_start + hsync;
	drm_mode->htotal = total_pixels;
	drm_mode->vdisplay = vdisplay_rnd;
	drm_mode->vsync_start = vdisplay_rnd + vodd_front_porch_lines;
	drm_mode->vsync_end = drm_mode->vsync_start + V_SYNC_RQD;
	drm_mode->vtotal = vtotal_lines;

	drm_mode->clock = pixel_freq;

	if (interlaced) {
		drm_mode->vtotal *= 2;
		drm_mode->flags |= DRM_MODE_FLAG_INTERLACE;
	}

525
	drm_mode_set_name(drm_mode);
526
527
528
529
	if (GTF_M == 600 && GTF_2C == 80 && GTF_K == 128 && GTF_2J == 40)
		drm_mode->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC;
	else
		drm_mode->flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC;
530

531
532
	return drm_mode;
}
533
534
535
EXPORT_SYMBOL(drm_gtf_mode_complex);

/**
536
537
538
539
540
541
542
 * drm_gtf_mode - create the modeline based on the GTF algorithm
 * @dev: drm device
 * @hdisplay: hdisplay size
 * @vdisplay: vdisplay size
 * @vrefresh: vrefresh rate.
 * @interlaced: whether to compute an interlaced mode
 * @margins: desired margin (borders) size
543
544
545
546
547
 *
 * return the modeline based on GTF algorithm
 *
 * This function is to create the modeline based on the GTF algorithm.
 * Generalized Timing Formula is derived from:
Daniel Vetter's avatar
Daniel Vetter committed
548
 *
549
550
551
552
553
554
555
556
 *	GTF Spreadsheet by Andy Morrish (1/5/97)
 *	available at http://www.vesa.org
 *
 * And it is copied from the file of xserver/hw/xfree86/modes/xf86gtf.c.
 * What I have done is to translate it by using integer calculation.
 * I also refer to the function of fb_get_mode in the file of
 * drivers/video/fbmon.c
 *
557
558
 * Standard GTF parameters::
 *
559
560
561
562
 *     M = 600
 *     C = 40
 *     K = 128
 *     J = 20
563
564
565
566
567
 *
 * Returns:
 * The modeline based on the GTF algorithm stored in a drm_display_mode object.
 * The display mode object is allocated with drm_mode_create(). Returns NULL
 * when no mode could be allocated.
568
569
570
 */
struct drm_display_mode *
drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
571
	     bool interlaced, int margins)
572
{
573
574
575
	return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
				    interlaced, margins,
				    600, 40 * 2, 128, 20 * 2);
576
}
577
EXPORT_SYMBOL(drm_gtf_mode);
578

579
#ifdef CONFIG_VIDEOMODE_HELPERS
580
581
582
583
584
585
586
/**
 * drm_display_mode_from_videomode - fill in @dmode using @vm,
 * @vm: videomode structure to use as source
 * @dmode: drm_display_mode structure to use as destination
 *
 * Fills out @dmode using the display mode specified in @vm.
 */
587
588
void drm_display_mode_from_videomode(const struct videomode *vm,
				     struct drm_display_mode *dmode)
589
590
591
592
593
594
595
596
597
598
599
600
601
602
{
	dmode->hdisplay = vm->hactive;
	dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
	dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
	dmode->htotal = dmode->hsync_end + vm->hback_porch;

	dmode->vdisplay = vm->vactive;
	dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
	dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
	dmode->vtotal = dmode->vsync_end + vm->vback_porch;

	dmode->clock = vm->pixelclock / 1000;

	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
	if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
608
		dmode->flags |= DRM_MODE_FLAG_PVSYNC;
609
	else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
610
		dmode->flags |= DRM_MODE_FLAG_NVSYNC;
611
	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
612
		dmode->flags |= DRM_MODE_FLAG_INTERLACE;
613
	if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
614
		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
615
616
	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
		dmode->flags |= DRM_MODE_FLAG_DBLCLK;
617
618
619
620
	drm_mode_set_name(dmode);
}
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);

621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
/**
 * drm_display_mode_to_videomode - fill in @vm using @dmode,
 * @dmode: drm_display_mode structure to use as source
 * @vm: videomode structure to use as destination
 *
 * Fills out @vm using the display mode specified in @dmode.
 */
void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
				   struct videomode *vm)
{
	vm->hactive = dmode->hdisplay;
	vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
	vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
	vm->hback_porch = dmode->htotal - dmode->hsync_end;

	vm->vactive = dmode->vdisplay;
	vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
	vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
	vm->vback_porch = dmode->vtotal - dmode->vsync_end;

	vm->pixelclock = dmode->clock * 1000;

	vm->flags = 0;
	if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
	else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
	if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
	else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
	if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
		vm->flags |= DISPLAY_FLAGS_INTERLACED;
	if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
		vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
	if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
		vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
}
EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);

661
662
663
664
/**
 * drm_bus_flags_from_videomode - extract information about pixelclk and
 * DE polarity from videomode and store it in a separate variable
 * @vm: videomode structure to use
665
666
 * @bus_flags: information about pixelclk, sync and DE polarity will be stored
 * here
667
 *
668
669
 * Sets DRM_BUS_FLAG_DE_(LOW|HIGH),  DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE
 * and DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
670
 * found in @vm
671
 */
672
673
674
675
void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
{
	*bus_flags = 0;
	if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
676
		*bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
677
	if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
678
		*bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
679

680
	if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
681
		*bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
682
	if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
683
		*bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
684

685
686
687
688
689
690
691
	if (vm->flags & DISPLAY_FLAGS_DE_LOW)
		*bus_flags |= DRM_BUS_FLAG_DE_LOW;
	if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
		*bus_flags |= DRM_BUS_FLAG_DE_HIGH;
}
EXPORT_SYMBOL_GPL(drm_bus_flags_from_videomode);

692
#ifdef CONFIG_OF
693
694
695
696
/**
 * of_get_drm_display_mode - get a drm_display_mode from devicetree
 * @np: device_node with the timing specification
 * @dmode: will be set to the return value
697
 * @bus_flags: information about pixelclk, sync and DE polarity
698
699
700
701
702
 * @index: index into the list of display timings in devicetree
 *
 * This function is expensive and should only be used, if only one mode is to be
 * read from DT. To get multiple modes start with of_get_display_timings and
 * work with that instead.
703
704
705
 *
 * Returns:
 * 0 on success, a negative errno code when no of videomode node was found.
706
707
 */
int of_get_drm_display_mode(struct device_node *np,
708
709
			    struct drm_display_mode *dmode, u32 *bus_flags,
			    int index)
710
711
712
713
714
715
716
717
718
{
	struct videomode vm;
	int ret;

	ret = of_get_videomode(np, &vm, index);
	if (ret)
		return ret;

	drm_display_mode_from_videomode(&vm, dmode);
719
720
	if (bus_flags)
		drm_bus_flags_from_videomode(&vm, bus_flags);
721

722
723
	pr_debug("%pOF: got %dx%d display mode\n",
		np, vm.hactive, vm.vactive);
724
725
726
727
728
	drm_mode_debug_printmodeline(dmode);

	return 0;
}
EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
729
730
#endif /* CONFIG_OF */
#endif /* CONFIG_VIDEOMODE_HELPERS */
731

Dave Airlie's avatar
Dave Airlie committed
732
733
734
735
/**
 * drm_mode_set_name - set the name on a mode
 * @mode: name will be set in this mode
 *
736
737
 * Set the name of @mode to a standard format which is <hdisplay>x<vdisplay>
 * with an optional 'i' suffix for interlaced modes.
Dave Airlie's avatar
Dave Airlie committed
738
739
740
 */
void drm_mode_set_name(struct drm_display_mode *mode)
{
741
742
743
744
745
	bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);

	snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d%s",
		 mode->hdisplay, mode->vdisplay,
		 interlaced ? "i" : "");
Dave Airlie's avatar
Dave Airlie committed
746
747
748
}
EXPORT_SYMBOL(drm_mode_set_name);

749
750
/**
 * drm_mode_hsync - get the hsync of a mode
Adam Jackson's avatar
Adam Jackson committed
751
752
 * @mode: mode
 *
753
754
755
 * Returns:
 * @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the
 * value first if it is not yet set.
Adam Jackson's avatar
Adam Jackson committed
756
 */
757
int drm_mode_hsync(const struct drm_display_mode *mode)
Adam Jackson's avatar
Adam Jackson committed
758
759
760
761
762
763
{
	unsigned int calc_val;

	if (mode->hsync)
		return mode->hsync;

764
	if (mode->htotal <= 0)
Adam Jackson's avatar
Adam Jackson committed
765
766
767
768
769
770
771
772
773
774
		return 0;

	calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
	calc_val += 500;				/* round to 1000Hz */
	calc_val /= 1000;				/* truncate to kHz */

	return calc_val;
}
EXPORT_SYMBOL(drm_mode_hsync);

Dave Airlie's avatar
Dave Airlie committed
775
776
777
778
/**
 * drm_mode_vrefresh - get the vrefresh of a mode
 * @mode: mode
 *
779
780
781
 * Returns:
 * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the
 * value first if it is not yet set.
Dave Airlie's avatar
Dave Airlie committed
782
 */
783
int drm_mode_vrefresh(const struct drm_display_mode *mode)
Dave Airlie's avatar
Dave Airlie committed
784
785
786
787
788
789
{
	int refresh = 0;

	if (mode->vrefresh > 0)
		refresh = mode->vrefresh;
	else if (mode->htotal > 0 && mode->vtotal > 0) {
790
791
792
793
		unsigned int num, den;

		num = mode->clock * 1000;
		den = mode->htotal * mode->vtotal;
Dave Airlie's avatar
Dave Airlie committed
794
795

		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
796
			num *= 2;
Dave Airlie's avatar
Dave Airlie committed
797
		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
798
			den *= 2;
Dave Airlie's avatar
Dave Airlie committed
799
		if (mode->vscan > 1)
800
801
802
			den *= mode->vscan;

		refresh = DIV_ROUND_CLOSEST(num, den);
Dave Airlie's avatar
Dave Airlie committed
803
804
805
806
807
	}
	return refresh;
}
EXPORT_SYMBOL(drm_mode_vrefresh);

808
809
810
811
812
813
814
815
816
817
818
819
/**
 * drm_mode_get_hv_timing - Fetches hdisplay/vdisplay for given mode
 * @mode: mode to query
 * @hdisplay: hdisplay value to fill in
 * @vdisplay: vdisplay value to fill in
 *
 * The vdisplay value will be doubled if the specified mode is a stereo mode of
 * the appropriate layout.
 */
void drm_mode_get_hv_timing(const struct drm_display_mode *mode,
			    int *hdisplay, int *vdisplay)
{
820
	struct drm_display_mode adjusted = *mode;
821
822
823
824
825
826
827

	drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
	*hdisplay = adjusted.crtc_hdisplay;
	*vdisplay = adjusted.crtc_vdisplay;
}
EXPORT_SYMBOL(drm_mode_get_hv_timing);

Dave Airlie's avatar
Dave Airlie committed
828
/**
829
 * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
Dave Airlie's avatar
Dave Airlie committed
830
 * @p: mode
831
 * @adjust_flags: a combination of adjustment flags
Dave Airlie's avatar
Dave Airlie committed
832
 *
833
 * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
834
835
836
837
838
839
 *
 * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
 *   interlaced modes.
 * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
 *   buffers containing two eyes (only adjust the timings when needed, eg. for
 *   "frame packing" or "side by side full").
840
841
 * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
 *   be performed for doublescan and vscan > 1 modes respectively.
Dave Airlie's avatar
Dave Airlie committed
842
843
844
 */
void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
{
845
	if (!p)
Dave Airlie's avatar
Dave Airlie committed
846
847
		return;

848
	p->crtc_clock = p->clock;
Dave Airlie's avatar
Dave Airlie committed
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
	p->crtc_hdisplay = p->hdisplay;
	p->crtc_hsync_start = p->hsync_start;
	p->crtc_hsync_end = p->hsync_end;
	p->crtc_htotal = p->htotal;
	p->crtc_hskew = p->hskew;
	p->crtc_vdisplay = p->vdisplay;
	p->crtc_vsync_start = p->vsync_start;
	p->crtc_vsync_end = p->vsync_end;
	p->crtc_vtotal = p->vtotal;

	if (p->flags & DRM_MODE_FLAG_INTERLACE) {
		if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
			p->crtc_vdisplay /= 2;
			p->crtc_vsync_start /= 2;
			p->crtc_vsync_end /= 2;
			p->crtc_vtotal /= 2;
		}
	}

868
869
870
871
872
873
874
	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
			p->crtc_vdisplay *= 2;
			p->crtc_vsync_start *= 2;
			p->crtc_vsync_end *= 2;
			p->crtc_vtotal *= 2;
		}
Dave Airlie's avatar
Dave Airlie committed
875
876
	}

877
878
879
880
881
882
883
	if (!(adjust_flags & CRTC_NO_VSCAN)) {
		if (p->vscan > 1) {
			p->crtc_vdisplay *= p->vscan;
			p->crtc_vsync_start *= p->vscan;
			p->crtc_vsync_end *= p->vscan;
			p->crtc_vtotal *= p->vscan;
		}
Dave Airlie's avatar
Dave Airlie committed
884
885
	}

886
887
888
889
890
891
892
893
894
895
896
897
898
899
	if (adjust_flags & CRTC_STEREO_DOUBLE) {
		unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;

		switch (layout) {
		case DRM_MODE_FLAG_3D_FRAME_PACKING:
			p->crtc_clock *= 2;
			p->crtc_vdisplay += p->crtc_vtotal;
			p->crtc_vsync_start += p->crtc_vtotal;
			p->crtc_vsync_end += p->crtc_vtotal;
			p->crtc_vtotal += p->crtc_vtotal;
			break;
		}
	}

Dave Airlie's avatar
Dave Airlie committed
900
901
902
903
904
905
906
	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
}
EXPORT_SYMBOL(drm_mode_set_crtcinfo);

Ville Syrjälä's avatar
Ville Syrjälä committed
907
908
909
910
911
/**
 * drm_mode_copy - copy the mode
 * @dst: mode to overwrite
 * @src: mode to copy
 *
912
913
 * Copy an existing mode into another mode, preserving the object id and
 * list head of the destination mode.
Ville Syrjälä's avatar
Ville Syrjälä committed
914
915
916
 */
void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
{
917
	struct list_head head = dst->head;
Ville Syrjälä's avatar
Ville Syrjälä committed
918
919

	*dst = *src;
920
	dst->head = head;
Ville Syrjälä's avatar
Ville Syrjälä committed
921
922
923
}
EXPORT_SYMBOL(drm_mode_copy);

Dave Airlie's avatar
Dave Airlie committed
924
925
/**
 * drm_mode_duplicate - allocate and duplicate an existing mode
926
927
 * @dev: drm_device to allocate the duplicated mode for
 * @mode: mode to duplicate
Dave Airlie's avatar
Dave Airlie committed
928
929
930
 *
 * Just allocate a new mode, copy the existing mode into it, and return
 * a pointer to it.  Used to create new instances of established modes.
931
932
933
 *
 * Returns:
 * Pointer to duplicated mode on success, NULL on error.
Dave Airlie's avatar
Dave Airlie committed
934
935
 */
struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
936
					    const struct drm_display_mode *mode)
Dave Airlie's avatar
Dave Airlie committed
937
938
939
940
941
942
943
{
	struct drm_display_mode *nmode;

	nmode = drm_mode_create(dev);
	if (!nmode)
		return NULL;

Ville Syrjälä's avatar
Ville Syrjälä committed
944
945
	drm_mode_copy(nmode, mode);

Dave Airlie's avatar
Dave Airlie committed
946
947
948
949
	return nmode;
}
EXPORT_SYMBOL(drm_mode_duplicate);

950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
				   const struct drm_display_mode *mode2)
{
	return mode1->hdisplay == mode2->hdisplay &&
		mode1->hsync_start == mode2->hsync_start &&
		mode1->hsync_end == mode2->hsync_end &&
		mode1->htotal == mode2->htotal &&
		mode1->hskew == mode2->hskew &&
		mode1->vdisplay == mode2->vdisplay &&
		mode1->vsync_start == mode2->vsync_start &&
		mode1->vsync_end == mode2->vsync_end &&
		mode1->vtotal == mode2->vtotal &&
		mode1->vscan == mode2->vscan;
}

static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
				  const struct drm_display_mode *mode2)
{
	/*
	 * do clock check convert to PICOS
	 * so fb modes get matched the same
	 */
	if (mode1->clock && mode2->clock)
		return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
	else
		return mode1->clock == mode2->clock;
}

static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
				 const struct drm_display_mode *mode2)
{
	return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
		(mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
}

static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
				    const struct drm_display_mode *mode2)
{
	return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
		(mode2->flags & DRM_MODE_FLAG_3D_MASK);
}

static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
					const struct drm_display_mode *mode2)
{
	return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
}

Dave Airlie's avatar
Dave Airlie committed
998
/**
999
 * drm_mode_match - test modes for (partial) equality
Dave Airlie's avatar
Dave Airlie committed
1000
1001
 * @mode1: first mode
 * @mode2: second mode
1002
 * @match_flags: which parts need to match (DRM_MODE_MATCH_*)
Dave Airlie's avatar
Dave Airlie committed
1003
1004
1005
 *
 * Check to see if @mode1 and @mode2 are equivalent.
 *
1006
 * Returns:
1007
 * True if the modes are (partially) equal, false otherwise.
Dave Airlie's avatar
Dave Airlie committed
1008
 */
1009
1010
1011
bool drm_mode_match(const struct drm_display_mode *mode1,
		    const struct drm_display_mode *mode2,
		    unsigned int match_flags)
Dave Airlie's avatar
Dave Airlie committed
1012
{
1013
1014
1015
1016
1017
1018
	if (!mode1 && !mode2)
		return true;

	if (!mode1 || !mode2)
		return false;

1019
1020
	if (match_flags & DRM_MODE_MATCH_TIMINGS &&
	    !drm_mode_match_timings(mode1, mode2))
Dave Airlie's avatar
Dave Airlie committed
1021
1022
		return false;

1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
	if (match_flags & DRM_MODE_MATCH_CLOCK &&
	    !drm_mode_match_clock(mode1, mode2))
		return false;

	if (match_flags & DRM_MODE_MATCH_FLAGS &&
	    !drm_mode_match_flags(mode1, mode2))
		return false;

	if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
	    !drm_mode_match_3d_flags(mode1, mode2))
		return false;

	if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
	    !drm_mode_match_aspect_ratio(mode1, mode2))
		return false;

	return true;
}
EXPORT_SYMBOL(drm_mode_match);

/**
 * drm_mode_equal - test modes for equality
 * @mode1: first mode
 * @mode2: second mode
 *
 * Check to see if @mode1 and @mode2 are equivalent.
 *
 * Returns:
 * True if the modes are equal, false otherwise.
 */
bool drm_mode_equal(const struct drm_display_mode *mode1,
		    const struct drm_display_mode *mode2)
{
	return drm_mode_match(mode1, mode2,
			      DRM_MODE_MATCH_TIMINGS |
			      DRM_MODE_MATCH_CLOCK |
			      DRM_MODE_MATCH_FLAGS |
1060
1061
			      DRM_MODE_MATCH_3D_FLAGS|
			      DRM_MODE_MATCH_ASPECT_RATIO);
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
}
EXPORT_SYMBOL(drm_mode_equal);

/**
 * drm_mode_equal_no_clocks - test modes for equality
 * @mode1: first mode
 * @mode2: second mode
 *
 * Check to see if @mode1 and @mode2 are equivalent, but
 * don't check the pixel clocks.
 *
 * Returns:
 * True if the modes are equal, false otherwise.
 */
1076
1077
bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1,
			      const struct drm_display_mode *mode2)
1078
{
1079
1080
1081
1082
	return drm_mode_match(mode1, mode2,
			      DRM_MODE_MATCH_TIMINGS |
			      DRM_MODE_MATCH_FLAGS |
			      DRM_MODE_MATCH_3D_FLAGS);
1083
}
1084
EXPORT_SYMBOL(drm_mode_equal_no_clocks);
1085
1086

/**
1087
 * drm_mode_equal_no_clocks_no_stereo - test modes for equality
1088
1089
1090
1091
 * @mode1: first mode
 * @mode2: second mode
 *
 * Check to see if @mode1 and @mode2 are equivalent, but
1092
 * don't check the pixel clocks nor the stereo layout.
1093
 *
1094
 * Returns:
1095
1096
 * True if the modes are equal, false otherwise.
 */
1097
1098
bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
					const struct drm_display_mode *mode2)
1099
{
1100
1101
1102
	return drm_mode_match(mode1, mode2,
			      DRM_MODE_MATCH_TIMINGS |
			      DRM_MODE_MATCH_FLAGS);
Dave Airlie's avatar
Dave Airlie committed
1103
}
1104
EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
Dave Airlie's avatar
Dave Airlie committed
1105

1106
static enum drm_mode_status
1107
1108
drm_mode_validate_basic(const struct drm_display_mode *mode)
{
1109
1110
1111
1112
1113
1114
	if (mode->type & ~DRM_MODE_TYPE_ALL)
		return MODE_BAD;

	if (mode->flags & ~DRM_MODE_FLAG_ALL)
		return MODE_BAD;

1115
1116
1117
	if ((mode->flags & DRM_MODE_FLAG_3D_MASK) > DRM_MODE_FLAG_3D_MAX)
		return MODE_BAD;

1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
	if (mode->clock == 0)
		return MODE_CLOCK_LOW;

	if (mode->hdisplay == 0 ||
	    mode->hsync_start < mode->hdisplay ||
	    mode->hsync_end < mode->hsync_start ||
	    mode->htotal < mode->hsync_end)
		return MODE_H_ILLEGAL;

	if (mode->vdisplay == 0 ||
	    mode->vsync_start < mode->vdisplay ||
	    mode->vsync_end < mode->vsync_start ||
	    mode->vtotal < mode->vsync_end)
		return MODE_V_ILLEGAL;

	return MODE_OK;
}
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163

/**
 * drm_mode_validate_driver - make sure the mode is somewhat sane
 * @dev: drm device
 * @mode: mode to check
 *
 * First do basic validation on the mode, and then allow the driver
 * to check for device/driver specific limitations via the optional
 * &drm_mode_config_helper_funcs.mode_valid hook.
 *
 * Returns:
 * The mode status
 */
enum drm_mode_status
drm_mode_validate_driver(struct drm_device *dev,
			const struct drm_display_mode *mode)
{
	enum drm_mode_status status;

	status = drm_mode_validate_basic(mode);
	if (status != MODE_OK)
		return status;

	if (dev->mode_config.funcs->mode_valid)
		return dev->mode_config.funcs->mode_valid(dev, mode);
	else
		return MODE_OK;
}
EXPORT_SYMBOL(drm_mode_validate_driver);
1164

Dave Airlie's avatar
Dave Airlie committed
1165
1166
/**
 * drm_mode_validate_size - make sure modes adhere to size constraints
1167
 * @mode: mode to check
Dave Airlie's avatar
Dave Airlie committed
1168
1169
1170
 * @maxX: maximum width
 * @maxY: maximum height
 *
1171
1172
 * This function is a helper which can be used to validate modes against size
 * limitations of the DRM device/connector. If a mode is too big its status
1173
 * member is updated with the appropriate validation failure code. The list
1174
 * itself is not changed.
1175
1176
1177
 *
 * Returns:
 * The mode status
Dave Airlie's avatar
Dave Airlie committed
1178
 */
1179
1180
1181
enum drm_mode_status
drm_mode_validate_size(const struct drm_display_mode *mode,
		       int maxX, int maxY)
Dave Airlie's avatar
Dave Airlie committed
1182
{
1183
1184
	if (maxX > 0 && mode->hdisplay > maxX)
		return MODE_VIRTUAL_X;
Dave Airlie's avatar
Dave Airlie committed
1185

1186
1187
	if (maxY > 0 && mode->vdisplay > maxY)
		return MODE_VIRTUAL_Y;
Dave Airlie's avatar
Dave Airlie committed
1188

1189
	return MODE_OK;
Dave Airlie's avatar
Dave Airlie committed
1190
1191
1192
}
EXPORT_SYMBOL(drm_mode_validate_size);

1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
/**
 * drm_mode_validate_ycbcr420 - add 'ycbcr420-only' modes only when allowed
 * @mode: mode to check
 * @connector: drm connector under action
 *
 * This function is a helper which can be used to filter out any YCBCR420
 * only mode, when the source doesn't support it.
 *
 * Returns:
 * The mode status
 */
enum drm_mode_status
drm_mode_validate_ycbcr420(const struct drm_display_mode *mode,
			   struct drm_connector *connector)
{
	u8 vic = drm_match_cea_mode(mode);
	enum drm_mode_status status = MODE_OK;
	struct drm_hdmi_info *hdmi = &connector->display_info.hdmi;

	if (test_bit(vic, hdmi->y420_vdb_modes)) {
		if (!connector->ycbcr_420_allowed)
			status = MODE_NO_420;
	}

	return status;
}
EXPORT_SYMBOL(drm_mode_validate_ycbcr420);

1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
#define MODE_STATUS(status) [MODE_ ## status + 3] = #status

static const char * const drm_mode_status_names[] = {
	MODE_STATUS(OK),
	MODE_STATUS(HSYNC),
	MODE_STATUS(VSYNC),
	MODE_STATUS(H_ILLEGAL),
	MODE_STATUS(V_ILLEGAL),
	MODE_STATUS(BAD_WIDTH),
	MODE_STATUS(NOMODE),
	MODE_STATUS(NO_INTERLACE),
	MODE_STATUS(NO_DBLESCAN),
	MODE_STATUS(NO_VSCAN),
	MODE_STATUS(MEM),
	MODE_STATUS(VIRTUAL_X),
	MODE_STATUS(VIRTUAL_Y),
	MODE_STATUS(MEM_VIRT),
	MODE_STATUS(NOCLOCK),
	MODE_STATUS(CLOCK_HIGH),
	MODE_STATUS(CLOCK_LOW),
	MODE_STATUS(CLOCK_RANGE),
	MODE_STATUS(BAD_HVALUE),
	MODE_STATUS(BAD_VVALUE),
	MODE_STATUS(BAD_VSCAN),
	MODE_STATUS(HSYNC_NARROW),
	MODE_STATUS(HSYNC_WIDE),
	MODE_STATUS(HBLANK_NARROW),
	MODE_STATUS(HBLANK_WIDE),
	MODE_STATUS(VSYNC_NARROW),
	MODE_STATUS(VSYNC_WIDE),
	MODE_STATUS(VBLANK_NARROW),
	MODE_STATUS(VBLANK_WIDE),
	MODE_STATUS(PANEL),
	MODE_STATUS(INTERLACE_WIDTH),
	MODE_STATUS(ONE_WIDTH),
	MODE_STATUS(ONE_HEIGHT),
	MODE_STATUS(ONE_SIZE),
	MODE_STATUS(NO_REDUCED),
	MODE_STATUS(NO_STEREO),
1260
	MODE_STATUS(NO_420),
1261
	MODE_STATUS(STALE),
1262
1263
1264
1265
1266
1267
	MODE_STATUS(BAD),
	MODE_STATUS(ERROR),
};

#undef MODE_STATUS

Ville Syrjälä's avatar
Ville Syrjälä committed
1268
const char *drm_get_mode_status_name(enum drm_mode_status status)
1269
1270
1271
1272
1273
1274
1275
1276
1277
{
	int index = status + 3;

	if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
		return "";

	return drm_mode_status_names[index];
}

Dave Airlie's avatar
Dave Airlie committed
1278
1279
1280
1281
1282
1283
/**
 * drm_mode_prune_invalid - remove invalid modes from mode list
 * @dev: DRM device
 * @mode_list: list of modes to check
 * @verbose: be verbose about it
 *
1284
 * This helper function can be used to prune a display mode list after
1285
 * validation has been completed. All modes whose status is not MODE_OK will be
1286
1287
 * removed from the list, and if @verbose the status code and mode name is also
 * printed to dmesg.
Dave Airlie's avatar
Dave Airlie committed
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
 */
void drm_mode_prune_invalid(struct drm_device *dev,
			    struct list_head *mode_list, bool verbose)
{
	struct drm_display_mode *mode, *t;

	list_for_each_entry_safe(mode, t, mode_list, head) {
		if (mode->status != MODE_OK) {
			list_del(&mode->head);
			if (verbose) {
				drm_mode_debug_printmodeline(mode);
1299
1300
1301
				DRM_DEBUG_KMS("Not using %s mode: %s\n",
					      mode->name,
					      drm_get_mode_status_name(mode->status));
Dave Airlie's avatar
Dave Airlie committed
1302
1303
1304
1305
1306
1307
1308
1309
1310
			}
			drm_mode_destroy(dev, mode);
		}
	}
}
EXPORT_SYMBOL(drm_mode_prune_invalid);

/**
 * drm_mode_compare - compare modes for favorability
1311
 * @priv: unused
Dave Airlie's avatar
Dave Airlie committed
1312
1313
1314
1315
1316
1317
 * @lh_a: list_head for first mode
 * @lh_b: list_head for second mode
 *
 * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
 * which is better.
 *
1318
 * Returns:
Dave Airlie's avatar
Dave Airlie committed
1319
1320
1321
 * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
 * positive if @lh_b is better than @lh_a.
 */
1322
static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head *lh_b)
Dave Airlie's avatar
Dave Airlie committed
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
{
	struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
	struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
	int diff;

	diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
		((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
	if (diff)
		return diff;
	diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
	if (diff)
		return diff;
1335
1336
1337
1338
1339

	diff = b->vrefresh - a->vrefresh;
	if (diff)
		return diff;

Dave Airlie's avatar
Dave Airlie committed
1340
1341
1342
1343
1344
1345
	diff = b->clock - a->clock;
	return diff;
}

/**
 * drm_mode_sort - sort mode list
1346
 * @mode_list: list of drm_display_mode structures to sort
Dave Airlie's avatar
Dave Airlie committed
1347
 *
1348
 * Sort @mode_list by favorability, moving good modes to the head of the list.
Dave Airlie's avatar
Dave Airlie committed
1349
1350
1351
 */
void drm_mode_sort(struct list_head *mode_list)
{
1352
	list_sort(NULL, mode_list, drm_mode_compare);
Dave Airlie's avatar
Dave Airlie committed
1353
1354
1355
1356
}
EXPORT_SYMBOL(drm_mode_sort);

/**
1357
 * drm_connector_list_update - update the mode list for the connector
Dave Airlie's avatar
Dave Airlie committed
1358
1359
1360
1361
 * @connector: the connector to update
 *
 * This moves the modes from the @connector probed_modes list
 * to the actual mode list. It compares the probed mode against the current
1362
1363
1364
1365
 * list and only adds different/new modes.
 *
 * This is just a helper functions doesn't validate any modes itself and also
 * doesn't prune any invalid modes. Callers need to do that themselves.
Dave Airlie's avatar
Dave Airlie committed
1366
 */
1367
void drm_connector_list_update(struct drm_connector *connector)
Dave Airlie's avatar
Dave Airlie committed
1368
1369
1370
{
	struct drm_display_mode *pmode, *pt;

1371
1372
	WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));

1373
1374
1375
1376
	list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
		struct drm_display_mode *mode;
		bool found_it = false;

Dave Airlie's avatar
Dave Airlie committed
1377
1378
		/* go through current modes checking for the new probed mode */
		list_for_each_entry(mode, &connector->modes, head) {
1379
1380
1381
1382
			if (!drm_mode_equal(pmode, mode))
				continue;

			found_it = true;
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399

			/*
			 * If the old matching mode is stale (ie. left over
			 * from a previous probe) just replace it outright.
			 * Otherwise just merge the type bits between all
			 * equal probed modes.
			 *
			 * If two probed modes are considered equal, pick the
			 * actual timings from the one that's marked as
			 * preferred (in case the match isn't 100%). If
			 * multiple or zero preferred modes are present, favor
			 * the mode added to the probed_modes list first.
			 */
			if (mode->status == MODE_STALE) {
				drm_mode_copy(mode, pmode);
			} else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
				   (pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
1400
				pmode->type |= mode->type;
1401
1402
				drm_mode_copy(mode, pmode);
			} else {
1403
				mode->type |= pmode->type;
1404
1405
			}

1406
1407
1408
			list_del(&pmode->head);
			drm_mode_destroy(connector->dev, pmode);
			break;
Dave Airlie's avatar
Dave Airlie committed
1409
1410
1411
1412
1413
1414
1415
		}

		if (!found_it) {
			list_move_tail(&pmode->head, &connector->modes);
		}
	}
}
1416
EXPORT_SYMBOL(drm_connector_list_update);
1417

1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
				      struct drm_cmdline_mode *mode)
{
	unsigned int bpp;

	if (str[0] != '-')
		return -EINVAL;

	str++;
	bpp = simple_strtol(str, end_ptr, 10);
	if (*end_ptr == str)
		return -EINVAL;

	mode->bpp = bpp;
	mode->bpp_specified = true;

	return 0;
}

static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
					  struct drm_cmdline_mode *mode)
{
	unsigned int refresh;

	if (str[0] != '@')
		return -EINVAL;

	str++;
	refresh = simple_strtol(str, end_ptr, 10);
	if (*end_ptr == str)
		return -EINVAL;

	mode->refresh = refresh;
	mode->refresh_specified = true;

	return 0;
}

static int drm_mode_parse_cmdline_extra(const char *str, int length,
1457
					bool freestanding,
1458
					const struct drm_connector *connector,
1459
1460
1461
1462
1463
1464
1465
					struct drm_cmdline_mode *mode)
{
	int i;

	for (i = 0; i < length; i++) {
		switch (str[i]) {
		case 'i':
1466
1467
1468
			if (freestanding)
				return -EINVAL;

1469
1470
1471
			mode->interlace = true;
			break;
		case 'm':
1472
1473
1474
			if (freestanding)
				return -EINVAL;

1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
			mode->margins = true;
			break;
		case 'D':
			if (mode->force != DRM_FORCE_UNSPECIFIED)
				return -EINVAL;

			if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
			    (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
				mode->force = DRM_FORCE_ON;
			else
				mode->force = DRM_FORCE_ON_DIGITAL;
			break;
		case 'd':
			if (mode->force != DRM_FORCE_UNSPECIFIED)
				return -EINVAL;

			mode->force = DRM_FORCE_OFF;
			break;
		case 'e':
			if (mode->force != DRM_FORCE_UNSPECIFIED)
				return -EINVAL;

			mode->force = DRM_FORCE_ON;
			break;
		default:
			return -EINVAL;
		}
	}

	return 0;
}

static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
					   bool extras,
1509
					   const struct drm_connector *connector,
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
					   struct drm_cmdline_mode *mode)
{
	const char *str_start = str;
	bool rb = false, cvt = false;
	int xres = 0, yres = 0;
	int remaining, i;
	char *end_ptr;

	xres = simple_strtol(str, &end_ptr, 10);
	if (end_ptr == str)
		return -EINVAL;

	if (end_ptr[0] != 'x')
		return -EINVAL;
	end_ptr++;

	str = end_ptr;
	yres = simple_strtol(str, &end_ptr, 10);
	if (end_ptr == str)
		return -EINVAL;

	remaining = length - (end_ptr - str_start);
	if (remaining < 0)
		return -EINVAL;

	for (i = 0; i < remaining; i++) {
		switch (end_ptr[i]) {
		case 'M':
			cvt = true;
			break;
		case 'R':
			rb = true;
			break;
		default:
			/*
			 * Try to pass that to our extras parsing
			 * function to handle the case where the
			 * extras are directly after the resolution
			 */
			if (extras) {
				int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
								       1,
1552
								       false,
1553
1554
1555
1556
1557
1558
1559
1560
1561