xref: /rk3399_rockchip-uboot/drivers/video/drm/drm_modes.c (revision 2bcebb1a79550117e5474bb586bdc094e4fe0576)
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  */
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_destroy - remove a mode
64  * @mode: mode to remove
65  */
66 void drm_mode_destroy(struct drm_display_mode *mode)
67 {
68 	if (!mode)
69 		return;
70 
71 	kfree(mode);
72 }
73 
74 static bool drm_mode_match_timings(const struct drm_display_mode *mode1,
75 				   const struct drm_display_mode *mode2)
76 {
77 	return mode1->hdisplay == mode2->hdisplay &&
78 	       mode1->hsync_start == mode2->hsync_start &&
79 	       mode1->hsync_end == mode2->hsync_end &&
80 	       mode1->htotal == mode2->htotal &&
81 	       mode1->hskew == mode2->hskew &&
82 	       mode1->vdisplay == mode2->vdisplay &&
83 	       mode1->vsync_start == mode2->vsync_start &&
84 	       mode1->vsync_end == mode2->vsync_end &&
85 	       mode1->vtotal == mode2->vtotal &&
86 	       mode1->vscan == mode2->vscan;
87 }
88 
89 static bool drm_mode_match_clock(const struct drm_display_mode *mode1,
90 				 const struct drm_display_mode *mode2)
91 {
92 	/*
93 	 * do clock check convert to PICOS
94 	 * so fb modes get matched the same
95 	 */
96 	if (mode1->clock && mode2->clock)
97 		return KHZ2PICOS(mode1->clock) == KHZ2PICOS(mode2->clock);
98 	else
99 		return mode1->clock == mode2->clock;
100 }
101 
102 static bool drm_mode_match_flags(const struct drm_display_mode *mode1,
103 				 const struct drm_display_mode *mode2)
104 {
105 	return (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) ==
106 	       (mode2->flags & ~DRM_MODE_FLAG_3D_MASK);
107 }
108 
109 static bool drm_mode_match_3d_flags(const struct drm_display_mode *mode1,
110 				    const struct drm_display_mode *mode2)
111 {
112 	return (mode1->flags & DRM_MODE_FLAG_3D_MASK) ==
113 	       (mode2->flags & DRM_MODE_FLAG_3D_MASK);
114 }
115 
116 static bool drm_mode_match_aspect_ratio(const struct drm_display_mode *mode1,
117 					const struct drm_display_mode *mode2)
118 {
119 	return mode1->picture_aspect_ratio == mode2->picture_aspect_ratio;
120 }
121 
122 /**
123  * drm_mode_match - test modes for (partial) equality
124  * @mode1: first mode
125  * @mode2: second mode
126  * @match_flags: which parts need to match (DRM_MODE_MATCH_*)
127  *
128  * Check to see if @mode1 and @mode2 are equivalent.
129  *
130  * Returns:
131  * True if the modes are (partially) equal, false otherwise.
132  */
133 bool drm_mode_match(const struct drm_display_mode *mode1,
134 		    const struct drm_display_mode *mode2,
135 		    unsigned int match_flags)
136 {
137 	if (!mode1 && !mode2)
138 		return true;
139 
140 	if (!mode1 || !mode2)
141 		return false;
142 
143 	if (match_flags & DRM_MODE_MATCH_TIMINGS &&
144 	    !drm_mode_match_timings(mode1, mode2))
145 		return false;
146 
147 	if (match_flags & DRM_MODE_MATCH_CLOCK &&
148 	    !drm_mode_match_clock(mode1, mode2))
149 		return false;
150 
151 	if (match_flags & DRM_MODE_MATCH_FLAGS &&
152 	    !drm_mode_match_flags(mode1, mode2))
153 		return false;
154 
155 	if (match_flags & DRM_MODE_MATCH_3D_FLAGS &&
156 	    !drm_mode_match_3d_flags(mode1, mode2))
157 		return false;
158 
159 	if (match_flags & DRM_MODE_MATCH_ASPECT_RATIO &&
160 	    !drm_mode_match_aspect_ratio(mode1, mode2))
161 		return false;
162 
163 	return true;
164 }
165 
166 /**
167  * drm_mode_equal - test modes for equality
168  * @mode1: first mode
169  * @mode2: second mode
170  *
171  * Check to see if @mode1 and @mode2 are equivalent.
172  *
173  * Returns:
174  * True if the modes are equal, false otherwise.
175  */
176 bool drm_mode_equal(const struct drm_display_mode *mode1,
177 		    const struct drm_display_mode *mode2)
178 {
179 	return drm_mode_match(mode1, mode2,
180 			      DRM_MODE_MATCH_TIMINGS |
181 			      DRM_MODE_MATCH_CLOCK |
182 			      DRM_MODE_MATCH_FLAGS |
183 			      DRM_MODE_MATCH_3D_FLAGS |
184 			      DRM_MODE_MATCH_ASPECT_RATIO);
185 }
186 
187 /**
188  * drm_display_mode_to_videomode - fill in @vm using @dmode,
189  * @dmode: drm_display_mode structure to use as source
190  * @vm: videomode structure to use as destination
191  *
192  * Fills out @vm using the display mode specified in @dmode.
193  */
194 void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
195 				   struct videomode *vm)
196 {
197 	vm->hactive = dmode->hdisplay;
198 	vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
199 	vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
200 	vm->hback_porch = dmode->htotal - dmode->hsync_end;
201 
202 	vm->vactive = dmode->vdisplay;
203 	vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
204 	vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
205 	vm->vback_porch = dmode->vtotal - dmode->vsync_end;
206 
207 	vm->pixelclock = dmode->clock * 1000;
208 
209 	vm->flags = 0;
210 	if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
211 		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
212 	else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
213 		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
214 	if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
215 		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
216 	else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
217 		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
218 	if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
219 		vm->flags |= DISPLAY_FLAGS_INTERLACED;
220 	if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
221 		vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
222 	if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
223 		vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
224 }
225