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