Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Russell King
0004  */
0005 
0006 #include <drm/drm_modeset_helper.h>
0007 #include <drm/drm_fb_helper.h>
0008 #include <drm/drm_fourcc.h>
0009 #include <drm/drm_gem_framebuffer_helper.h>
0010 
0011 #include "armada_drm.h"
0012 #include "armada_fb.h"
0013 #include "armada_gem.h"
0014 #include "armada_hw.h"
0015 
0016 static const struct drm_framebuffer_funcs armada_fb_funcs = {
0017     .destroy    = drm_gem_fb_destroy,
0018     .create_handle  = drm_gem_fb_create_handle,
0019 };
0020 
0021 struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev,
0022     const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj)
0023 {
0024     struct armada_framebuffer *dfb;
0025     uint8_t format, config;
0026     int ret;
0027 
0028     switch (mode->pixel_format) {
0029 #define FMT(drm, fmt, mod)      \
0030     case DRM_FORMAT_##drm:      \
0031         format = CFG_##fmt; \
0032         config = mod;       \
0033         break
0034     FMT(RGB565, 565,        CFG_SWAPRB);
0035     FMT(BGR565, 565,        0);
0036     FMT(ARGB1555,   1555,       CFG_SWAPRB);
0037     FMT(ABGR1555,   1555,       0);
0038     FMT(RGB888, 888PACK,    CFG_SWAPRB);
0039     FMT(BGR888, 888PACK,    0);
0040     FMT(XRGB8888,   X888,       CFG_SWAPRB);
0041     FMT(XBGR8888,   X888,       0);
0042     FMT(ARGB8888,   8888,       CFG_SWAPRB);
0043     FMT(ABGR8888,   8888,       0);
0044     FMT(YUYV,   422PACK,    CFG_YUV2RGB | CFG_SWAPYU | CFG_SWAPUV);
0045     FMT(UYVY,   422PACK,    CFG_YUV2RGB);
0046     FMT(VYUY,   422PACK,    CFG_YUV2RGB | CFG_SWAPUV);
0047     FMT(YVYU,   422PACK,    CFG_YUV2RGB | CFG_SWAPYU);
0048     FMT(YUV422, 422,        CFG_YUV2RGB);
0049     FMT(YVU422, 422,        CFG_YUV2RGB | CFG_SWAPUV);
0050     FMT(YUV420, 420,        CFG_YUV2RGB);
0051     FMT(YVU420, 420,        CFG_YUV2RGB | CFG_SWAPUV);
0052     FMT(C8,     PSEUDO8,    0);
0053 #undef FMT
0054     default:
0055         return ERR_PTR(-EINVAL);
0056     }
0057 
0058     dfb = kzalloc(sizeof(*dfb), GFP_KERNEL);
0059     if (!dfb) {
0060         DRM_ERROR("failed to allocate Armada fb object\n");
0061         return ERR_PTR(-ENOMEM);
0062     }
0063 
0064     dfb->fmt = format;
0065     dfb->mod = config;
0066     dfb->fb.obj[0] = &obj->obj;
0067 
0068     drm_helper_mode_fill_fb_struct(dev, &dfb->fb, mode);
0069 
0070     ret = drm_framebuffer_init(dev, &dfb->fb, &armada_fb_funcs);
0071     if (ret) {
0072         kfree(dfb);
0073         return ERR_PTR(ret);
0074     }
0075 
0076     /*
0077      * Take a reference on our object as we're successful - the
0078      * caller already holds a reference, which keeps us safe for
0079      * the above call, but the caller will drop their reference
0080      * to it.  Hence we need to take our own reference.
0081      */
0082     drm_gem_object_get(&obj->obj);
0083 
0084     return dfb;
0085 }
0086 
0087 struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
0088     struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode)
0089 {
0090     const struct drm_format_info *info = drm_get_format_info(dev, mode);
0091     struct armada_gem_object *obj;
0092     struct armada_framebuffer *dfb;
0093     int ret;
0094 
0095     DRM_DEBUG_DRIVER("w%u h%u pf%08x f%u p%u,%u,%u\n",
0096         mode->width, mode->height, mode->pixel_format,
0097         mode->flags, mode->pitches[0], mode->pitches[1],
0098         mode->pitches[2]);
0099 
0100     /* We can only handle a single plane at the moment */
0101     if (info->num_planes > 1 &&
0102         (mode->handles[0] != mode->handles[1] ||
0103          mode->handles[0] != mode->handles[2])) {
0104         ret = -EINVAL;
0105         goto err;
0106     }
0107 
0108     obj = armada_gem_object_lookup(dfile, mode->handles[0]);
0109     if (!obj) {
0110         ret = -ENOENT;
0111         goto err;
0112     }
0113 
0114     if (obj->obj.import_attach && !obj->sgt) {
0115         ret = armada_gem_map_import(obj);
0116         if (ret)
0117             goto err_unref;
0118     }
0119 
0120     /* Framebuffer objects must have a valid device address for scanout */
0121     if (!obj->mapped) {
0122         ret = -EINVAL;
0123         goto err_unref;
0124     }
0125 
0126     dfb = armada_framebuffer_create(dev, mode, obj);
0127     if (IS_ERR(dfb)) {
0128         ret = PTR_ERR(dfb);
0129         goto err;
0130     }
0131 
0132     drm_gem_object_put(&obj->obj);
0133 
0134     return &dfb->fb;
0135 
0136  err_unref:
0137     drm_gem_object_put(&obj->obj);
0138  err:
0139     DRM_ERROR("failed to initialize framebuffer: %d\n", ret);
0140     return ERR_PTR(ret);
0141 }