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