linux/drivers/gpu/drm/armada/armada_fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2012 Russell King
   4 */
   5
   6#include <drm/drm_modeset_helper.h>
   7#include <drm/drm_fb_helper.h>
   8#include <drm/drm_fourcc.h>
   9#include <drm/drm_gem_framebuffer_helper.h>
  10
  11#include "armada_drm.h"
  12#include "armada_fb.h"
  13#include "armada_gem.h"
  14#include "armada_hw.h"
  15
  16static const struct drm_framebuffer_funcs armada_fb_funcs = {
  17        .destroy        = drm_gem_fb_destroy,
  18        .create_handle  = drm_gem_fb_create_handle,
  19};
  20
  21struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
  22        const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
  23{
  24        struct armada_framebuffer *dfb;
  25        uint8_t format, config;
  26        int ret;
  27
  28        switch (mode->pixel_format) {
  29#define FMT(drm, fmt, mod)              \
  30        case DRM_FORMAT_##drm:          \
  31                format = CFG_##fmt;     \
  32                config = mod;           \
  33                break
  34        FMT(RGB565,     565,            CFG_SWAPRB);
  35        FMT(BGR565,     565,            0);
  36        FMT(ARGB1555,   1555,           CFG_SWAPRB);
  37        FMT(ABGR1555,   1555,           0);
  38        FMT(RGB888,     888PACK,        CFG_SWAPRB);
  39        FMT(BGR888,     888PACK,        0);
  40        FMT(XRGB8888,   X888,           CFG_SWAPRB);
  41        FMT(XBGR8888,   X888,           0);
  42        FMT(ARGB8888,   8888,           CFG_SWAPRB);
  43        FMT(ABGR8888,   8888,           0);
  44        FMT(YUYV,       422PACK,        CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV);
  45        FMT(UYVY,       422PACK,        CFG_YUV2RGB);
  46        FMT(VYUY,       422PACK,        CFG_YUV2RGB | CFG_SWAPUV);
  47        FMT(YVYU,       422PACK,        CFG_YUV2RGB | CFG_SWAPYU);
  48        FMT(YUV422,     422,            CFG_YUV2RGB);
  49        FMT(YVU422,     422,            CFG_YUV2RGB | CFG_SWAPUV);
  50        FMT(YUV420,     420,            CFG_YUV2RGB);
  51        FMT(YVU420,     420,            CFG_YUV2RGB | CFG_SWAPUV);
  52        FMT(C8,         PSEUDO8,        0);
  53#undef FMT
  54        default:
  55                return ERR_PTR(-EINVAL);
  56        }
  57
  58        dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
  59        if (!dfb) {
  60                DRM_ERROR("failed to allocate Armada fb object\n");
  61                return ERR_PTR(-ENOMEM);
  62        }
  63
  64        dfb->fmt = format;
  65        dfb->mod = config;
  66        dfb->fb.obj[0] = &obj->obj;
  67
  68        drm_helper_mode_fill_fb_struct(dev, &dfb->fb, mode);
  69
  70        ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs);
  71        if (ret) {
  72                kfree(dfb);
  73                return ERR_PTR(ret);
  74        }
  75
  76        /*
  77         * Take a reference on our object as we're successful - the
  78         * caller already holds a reference, which keeps us safe for
  79         * the above call, but the caller will drop their reference
  80         * to it.  Hence we need to take our own reference.
  81         */
  82        drm_gem_object_get(&obj->obj);
  83
  84        return dfb;
  85}
  86
  87struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
  88        struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
  89{
  90        const struct drm_format_info *info = drm_get_format_info(dev, mode);
  91        struct armada_gem_object *obj;
  92        struct armada_framebuffer *dfb;
  93        int ret;
  94
  95        DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n",
  96                mode->width, mode->height, mode->pixel_format,
  97                mode->flags, mode->pitches[0], mode->pitches[1],
  98                mode->pitches[2]);
  99
 100        /* We can only handle a single plane at the moment */
 101        if (info->num_planes > 1 &&
 102            (mode->handles[0] != mode->handles[1] ||
 103             mode->handles[0] != mode->handles[2])) {
 104                ret = -EINVAL;
 105                goto err;
 106        }
 107
 108        obj = armada_gem_object_lookup(dfile, mode->handles[0]);
 109        if (!obj) {
 110                ret = -ENOENT;
 111                goto err;
 112        }
 113
 114        if (obj->obj.import_attach && !obj->sgt) {
 115                ret = armada_gem_map_import(obj);
 116                if (ret)
 117                        goto err_unref;
 118        }
 119
 120        /* Framebuffer objects must have a valid device address for scanout */
 121        if (!obj->mapped) {
 122                ret = -EINVAL;
 123                goto err_unref;
 124        }
 125
 126        dfb = armada_framebuffer_create(dev, mode, obj);
 127        if (IS_ERR(dfb)) {
 128                ret = PTR_ERR(dfb);
 129                goto err;
 130        }
 131
 132        drm_gem_object_put(&obj->obj);
 133
 134        return &dfb->fb;
 135
 136 err_unref:
 137        drm_gem_object_put(&obj->obj);
 138 err:
 139        DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
 140        return ERR_PTR(ret);
 141}
 142