linux/drivers/gpu/drm/mediatek/mtk_drm_fb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 MediaTek Inc.
   4 */
   5
   6#include <drm/drmP.h>
   7#include <drm/drm_modeset_helper.h>
   8#include <drm/drm_fb_helper.h>
   9#include <drm/drm_gem.h>
  10#include <drm/drm_gem_framebuffer_helper.h>
  11#include <linux/dma-buf.h>
  12#include <linux/reservation.h>
  13
  14#include "mtk_drm_drv.h"
  15#include "mtk_drm_fb.h"
  16#include "mtk_drm_gem.h"
  17
  18static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
  19        .create_handle = drm_gem_fb_create_handle,
  20        .destroy = drm_gem_fb_destroy,
  21};
  22
  23static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,
  24                                        const struct drm_mode_fb_cmd2 *mode,
  25                                        struct drm_gem_object *obj)
  26{
  27        const struct drm_format_info *info = drm_get_format_info(dev, mode);
  28        struct drm_framebuffer *fb;
  29        int ret;
  30
  31        if (info->num_planes != 1)
  32                return ERR_PTR(-EINVAL);
  33
  34        fb = kzalloc(sizeof(*fb), GFP_KERNEL);
  35        if (!fb)
  36                return ERR_PTR(-ENOMEM);
  37
  38        drm_helper_mode_fill_fb_struct(dev, fb, mode);
  39
  40        fb->obj[0] = obj;
  41
  42        ret = drm_framebuffer_init(dev, fb, &mtk_drm_fb_funcs);
  43        if (ret) {
  44                DRM_ERROR("failed to initialize framebuffer\n");
  45                kfree(fb);
  46                return ERR_PTR(ret);
  47        }
  48
  49        return fb;
  50}
  51
  52/*
  53 * Wait for any exclusive fence in fb's gem object's reservation object.
  54 *
  55 * Returns -ERESTARTSYS if interrupted, else 0.
  56 */
  57int mtk_fb_wait(struct drm_framebuffer *fb)
  58{
  59        struct drm_gem_object *gem;
  60        struct reservation_object *resv;
  61        long ret;
  62
  63        if (!fb)
  64                return 0;
  65
  66        gem = fb->obj[0];
  67        if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
  68                return 0;
  69
  70        resv = gem->dma_buf->resv;
  71        ret = reservation_object_wait_timeout_rcu(resv, false, true,
  72                                                  MAX_SCHEDULE_TIMEOUT);
  73        /* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
  74        if (WARN_ON(ret < 0))
  75                return ret;
  76
  77        return 0;
  78}
  79
  80struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
  81                                               struct drm_file *file,
  82                                               const struct drm_mode_fb_cmd2 *cmd)
  83{
  84        const struct drm_format_info *info = drm_get_format_info(dev, cmd);
  85        struct drm_framebuffer *fb;
  86        struct drm_gem_object *gem;
  87        unsigned int width = cmd->width;
  88        unsigned int height = cmd->height;
  89        unsigned int size, bpp;
  90        int ret;
  91
  92        if (info->num_planes != 1)
  93                return ERR_PTR(-EINVAL);
  94
  95        gem = drm_gem_object_lookup(file, cmd->handles[0]);
  96        if (!gem)
  97                return ERR_PTR(-ENOENT);
  98
  99        bpp = info->cpp[0];
 100        size = (height - 1) * cmd->pitches[0] + width * bpp;
 101        size += cmd->offsets[0];
 102
 103        if (gem->size < size) {
 104                ret = -EINVAL;
 105                goto unreference;
 106        }
 107
 108        fb = mtk_drm_framebuffer_init(dev, cmd, gem);
 109        if (IS_ERR(fb)) {
 110                ret = PTR_ERR(fb);
 111                goto unreference;
 112        }
 113
 114        return fb;
 115
 116unreference:
 117        drm_gem_object_put_unlocked(gem);
 118        return ERR_PTR(ret);
 119}
 120