1 /* 2 * Copyright (c) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com> 3 * 4 * DRM core format related functions 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that copyright 9 * notice and this permission notice appear in supporting documentation, and 10 * that the name of the copyright holders not be used in advertising or 11 * publicity pertaining to distribution of the software without specific, 12 * written prior permission. The copyright holders make no representations 13 * about the suitability of this software for any purpose. It is provided "as 14 * is" without express or implied warranty. 15 * 16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 22 * OF THIS SOFTWARE. 23 */ 24 25 #include <linux/bug.h> 26 #include <linux/ctype.h> 27 #include <linux/export.h> 28 #include <linux/kernel.h> 29 30 #include <drm/drmP.h> 31 #include <drm/drm_fourcc.h> 32 33 static char printable_char(int c) 34 { 35 return isascii(c) && isprint(c) ? c : '?'; 36 } 37 38 /** 39 * drm_get_format_name - return a string for drm fourcc format 40 * @format: format to compute name of 41 * 42 * Note that the buffer used by this function is globally shared and owned by 43 * the function itself. 44 * 45 * FIXME: This isn't really multithreading safe. 46 */ 47 const char *drm_get_format_name(uint32_t format) 48 { 49 static char buf[32]; 50 51 snprintf(buf, sizeof(buf), 52 "%c%c%c%c %s-endian (0x%08x)", 53 printable_char(format & 0xff), 54 printable_char((format >> 8) & 0xff), 55 printable_char((format >> 16) & 0xff), 56 printable_char((format >> 24) & 0x7f), 57 format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little", 58 format); 59 60 return buf; 61 } 62 EXPORT_SYMBOL(drm_get_format_name); 63 64 /** 65 * drm_fb_get_bpp_depth - get the bpp/depth values for format 66 * @format: pixel format (DRM_FORMAT_*) 67 * @depth: storage for the depth value 68 * @bpp: storage for the bpp value 69 * 70 * This only supports RGB formats here for compat with code that doesn't use 71 * pixel formats directly yet. 72 */ 73 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, 74 int *bpp) 75 { 76 switch (format) { 77 case DRM_FORMAT_C8: 78 case DRM_FORMAT_RGB332: 79 case DRM_FORMAT_BGR233: 80 *depth = 8; 81 *bpp = 8; 82 break; 83 case DRM_FORMAT_XRGB1555: 84 case DRM_FORMAT_XBGR1555: 85 case DRM_FORMAT_RGBX5551: 86 case DRM_FORMAT_BGRX5551: 87 case DRM_FORMAT_ARGB1555: 88 case DRM_FORMAT_ABGR1555: 89 case DRM_FORMAT_RGBA5551: 90 case DRM_FORMAT_BGRA5551: 91 *depth = 15; 92 *bpp = 16; 93 break; 94 case DRM_FORMAT_RGB565: 95 case DRM_FORMAT_BGR565: 96 *depth = 16; 97 *bpp = 16; 98 break; 99 case DRM_FORMAT_RGB888: 100 case DRM_FORMAT_BGR888: 101 *depth = 24; 102 *bpp = 24; 103 break; 104 case DRM_FORMAT_XRGB8888: 105 case DRM_FORMAT_XBGR8888: 106 case DRM_FORMAT_RGBX8888: 107 case DRM_FORMAT_BGRX8888: 108 *depth = 24; 109 *bpp = 32; 110 break; 111 case DRM_FORMAT_XRGB2101010: 112 case DRM_FORMAT_XBGR2101010: 113 case DRM_FORMAT_RGBX1010102: 114 case DRM_FORMAT_BGRX1010102: 115 case DRM_FORMAT_ARGB2101010: 116 case DRM_FORMAT_ABGR2101010: 117 case DRM_FORMAT_RGBA1010102: 118 case DRM_FORMAT_BGRA1010102: 119 *depth = 30; 120 *bpp = 32; 121 break; 122 case DRM_FORMAT_ARGB8888: 123 case DRM_FORMAT_ABGR8888: 124 case DRM_FORMAT_RGBA8888: 125 case DRM_FORMAT_BGRA8888: 126 *depth = 32; 127 *bpp = 32; 128 break; 129 default: 130 DRM_DEBUG_KMS("unsupported pixel format %s\n", 131 drm_get_format_name(format)); 132 *depth = 0; 133 *bpp = 0; 134 break; 135 } 136 } 137 EXPORT_SYMBOL(drm_fb_get_bpp_depth); 138 139 /** 140 * drm_format_num_planes - get the number of planes for format 141 * @format: pixel format (DRM_FORMAT_*) 142 * 143 * Returns: 144 * The number of planes used by the specified pixel format. 145 */ 146 int drm_format_num_planes(uint32_t format) 147 { 148 switch (format) { 149 case DRM_FORMAT_YUV410: 150 case DRM_FORMAT_YVU410: 151 case DRM_FORMAT_YUV411: 152 case DRM_FORMAT_YVU411: 153 case DRM_FORMAT_YUV420: 154 case DRM_FORMAT_YVU420: 155 case DRM_FORMAT_YUV422: 156 case DRM_FORMAT_YVU422: 157 case DRM_FORMAT_YUV444: 158 case DRM_FORMAT_YVU444: 159 return 3; 160 case DRM_FORMAT_NV12: 161 case DRM_FORMAT_NV21: 162 case DRM_FORMAT_NV16: 163 case DRM_FORMAT_NV61: 164 case DRM_FORMAT_NV24: 165 case DRM_FORMAT_NV42: 166 return 2; 167 default: 168 return 1; 169 } 170 } 171 EXPORT_SYMBOL(drm_format_num_planes); 172 173 /** 174 * drm_format_plane_cpp - determine the bytes per pixel value 175 * @format: pixel format (DRM_FORMAT_*) 176 * @plane: plane index 177 * 178 * Returns: 179 * The bytes per pixel value for the specified plane. 180 */ 181 int drm_format_plane_cpp(uint32_t format, int plane) 182 { 183 unsigned int depth; 184 int bpp; 185 186 if (plane >= drm_format_num_planes(format)) 187 return 0; 188 189 switch (format) { 190 case DRM_FORMAT_YUYV: 191 case DRM_FORMAT_YVYU: 192 case DRM_FORMAT_UYVY: 193 case DRM_FORMAT_VYUY: 194 return 2; 195 case DRM_FORMAT_NV12: 196 case DRM_FORMAT_NV21: 197 case DRM_FORMAT_NV16: 198 case DRM_FORMAT_NV61: 199 case DRM_FORMAT_NV24: 200 case DRM_FORMAT_NV42: 201 return plane ? 2 : 1; 202 case DRM_FORMAT_YUV410: 203 case DRM_FORMAT_YVU410: 204 case DRM_FORMAT_YUV411: 205 case DRM_FORMAT_YVU411: 206 case DRM_FORMAT_YUV420: 207 case DRM_FORMAT_YVU420: 208 case DRM_FORMAT_YUV422: 209 case DRM_FORMAT_YVU422: 210 case DRM_FORMAT_YUV444: 211 case DRM_FORMAT_YVU444: 212 return 1; 213 default: 214 drm_fb_get_bpp_depth(format, &depth, &bpp); 215 return bpp >> 3; 216 } 217 } 218 EXPORT_SYMBOL(drm_format_plane_cpp); 219 220 /** 221 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor 222 * @format: pixel format (DRM_FORMAT_*) 223 * 224 * Returns: 225 * The horizontal chroma subsampling factor for the 226 * specified pixel format. 227 */ 228 int drm_format_horz_chroma_subsampling(uint32_t format) 229 { 230 switch (format) { 231 case DRM_FORMAT_YUV411: 232 case DRM_FORMAT_YVU411: 233 case DRM_FORMAT_YUV410: 234 case DRM_FORMAT_YVU410: 235 return 4; 236 case DRM_FORMAT_YUYV: 237 case DRM_FORMAT_YVYU: 238 case DRM_FORMAT_UYVY: 239 case DRM_FORMAT_VYUY: 240 case DRM_FORMAT_NV12: 241 case DRM_FORMAT_NV21: 242 case DRM_FORMAT_NV16: 243 case DRM_FORMAT_NV61: 244 case DRM_FORMAT_YUV422: 245 case DRM_FORMAT_YVU422: 246 case DRM_FORMAT_YUV420: 247 case DRM_FORMAT_YVU420: 248 return 2; 249 default: 250 return 1; 251 } 252 } 253 EXPORT_SYMBOL(drm_format_horz_chroma_subsampling); 254 255 /** 256 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor 257 * @format: pixel format (DRM_FORMAT_*) 258 * 259 * Returns: 260 * The vertical chroma subsampling factor for the 261 * specified pixel format. 262 */ 263 int drm_format_vert_chroma_subsampling(uint32_t format) 264 { 265 switch (format) { 266 case DRM_FORMAT_YUV410: 267 case DRM_FORMAT_YVU410: 268 return 4; 269 case DRM_FORMAT_YUV420: 270 case DRM_FORMAT_YVU420: 271 case DRM_FORMAT_NV12: 272 case DRM_FORMAT_NV21: 273 return 2; 274 default: 275 return 1; 276 } 277 } 278 EXPORT_SYMBOL(drm_format_vert_chroma_subsampling); 279 280 /** 281 * drm_format_plane_width - width of the plane given the first plane 282 * @width: width of the first plane 283 * @format: pixel format 284 * @plane: plane index 285 * 286 * Returns: 287 * The width of @plane, given that the width of the first plane is @width. 288 */ 289 int drm_format_plane_width(int width, uint32_t format, int plane) 290 { 291 if (plane >= drm_format_num_planes(format)) 292 return 0; 293 294 if (plane == 0) 295 return width; 296 297 return width / drm_format_horz_chroma_subsampling(format); 298 } 299 EXPORT_SYMBOL(drm_format_plane_width); 300 301 /** 302 * drm_format_plane_height - height of the plane given the first plane 303 * @height: height of the first plane 304 * @format: pixel format 305 * @plane: plane index 306 * 307 * Returns: 308 * The height of @plane, given that the height of the first plane is @height. 309 */ 310 int drm_format_plane_height(int height, uint32_t format, int plane) 311 { 312 if (plane >= drm_format_num_planes(format)) 313 return 0; 314 315 if (plane == 0) 316 return height; 317 318 return height / drm_format_vert_chroma_subsampling(format); 319 } 320 EXPORT_SYMBOL(drm_format_plane_height); 321