xref: /rk3399_rockchip-uboot/drivers/video/drm/drm_modes.c (revision a265befef37b147d4bcf05fc84500fe072a3f33f)
1e022625eSWyon Bi // SPDX-License-Identifier: GPL-2.0+
2e022625eSWyon Bi /*
3e022625eSWyon Bi  * Copyright © 1997-2003 by The XFree86 Project, Inc.
4e022625eSWyon Bi  * Copyright © 2007 Dave Airlie
5e022625eSWyon Bi  * Copyright © 2007-2008 Intel Corporation
6e022625eSWyon Bi  *   Jesse Barnes <jesse.barnes@intel.com>
7e022625eSWyon Bi  * Copyright 2005-2006 Luc Verhaegen
8e022625eSWyon Bi  * Copyright (c) 2001, Andy Ritger  aritger@nvidia.com
9e022625eSWyon Bi  *
10e022625eSWyon Bi  * Permission is hereby granted, free of charge, to any person obtaining a
11e022625eSWyon Bi  * copy of this software and associated documentation files (the "Software"),
12e022625eSWyon Bi  * to deal in the Software without restriction, including without limitation
13e022625eSWyon Bi  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14e022625eSWyon Bi  * and/or sell copies of the Software, and to permit persons to whom the
15e022625eSWyon Bi  * Software is furnished to do so, subject to the following conditions:
16e022625eSWyon Bi  *
17e022625eSWyon Bi  * The above copyright notice and this permission notice shall be included in
18e022625eSWyon Bi  * all copies or substantial portions of the Software.
19e022625eSWyon Bi  *
20e022625eSWyon Bi  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21e022625eSWyon Bi  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22e022625eSWyon Bi  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23e022625eSWyon Bi  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
24e022625eSWyon Bi  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25e022625eSWyon Bi  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26e022625eSWyon Bi  * OTHER DEALINGS IN THE SOFTWARE.
27e022625eSWyon Bi  *
28e022625eSWyon Bi  * Except as contained in this notice, the name of the copyright holder(s)
29e022625eSWyon Bi  * and author(s) shall not be used in advertising or otherwise to promote
30e022625eSWyon Bi  * the sale, use or other dealings in this Software without prior written
31e022625eSWyon Bi  * authorization from the copyright holder(s) and author(s).
32e022625eSWyon Bi  */
33e022625eSWyon Bi 
34e022625eSWyon Bi #include <common.h>
35e022625eSWyon Bi #include <drm_modes.h>
36e022625eSWyon Bi #include <linux/compat.h>
37e022625eSWyon Bi #include <malloc.h>
38e022625eSWyon Bi 
39e022625eSWyon Bi #define PICOS2KHZ(a)	(1000000000UL / (a))
40e022625eSWyon Bi #define KHZ2PICOS(a)	(1000000000UL / (a))
41e022625eSWyon Bi 
42e022625eSWyon Bi /**
43e022625eSWyon Bi  * drm_mode_create - create a new display mode
44e022625eSWyon Bi  *
45e022625eSWyon Bi  * Create a new, cleared drm_display_mode.
46e022625eSWyon Bi  *
47e022625eSWyon Bi  * Returns:
48e022625eSWyon Bi  * Pointer to new mode on success, NULL on error.
49e022625eSWyon Bi  */
drm_mode_create(void)50e022625eSWyon Bi struct drm_display_mode *drm_mode_create(void)
51e022625eSWyon Bi {
52e022625eSWyon Bi 	struct drm_display_mode *nmode;
53e022625eSWyon Bi 
54e022625eSWyon Bi 	nmode = malloc(sizeof(struct drm_display_mode));
55e022625eSWyon Bi 	memset(nmode, 0, sizeof(struct drm_display_mode));
56e022625eSWyon Bi 	if (!nmode)
57e022625eSWyon Bi 		return NULL;
58e022625eSWyon Bi 
59e022625eSWyon Bi 	return nmode;
60e022625eSWyon Bi }
61e022625eSWyon Bi 
62e022625eSWyon Bi /**
63*a265befeSGuochun Huang  * drm_mode_copy - copy the mode
64*a265befeSGuochun Huang  * @dst: mode to overwrite
65*a265befeSGuochun Huang  * @src: mode to copy
66*a265befeSGuochun Huang  *
67*a265befeSGuochun Huang  * Copy an existing mode into another mode, preserving the object id and
68*a265befeSGuochun Huang  * list head of the destination mode.
69*a265befeSGuochun Huang  */
drm_mode_copy(struct drm_display_mode * dst,const struct drm_display_mode * src)70*a265befeSGuochun Huang void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
71*a265befeSGuochun Huang {
72*a265befeSGuochun Huang 	*dst = *src;
73*a265befeSGuochun Huang }
74*a265befeSGuochun Huang 
75*a265befeSGuochun Huang /**
76e022625eSWyon Bi  * drm_mode_destroy - remove a mode
77e022625eSWyon Bi  * @mode: mode to remove
78e022625eSWyon Bi  */
drm_mode_destroy(struct drm_display_mode * mode)79e022625eSWyon Bi void drm_mode_destroy(struct drm_display_mode *mode)
80e022625eSWyon Bi {
81e022625eSWyon Bi 	if (!mode)
82e022625eSWyon Bi 		return;
83e022625eSWyon Bi 
84e022625eSWyon Bi 	kfree(mode);
85e022625eSWyon Bi }
86e022625eSWyon Bi 
drm_mode_match_timings(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)87e022625eSWyon Bi static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
88e022625eSWyon Bi 				   const struct drm_display_mode *mode2)
89e022625eSWyon Bi {
90e022625eSWyon Bi 	return mode1->hdisplay == mode2->hdisplay &&
91e022625eSWyon Bi 	       mode1->hsync_start == mode2->hsync_start &&
92e022625eSWyon Bi 	       mode1->hsync_end == mode2->hsync_end &&
93e022625eSWyon Bi 	       mode1->htotal == mode2->htotal &&
94e022625eSWyon Bi 	       mode1->hskew == mode2->hskew &&
95e022625eSWyon Bi 	       mode1->vdisplay == mode2->vdisplay &&
96e022625eSWyon Bi 	       mode1->vsync_start == mode2->vsync_start &&
97e022625eSWyon Bi 	       mode1->vsync_end == mode2->vsync_end &&
98e022625eSWyon Bi 	       mode1->vtotal == mode2->vtotal &&
99e022625eSWyon Bi 	       mode1->vscan == mode2->vscan;
100e022625eSWyon Bi }
101e022625eSWyon Bi 
drm_mode_match_clock(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)102e022625eSWyon Bi static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
103e022625eSWyon Bi 				 const struct drm_display_mode *mode2)
104e022625eSWyon Bi {
105e022625eSWyon Bi 	/*
106e022625eSWyon Bi 	 * do clock check convert to PICOS
107e022625eSWyon Bi 	 * so fb modes get matched the same
108e022625eSWyon Bi 	 */
109e022625eSWyon Bi 	if (mode1->clock && mode2->clock)
110e022625eSWyon Bi 		return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
111e022625eSWyon Bi 	else
112e022625eSWyon Bi 		return mode1->clock == mode2->clock;
113e022625eSWyon Bi }
114e022625eSWyon Bi 
drm_mode_match_flags(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)115e022625eSWyon Bi static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
116e022625eSWyon Bi 				 const struct drm_display_mode *mode2)
117e022625eSWyon Bi {
118e022625eSWyon Bi 	return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
119e022625eSWyon Bi 	       (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
120e022625eSWyon Bi }
121e022625eSWyon Bi 
drm_mode_match_3d_flags(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)122e022625eSWyon Bi static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
123e022625eSWyon Bi 				    const struct drm_display_mode *mode2)
124e022625eSWyon Bi {
125e022625eSWyon Bi 	return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
126e022625eSWyon Bi 	       (mode2->flags & DRM_MODE_FLAG_3D_MASK);
127e022625eSWyon Bi }
128e022625eSWyon Bi 
drm_mode_match_aspect_ratio(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)129e022625eSWyon Bi static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
130e022625eSWyon Bi 					const struct drm_display_mode *mode2)
131e022625eSWyon Bi {
132e022625eSWyon Bi 	return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
133e022625eSWyon Bi }
134e022625eSWyon Bi 
135e022625eSWyon Bi /**
136e022625eSWyon Bi  * drm_mode_match - test modes for (partial) equality
137e022625eSWyon Bi  * @mode1: first mode
138e022625eSWyon Bi  * @mode2: second mode
139e022625eSWyon Bi  * @match_flags: which parts need to match (DRM_MODE_MATCH_*)
140e022625eSWyon Bi  *
141e022625eSWyon Bi  * Check to see if @mode1 and @mode2 are equivalent.
142e022625eSWyon Bi  *
143e022625eSWyon Bi  * Returns:
144e022625eSWyon Bi  * True if the modes are (partially) equal, false otherwise.
145e022625eSWyon Bi  */
drm_mode_match(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2,unsigned int match_flags)146e022625eSWyon Bi bool drm_mode_match(const struct drm_display_mode *mode1,
147e022625eSWyon Bi 		    const struct drm_display_mode *mode2,
148e022625eSWyon Bi 		    unsigned int match_flags)
149e022625eSWyon Bi {
150e022625eSWyon Bi 	if (!mode1 && !mode2)
151e022625eSWyon Bi 		return true;
152e022625eSWyon Bi 
153e022625eSWyon Bi 	if (!mode1 || !mode2)
154e022625eSWyon Bi 		return false;
155e022625eSWyon Bi 
156e022625eSWyon Bi 	if (match_flags & DRM_MODE_MATCH_TIMINGS &&
157e022625eSWyon Bi 	    !drm_mode_match_timings(mode1, mode2))
158e022625eSWyon Bi 		return false;
159e022625eSWyon Bi 
160e022625eSWyon Bi 	if (match_flags & DRM_MODE_MATCH_CLOCK &&
161e022625eSWyon Bi 	    !drm_mode_match_clock(mode1, mode2))
162e022625eSWyon Bi 		return false;
163e022625eSWyon Bi 
164e022625eSWyon Bi 	if (match_flags & DRM_MODE_MATCH_FLAGS &&
165e022625eSWyon Bi 	    !drm_mode_match_flags(mode1, mode2))
166e022625eSWyon Bi 		return false;
167e022625eSWyon Bi 
168e022625eSWyon Bi 	if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
169e022625eSWyon Bi 	    !drm_mode_match_3d_flags(mode1, mode2))
170e022625eSWyon Bi 		return false;
171e022625eSWyon Bi 
172e022625eSWyon Bi 	if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
173e022625eSWyon Bi 	    !drm_mode_match_aspect_ratio(mode1, mode2))
174e022625eSWyon Bi 		return false;
175e022625eSWyon Bi 
176e022625eSWyon Bi 	return true;
177e022625eSWyon Bi }
178e022625eSWyon Bi 
179e022625eSWyon Bi /**
180e022625eSWyon Bi  * drm_mode_equal - test modes for equality
181e022625eSWyon Bi  * @mode1: first mode
182e022625eSWyon Bi  * @mode2: second mode
183e022625eSWyon Bi  *
184e022625eSWyon Bi  * Check to see if @mode1 and @mode2 are equivalent.
185e022625eSWyon Bi  *
186e022625eSWyon Bi  * Returns:
187e022625eSWyon Bi  * True if the modes are equal, false otherwise.
188e022625eSWyon Bi  */
drm_mode_equal(const struct drm_display_mode * mode1,const struct drm_display_mode * mode2)189e022625eSWyon Bi bool drm_mode_equal(const struct drm_display_mode *mode1,
190e022625eSWyon Bi 		    const struct drm_display_mode *mode2)
191e022625eSWyon Bi {
192e022625eSWyon Bi 	return drm_mode_match(mode1, mode2,
193e022625eSWyon Bi 			      DRM_MODE_MATCH_TIMINGS |
194e022625eSWyon Bi 			      DRM_MODE_MATCH_CLOCK |
195e022625eSWyon Bi 			      DRM_MODE_MATCH_FLAGS |
196e022625eSWyon Bi 			      DRM_MODE_MATCH_3D_FLAGS |
197e022625eSWyon Bi 			      DRM_MODE_MATCH_ASPECT_RATIO);
198e022625eSWyon Bi }
1992cb51333SDamon Ding 
2002cb51333SDamon Ding /**
201*a265befeSGuochun Huang  * drm_display_mode_from_videomode - fill in @dmode using @vm,
202*a265befeSGuochun Huang  * @vm: videomode structure to use as source
203*a265befeSGuochun Huang  * @dmode: drm_display_mode structure to use as destination
204*a265befeSGuochun Huang  *
205*a265befeSGuochun Huang  * Fills out @dmode using the display mode specified in @vm.
206*a265befeSGuochun Huang  */
drm_display_mode_from_videomode(const struct videomode * vm,struct drm_display_mode * dmode)207*a265befeSGuochun Huang void drm_display_mode_from_videomode(const struct videomode *vm,
208*a265befeSGuochun Huang 				     struct drm_display_mode *dmode)
209*a265befeSGuochun Huang {
210*a265befeSGuochun Huang 	dmode->hdisplay = vm->hactive;
211*a265befeSGuochun Huang 	dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
212*a265befeSGuochun Huang 	dmode->hsync_end = dmode->hsync_start + vm->hsync_len;
213*a265befeSGuochun Huang 	dmode->htotal = dmode->hsync_end + vm->hback_porch;
214*a265befeSGuochun Huang 
215*a265befeSGuochun Huang 	dmode->vdisplay = vm->vactive;
216*a265befeSGuochun Huang 	dmode->vsync_start = dmode->vdisplay + vm->vfront_porch;
217*a265befeSGuochun Huang 	dmode->vsync_end = dmode->vsync_start + vm->vsync_len;
218*a265befeSGuochun Huang 	dmode->vtotal = dmode->vsync_end + vm->vback_porch;
219*a265befeSGuochun Huang 
220*a265befeSGuochun Huang 	dmode->clock = vm->pixelclock / 1000;
221*a265befeSGuochun Huang 
222*a265befeSGuochun Huang 	dmode->flags = 0;
223*a265befeSGuochun Huang 	if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
224*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_PHSYNC;
225*a265befeSGuochun Huang 	else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
226*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_NHSYNC;
227*a265befeSGuochun Huang 	if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
228*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_PVSYNC;
229*a265befeSGuochun Huang 	else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
230*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_NVSYNC;
231*a265befeSGuochun Huang 	if (vm->flags & DISPLAY_FLAGS_INTERLACED)
232*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_INTERLACE;
233*a265befeSGuochun Huang 	if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
234*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
235*a265befeSGuochun Huang 	if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
236*a265befeSGuochun Huang 		dmode->flags |= DRM_MODE_FLAG_DBLCLK;
237*a265befeSGuochun Huang }
238*a265befeSGuochun Huang 
239*a265befeSGuochun Huang /**
2402cb51333SDamon Ding  * drm_display_mode_to_videomode - fill in @vm using @dmode,
2412cb51333SDamon Ding  * @dmode: drm_display_mode structure to use as source
2422cb51333SDamon Ding  * @vm: videomode structure to use as destination
2432cb51333SDamon Ding  *
2442cb51333SDamon Ding  * Fills out @vm using the display mode specified in @dmode.
2452cb51333SDamon Ding  */
drm_display_mode_to_videomode(const struct drm_display_mode * dmode,struct videomode * vm)2462cb51333SDamon Ding void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
2472cb51333SDamon Ding 				   struct videomode *vm)
2482cb51333SDamon Ding {
2492cb51333SDamon Ding 	vm->hactive = dmode->hdisplay;
2502cb51333SDamon Ding 	vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
2512cb51333SDamon Ding 	vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
2522cb51333SDamon Ding 	vm->hback_porch = dmode->htotal - dmode->hsync_end;
2532cb51333SDamon Ding 
2542cb51333SDamon Ding 	vm->vactive = dmode->vdisplay;
2552cb51333SDamon Ding 	vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
2562cb51333SDamon Ding 	vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
2572cb51333SDamon Ding 	vm->vback_porch = dmode->vtotal - dmode->vsync_end;
2582cb51333SDamon Ding 
2592cb51333SDamon Ding 	vm->pixelclock = dmode->clock * 1000;
2602cb51333SDamon Ding 
2612cb51333SDamon Ding 	vm->flags = 0;
2622cb51333SDamon Ding 	if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
2632cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
2642cb51333SDamon Ding 	else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
2652cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
2662cb51333SDamon Ding 	if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
2672cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
2682cb51333SDamon Ding 	else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
2692cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
2702cb51333SDamon Ding 	if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
2712cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_INTERLACED;
2722cb51333SDamon Ding 	if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
2732cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
2742cb51333SDamon Ding 	if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
2752cb51333SDamon Ding 		vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
2762cb51333SDamon Ding }
277