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