linux/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
   3 * Author:Mark Yao <mark.yao@rock-chips.com>
   4 *
   5 * This software is licensed under the terms of the GNU General Public
   6 * License version 2, as published by the Free Software Foundation, and
   7 * may be copied, distributed, and modified under those terms.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <drm/drm.h>
  17#include <drm/drmP.h>
  18#include <drm/drm_atomic.h>
  19#include <drm/drm_fb_helper.h>
  20#include <drm/drm_crtc_helper.h>
  21
  22#include "rockchip_drm_drv.h"
  23#include "rockchip_drm_fb.h"
  24#include "rockchip_drm_gem.h"
  25#include "rockchip_drm_psr.h"
  26
  27#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
  28
  29struct rockchip_drm_fb {
  30        struct drm_framebuffer fb;
  31        struct drm_gem_object *obj[ROCKCHIP_MAX_FB_BUFFER];
  32};
  33
  34struct drm_gem_object *rockchip_fb_get_gem_obj(struct drm_framebuffer *fb,
  35                                               unsigned int plane)
  36{
  37        struct rockchip_drm_fb *rk_fb = to_rockchip_fb(fb);
  38
  39        if (plane >= ROCKCHIP_MAX_FB_BUFFER)
  40                return NULL;
  41
  42        return rk_fb->obj[plane];
  43}
  44
  45static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
  46{
  47        struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
  48        int i;
  49
  50        for (i = 0; i < ROCKCHIP_MAX_FB_BUFFER; i++)
  51                drm_gem_object_put_unlocked(rockchip_fb->obj[i]);
  52
  53        drm_framebuffer_cleanup(fb);
  54        kfree(rockchip_fb);
  55}
  56
  57static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
  58                                         struct drm_file *file_priv,
  59                                         unsigned int *handle)
  60{
  61        struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
  62
  63        return drm_gem_handle_create(file_priv,
  64                                     rockchip_fb->obj[0], handle);
  65}
  66
  67static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
  68                                 struct drm_file *file,
  69                                 unsigned int flags, unsigned int color,
  70                                 struct drm_clip_rect *clips,
  71                                 unsigned int num_clips)
  72{
  73        rockchip_drm_psr_flush_all(fb->dev);
  74        return 0;
  75}
  76
  77static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
  78        .destroy        = rockchip_drm_fb_destroy,
  79        .create_handle  = rockchip_drm_fb_create_handle,
  80        .dirty          = rockchip_drm_fb_dirty,
  81};
  82
  83static struct rockchip_drm_fb *
  84rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
  85                  struct drm_gem_object **obj, unsigned int num_planes)
  86{
  87        struct rockchip_drm_fb *rockchip_fb;
  88        int ret;
  89        int i;
  90
  91        rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
  92        if (!rockchip_fb)
  93                return ERR_PTR(-ENOMEM);
  94
  95        drm_helper_mode_fill_fb_struct(dev, &rockchip_fb->fb, mode_cmd);
  96
  97        for (i = 0; i < num_planes; i++)
  98                rockchip_fb->obj[i] = obj[i];
  99
 100        ret = drm_framebuffer_init(dev, &rockchip_fb->fb,
 101                                   &rockchip_drm_fb_funcs);
 102        if (ret) {
 103                dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
 104                        ret);
 105                kfree(rockchip_fb);
 106                return ERR_PTR(ret);
 107        }
 108
 109        return rockchip_fb;
 110}
 111
 112static struct drm_framebuffer *
 113rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 114                        const struct drm_mode_fb_cmd2 *mode_cmd)
 115{
 116        struct rockchip_drm_fb *rockchip_fb;
 117        struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
 118        struct drm_gem_object *obj;
 119        unsigned int hsub;
 120        unsigned int vsub;
 121        int num_planes;
 122        int ret;
 123        int i;
 124
 125        hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
 126        vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
 127        num_planes = min(drm_format_num_planes(mode_cmd->pixel_format),
 128                         ROCKCHIP_MAX_FB_BUFFER);
 129
 130        for (i = 0; i < num_planes; i++) {
 131                unsigned int width = mode_cmd->width / (i ? hsub : 1);
 132                unsigned int height = mode_cmd->height / (i ? vsub : 1);
 133                unsigned int min_size;
 134
 135                obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
 136                if (!obj) {
 137                        dev_err(dev->dev, "Failed to lookup GEM object\n");
 138                        ret = -ENXIO;
 139                        goto err_gem_object_unreference;
 140                }
 141
 142                min_size = (height - 1) * mode_cmd->pitches[i] +
 143                        mode_cmd->offsets[i] +
 144                        width * drm_format_plane_cpp(mode_cmd->pixel_format, i);
 145
 146                if (obj->size < min_size) {
 147                        drm_gem_object_put_unlocked(obj);
 148                        ret = -EINVAL;
 149                        goto err_gem_object_unreference;
 150                }
 151                objs[i] = obj;
 152        }
 153
 154        rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, objs, i);
 155        if (IS_ERR(rockchip_fb)) {
 156                ret = PTR_ERR(rockchip_fb);
 157                goto err_gem_object_unreference;
 158        }
 159
 160        return &rockchip_fb->fb;
 161
 162err_gem_object_unreference:
 163        for (i--; i >= 0; i--)
 164                drm_gem_object_put_unlocked(objs[i]);
 165        return ERR_PTR(ret);
 166}
 167
 168static void rockchip_drm_output_poll_changed(struct drm_device *dev)
 169{
 170        struct rockchip_drm_private *private = dev->dev_private;
 171
 172        drm_fb_helper_hotplug_event(&private->fbdev_helper);
 173}
 174
 175static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
 176        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 177};
 178
 179static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
 180        .fb_create = rockchip_user_fb_create,
 181        .output_poll_changed = rockchip_drm_output_poll_changed,
 182        .atomic_check = drm_atomic_helper_check,
 183        .atomic_commit = drm_atomic_helper_commit,
 184};
 185
 186struct drm_framebuffer *
 187rockchip_drm_framebuffer_init(struct drm_device *dev,
 188                              const struct drm_mode_fb_cmd2 *mode_cmd,
 189                              struct drm_gem_object *obj)
 190{
 191        struct rockchip_drm_fb *rockchip_fb;
 192
 193        rockchip_fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1);
 194        if (IS_ERR(rockchip_fb))
 195                return ERR_CAST(rockchip_fb);
 196
 197        return &rockchip_fb->fb;
 198}
 199
 200void rockchip_drm_mode_config_init(struct drm_device *dev)
 201{
 202        dev->mode_config.min_width = 0;
 203        dev->mode_config.min_height = 0;
 204
 205        /*
 206         * set max width and height as default value(4096x4096).
 207         * this value would be used to check framebuffer size limitation
 208         * at drm_mode_addfb().
 209         */
 210        dev->mode_config.max_width = 4096;
 211        dev->mode_config.max_height = 4096;
 212
 213        dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
 214        dev->mode_config.helper_private = &rockchip_mode_config_helpers;
 215}
 216