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