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