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_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 */ 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 */ 79 void drm_mode_destroy(struct drm_display_mode *mode) 80 { 81 if (!mode) 82 return; 83 84 kfree(mode); 85 } 86 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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