linux/drivers/gpu/drm/mediatek/mtk_drm_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 MediaTek Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <drm/drmP.h>
  15#include <drm/drm_crtc_helper.h>
  16#include <drm/drm_fb_helper.h>
  17#include <drm/drm_gem.h>
  18#include <linux/dma-buf.h>
  19#include <linux/reservation.h>
  20
  21#include "mtk_drm_drv.h"
  22#include "mtk_drm_fb.h"
  23#include "mtk_drm_gem.h"
  24
  25/*
  26 * mtk specific framebuffer structure.
  27 *
  28 * @fb: drm framebuffer object.
  29 * @gem_obj: array of gem objects.
  30 */
  31struct mtk_drm_fb {
  32        struct drm_framebuffer  base;
  33        /* For now we only support a single plane */
  34        struct drm_gem_object   *gem_obj;
  35};
  36
  37#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
  38
  39struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb)
  40{
  41        struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
  42
  43        return mtk_fb->gem_obj;
  44}
  45
  46static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
  47                                    struct drm_file *file_priv,
  48                                    unsigned int *handle)
  49{
  50        struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
  51
  52        return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle);
  53}
  54
  55static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
  56{
  57        struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
  58
  59        drm_framebuffer_cleanup(fb);
  60
  61        drm_gem_object_put_unlocked(mtk_fb->gem_obj);
  62
  63        kfree(mtk_fb);
  64}
  65
  66static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
  67        .create_handle = mtk_drm_fb_create_handle,
  68        .destroy = mtk_drm_fb_destroy,
  69};
  70
  71static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
  72                                        const struct drm_mode_fb_cmd2 *mode,
  73                                        struct drm_gem_object *obj)
  74{
  75        struct mtk_drm_fb *mtk_fb;
  76        int ret;
  77
  78        if (drm_format_num_planes(mode->pixel_format) != 1)
  79                return ERR_PTR(-EINVAL);
  80
  81        mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL);
  82        if (!mtk_fb)
  83                return ERR_PTR(-ENOMEM);
  84
  85        drm_helper_mode_fill_fb_struct(dev, &mtk_fb->base, mode);
  86
  87        mtk_fb->gem_obj = obj;
  88
  89        ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs);
  90        if (ret) {
  91                DRM_ERROR("failed to initialize framebuffer\n");
  92                kfree(mtk_fb);
  93                return ERR_PTR(ret);
  94        }
  95
  96        return mtk_fb;
  97}
  98
  99/*
 100 * Wait for any exclusive fence in fb's gem object's reservation object.
 101 *
 102 * Returns -ERESTARTSYS if interrupted, else 0.
 103 */
 104int mtk_fb_wait(struct drm_framebuffer *fb)
 105{
 106        struct drm_gem_object *gem;
 107        struct reservation_object *resv;
 108        long ret;
 109
 110        if (!fb)
 111                return 0;
 112
 113        gem = mtk_fb_get_gem_obj(fb);
 114        if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
 115                return 0;
 116
 117        resv = gem->dma_buf->resv;
 118        ret = reservation_object_wait_timeout_rcu(resv, false, true,
 119                                                  MAX_SCHEDULE_TIMEOUT);
 120        /* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
 121        if (WARN_ON(ret < 0))
 122                return ret;
 123
 124        return 0;
 125}
 126
 127struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
 128                                               struct drm_file *file,
 129                                               const struct drm_mode_fb_cmd2 *cmd)
 130{
 131        struct mtk_drm_fb *mtk_fb;
 132        struct drm_gem_object *gem;
 133        unsigned int width = cmd->width;
 134        unsigned int height = cmd->height;
 135        unsigned int size, bpp;
 136        int ret;
 137
 138        if (drm_format_num_planes(cmd->pixel_format) != 1)
 139                return ERR_PTR(-EINVAL);
 140
 141        gem = drm_gem_object_lookup(file, cmd->handles[0]);
 142        if (!gem)
 143                return ERR_PTR(-ENOENT);
 144
 145        bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
 146        size = (height - 1) * cmd->pitches[0] + width * bpp;
 147        size += cmd->offsets[0];
 148
 149        if (gem->size < size) {
 150                ret = -EINVAL;
 151                goto unreference;
 152        }
 153
 154        mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
 155        if (IS_ERR(mtk_fb)) {
 156                ret = PTR_ERR(mtk_fb);
 157                goto unreference;
 158        }
 159
 160        return &mtk_fb->base;
 161
 162unreference:
 163        drm_gem_object_put_unlocked(gem);
 164        return ERR_PTR(ret);
 165}
 166