linux/drivers/gpu/drm/drm_fourcc.c
<<
>>
Prefs
   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
  33static char printable_char(int c)
  34{
  35        return isascii(c) && isprint(c) ? c : '?';
  36}
  37
  38/**
  39 * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
  40 * @bpp: bits per pixels
  41 * @depth: bit depth per pixel
  42 *
  43 * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
  44 * Useful in fbdev emulation code, since that deals in those values.
  45 */
  46uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
  47{
  48        uint32_t fmt;
  49
  50        switch (bpp) {
  51        case 8:
  52                fmt = DRM_FORMAT_C8;
  53                break;
  54        case 16:
  55                if (depth == 15)
  56                        fmt = DRM_FORMAT_XRGB1555;
  57                else
  58                        fmt = DRM_FORMAT_RGB565;
  59                break;
  60        case 24:
  61                fmt = DRM_FORMAT_RGB888;
  62                break;
  63        case 32:
  64                if (depth == 24)
  65                        fmt = DRM_FORMAT_XRGB8888;
  66                else if (depth == 30)
  67                        fmt = DRM_FORMAT_XRGB2101010;
  68                else
  69                        fmt = DRM_FORMAT_ARGB8888;
  70                break;
  71        default:
  72                DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
  73                fmt = DRM_FORMAT_XRGB8888;
  74                break;
  75        }
  76
  77        return fmt;
  78}
  79EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  80
  81/**
  82 * drm_get_format_name - return a string for drm fourcc format
  83 * @format: format to compute name of
  84 *
  85 * Note that the buffer returned by this function is owned by the caller
  86 * and will need to be freed using kfree().
  87 */
  88char *drm_get_format_name(uint32_t format)
  89{
  90        char *buf = kmalloc(32, GFP_KERNEL);
  91
  92        snprintf(buf, 32,
  93                 "%c%c%c%c %s-endian (0x%08x)",
  94                 printable_char(format & 0xff),
  95                 printable_char((format >> 8) & 0xff),
  96                 printable_char((format >> 16) & 0xff),
  97                 printable_char((format >> 24) & 0x7f),
  98                 format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
  99                 format);
 100
 101        return buf;
 102}
 103EXPORT_SYMBOL(drm_get_format_name);
 104
 105/**
 106 * drm_fb_get_bpp_depth - get the bpp/depth values for format
 107 * @format: pixel format (DRM_FORMAT_*)
 108 * @depth: storage for the depth value
 109 * @bpp: storage for the bpp value
 110 *
 111 * This only supports RGB formats here for compat with code that doesn't use
 112 * pixel formats directly yet.
 113 */
 114void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
 115                          int *bpp)
 116{
 117        char *format_name;
 118
 119        switch (format) {
 120        case DRM_FORMAT_C8:
 121        case DRM_FORMAT_RGB332:
 122        case DRM_FORMAT_BGR233:
 123                *depth = 8;
 124                *bpp = 8;
 125                break;
 126        case DRM_FORMAT_XRGB1555:
 127        case DRM_FORMAT_XBGR1555:
 128        case DRM_FORMAT_RGBX5551:
 129        case DRM_FORMAT_BGRX5551:
 130        case DRM_FORMAT_ARGB1555:
 131        case DRM_FORMAT_ABGR1555:
 132        case DRM_FORMAT_RGBA5551:
 133        case DRM_FORMAT_BGRA5551:
 134                *depth = 15;
 135                *bpp = 16;
 136                break;
 137        case DRM_FORMAT_RGB565:
 138        case DRM_FORMAT_BGR565:
 139                *depth = 16;
 140                *bpp = 16;
 141                break;
 142        case DRM_FORMAT_RGB888:
 143        case DRM_FORMAT_BGR888:
 144                *depth = 24;
 145                *bpp = 24;
 146                break;
 147        case DRM_FORMAT_XRGB8888:
 148        case DRM_FORMAT_XBGR8888:
 149        case DRM_FORMAT_RGBX8888:
 150        case DRM_FORMAT_BGRX8888:
 151                *depth = 24;
 152                *bpp = 32;
 153                break;
 154        case DRM_FORMAT_XRGB2101010:
 155        case DRM_FORMAT_XBGR2101010:
 156        case DRM_FORMAT_RGBX1010102:
 157        case DRM_FORMAT_BGRX1010102:
 158        case DRM_FORMAT_ARGB2101010:
 159        case DRM_FORMAT_ABGR2101010:
 160        case DRM_FORMAT_RGBA1010102:
 161        case DRM_FORMAT_BGRA1010102:
 162                *depth = 30;
 163                *bpp = 32;
 164                break;
 165        case DRM_FORMAT_ARGB8888:
 166        case DRM_FORMAT_ABGR8888:
 167        case DRM_FORMAT_RGBA8888:
 168        case DRM_FORMAT_BGRA8888:
 169                *depth = 32;
 170                *bpp = 32;
 171                break;
 172        default:
 173                format_name = drm_get_format_name(format);
 174                DRM_DEBUG_KMS("unsupported pixel format %s\n", format_name);
 175                kfree(format_name);
 176                *depth = 0;
 177                *bpp = 0;
 178                break;
 179        }
 180}
 181EXPORT_SYMBOL(drm_fb_get_bpp_depth);
 182
 183/**
 184 * drm_format_num_planes - get the number of planes for format
 185 * @format: pixel format (DRM_FORMAT_*)
 186 *
 187 * Returns:
 188 * The number of planes used by the specified pixel format.
 189 */
 190int drm_format_num_planes(uint32_t format)
 191{
 192        switch (format) {
 193        case DRM_FORMAT_YUV410:
 194        case DRM_FORMAT_YVU410:
 195        case DRM_FORMAT_YUV411:
 196        case DRM_FORMAT_YVU411:
 197        case DRM_FORMAT_YUV420:
 198        case DRM_FORMAT_YVU420:
 199        case DRM_FORMAT_YUV422:
 200        case DRM_FORMAT_YVU422:
 201        case DRM_FORMAT_YUV444:
 202        case DRM_FORMAT_YVU444:
 203                return 3;
 204        case DRM_FORMAT_NV12:
 205        case DRM_FORMAT_NV21:
 206        case DRM_FORMAT_NV16:
 207        case DRM_FORMAT_NV61:
 208        case DRM_FORMAT_NV24:
 209        case DRM_FORMAT_NV42:
 210                return 2;
 211        default:
 212                return 1;
 213        }
 214}
 215EXPORT_SYMBOL(drm_format_num_planes);
 216
 217/**
 218 * drm_format_plane_cpp - determine the bytes per pixel value
 219 * @format: pixel format (DRM_FORMAT_*)
 220 * @plane: plane index
 221 *
 222 * Returns:
 223 * The bytes per pixel value for the specified plane.
 224 */
 225int drm_format_plane_cpp(uint32_t format, int plane)
 226{
 227        unsigned int depth;
 228        int bpp;
 229
 230        if (plane >= drm_format_num_planes(format))
 231                return 0;
 232
 233        switch (format) {
 234        case DRM_FORMAT_YUYV:
 235        case DRM_FORMAT_YVYU:
 236        case DRM_FORMAT_UYVY:
 237        case DRM_FORMAT_VYUY:
 238                return 2;
 239        case DRM_FORMAT_NV12:
 240        case DRM_FORMAT_NV21:
 241        case DRM_FORMAT_NV16:
 242        case DRM_FORMAT_NV61:
 243        case DRM_FORMAT_NV24:
 244        case DRM_FORMAT_NV42:
 245                return plane ? 2 : 1;
 246        case DRM_FORMAT_YUV410:
 247        case DRM_FORMAT_YVU410:
 248        case DRM_FORMAT_YUV411:
 249        case DRM_FORMAT_YVU411:
 250        case DRM_FORMAT_YUV420:
 251        case DRM_FORMAT_YVU420:
 252        case DRM_FORMAT_YUV422:
 253        case DRM_FORMAT_YVU422:
 254        case DRM_FORMAT_YUV444:
 255        case DRM_FORMAT_YVU444:
 256                return 1;
 257        default:
 258                drm_fb_get_bpp_depth(format, &depth, &bpp);
 259                return bpp >> 3;
 260        }
 261}
 262EXPORT_SYMBOL(drm_format_plane_cpp);
 263
 264/**
 265 * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
 266 * @format: pixel format (DRM_FORMAT_*)
 267 *
 268 * Returns:
 269 * The horizontal chroma subsampling factor for the
 270 * specified pixel format.
 271 */
 272int drm_format_horz_chroma_subsampling(uint32_t format)
 273{
 274        switch (format) {
 275        case DRM_FORMAT_YUV411:
 276        case DRM_FORMAT_YVU411:
 277        case DRM_FORMAT_YUV410:
 278        case DRM_FORMAT_YVU410:
 279                return 4;
 280        case DRM_FORMAT_YUYV:
 281        case DRM_FORMAT_YVYU:
 282        case DRM_FORMAT_UYVY:
 283        case DRM_FORMAT_VYUY:
 284        case DRM_FORMAT_NV12:
 285        case DRM_FORMAT_NV21:
 286        case DRM_FORMAT_NV16:
 287        case DRM_FORMAT_NV61:
 288        case DRM_FORMAT_YUV422:
 289        case DRM_FORMAT_YVU422:
 290        case DRM_FORMAT_YUV420:
 291        case DRM_FORMAT_YVU420:
 292                return 2;
 293        default:
 294                return 1;
 295        }
 296}
 297EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
 298
 299/**
 300 * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
 301 * @format: pixel format (DRM_FORMAT_*)
 302 *
 303 * Returns:
 304 * The vertical chroma subsampling factor for the
 305 * specified pixel format.
 306 */
 307int drm_format_vert_chroma_subsampling(uint32_t format)
 308{
 309        switch (format) {
 310        case DRM_FORMAT_YUV410:
 311        case DRM_FORMAT_YVU410:
 312                return 4;
 313        case DRM_FORMAT_YUV420:
 314        case DRM_FORMAT_YVU420:
 315        case DRM_FORMAT_NV12:
 316        case DRM_FORMAT_NV21:
 317                return 2;
 318        default:
 319                return 1;
 320        }
 321}
 322EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
 323
 324/**
 325 * drm_format_plane_width - width of the plane given the first plane
 326 * @width: width of the first plane
 327 * @format: pixel format
 328 * @plane: plane index
 329 *
 330 * Returns:
 331 * The width of @plane, given that the width of the first plane is @width.
 332 */
 333int drm_format_plane_width(int width, uint32_t format, int plane)
 334{
 335        if (plane >= drm_format_num_planes(format))
 336                return 0;
 337
 338        if (plane == 0)
 339                return width;
 340
 341        return width / drm_format_horz_chroma_subsampling(format);
 342}
 343EXPORT_SYMBOL(drm_format_plane_width);
 344
 345/**
 346 * drm_format_plane_height - height of the plane given the first plane
 347 * @height: height of the first plane
 348 * @format: pixel format
 349 * @plane: plane index
 350 *
 351 * Returns:
 352 * The height of @plane, given that the height of the first plane is @height.
 353 */
 354int drm_format_plane_height(int height, uint32_t format, int plane)
 355{
 356        if (plane >= drm_format_num_planes(format))
 357                return 0;
 358
 359        if (plane == 0)
 360                return height;
 361
 362        return height / drm_format_vert_chroma_subsampling(format);
 363}
 364EXPORT_SYMBOL(drm_format_plane_height);
 365