linux/drivers/gpu/drm/msm/msm_fb.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Red Hat
   3 * Author: Rob Clark <robdclark@gmail.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18#include "msm_drv.h"
  19
  20#include "drm_crtc.h"
  21#include "drm_crtc_helper.h"
  22
  23struct msm_framebuffer {
  24        struct drm_framebuffer base;
  25        const struct msm_format *format;
  26        struct drm_gem_object *planes[2];
  27};
  28#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
  29
  30
  31static int msm_framebuffer_create_handle(struct drm_framebuffer *fb,
  32                struct drm_file *file_priv,
  33                unsigned int *handle)
  34{
  35        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  36        return drm_gem_handle_create(file_priv,
  37                        msm_fb->planes[0], handle);
  38}
  39
  40static void msm_framebuffer_destroy(struct drm_framebuffer *fb)
  41{
  42        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  43        int i, n = drm_format_num_planes(fb->pixel_format);
  44
  45        DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
  46
  47        drm_framebuffer_cleanup(fb);
  48
  49        for (i = 0; i < n; i++) {
  50                struct drm_gem_object *bo = msm_fb->planes[i];
  51                if (bo)
  52                        drm_gem_object_unreference_unlocked(bo);
  53        }
  54
  55        kfree(msm_fb);
  56}
  57
  58static int msm_framebuffer_dirty(struct drm_framebuffer *fb,
  59                struct drm_file *file_priv, unsigned flags, unsigned color,
  60                struct drm_clip_rect *clips, unsigned num_clips)
  61{
  62        return 0;
  63}
  64
  65static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
  66        .create_handle = msm_framebuffer_create_handle,
  67        .destroy = msm_framebuffer_destroy,
  68        .dirty = msm_framebuffer_dirty,
  69};
  70
  71#ifdef CONFIG_DEBUG_FS
  72void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
  73{
  74        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  75        int i, n = drm_format_num_planes(fb->pixel_format);
  76
  77        seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n",
  78                        fb->width, fb->height, (char *)&fb->pixel_format,
  79                        fb->refcount.refcount.counter, fb->base.id);
  80
  81        for (i = 0; i < n; i++) {
  82                seq_printf(m, "   %d: offset=%d pitch=%d, obj: ",
  83                                i, fb->offsets[i], fb->pitches[i]);
  84                msm_gem_describe(msm_fb->planes[i], m);
  85        }
  86}
  87#endif
  88
  89struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
  90{
  91        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  92        return msm_fb->planes[plane];
  93}
  94
  95const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
  96{
  97        struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  98        return msm_fb->format;
  99}
 100
 101struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 102                struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd)
 103{
 104        struct drm_gem_object *bos[4] = {0};
 105        struct drm_framebuffer *fb;
 106        int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
 107
 108        for (i = 0; i < n; i++) {
 109                bos[i] = drm_gem_object_lookup(dev, file,
 110                                mode_cmd->handles[i]);
 111                if (!bos[i]) {
 112                        ret = -ENXIO;
 113                        goto out_unref;
 114                }
 115        }
 116
 117        fb = msm_framebuffer_init(dev, mode_cmd, bos);
 118        if (IS_ERR(fb)) {
 119                ret = PTR_ERR(fb);
 120                goto out_unref;
 121        }
 122
 123        return fb;
 124
 125out_unref:
 126        for (i = 0; i < n; i++)
 127                drm_gem_object_unreference_unlocked(bos[i]);
 128        return ERR_PTR(ret);
 129}
 130
 131struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
 132                struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
 133{
 134        struct msm_drm_private *priv = dev->dev_private;
 135        struct msm_kms *kms = priv->kms;
 136        struct msm_framebuffer *msm_fb;
 137        struct drm_framebuffer *fb = NULL;
 138        const struct msm_format *format;
 139        int ret, i, n;
 140        unsigned int hsub, vsub;
 141
 142        DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
 143                        dev, mode_cmd, mode_cmd->width, mode_cmd->height,
 144                        (char *)&mode_cmd->pixel_format);
 145
 146        n = drm_format_num_planes(mode_cmd->pixel_format);
 147        hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
 148        vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
 149
 150        format = kms->funcs->get_format(kms, mode_cmd->pixel_format);
 151        if (!format) {
 152                dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
 153                                (char *)&mode_cmd->pixel_format);
 154                ret = -EINVAL;
 155                goto fail;
 156        }
 157
 158        msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL);
 159        if (!msm_fb) {
 160                ret = -ENOMEM;
 161                goto fail;
 162        }
 163
 164        fb = &msm_fb->base;
 165
 166        msm_fb->format = format;
 167
 168        for (i = 0; i < n; i++) {
 169                unsigned int width = mode_cmd->width / (i ? hsub : 1);
 170                unsigned int height = mode_cmd->height / (i ? vsub : 1);
 171                unsigned int min_size;
 172
 173                min_size = (height - 1) * mode_cmd->pitches[i]
 174                         + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
 175                         + mode_cmd->offsets[i];
 176
 177                if (bos[i]->size < min_size) {
 178                        ret = -EINVAL;
 179                        goto fail;
 180                }
 181
 182                msm_fb->planes[i] = bos[i];
 183        }
 184
 185        drm_helper_mode_fill_fb_struct(fb, mode_cmd);
 186
 187        ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs);
 188        if (ret) {
 189                dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
 190                goto fail;
 191        }
 192
 193        DBG("create: FB ID: %d (%p)", fb->base.id, fb);
 194
 195        return fb;
 196
 197fail:
 198        if (fb)
 199                msm_framebuffer_destroy(fb);
 200
 201        return ERR_PTR(ret);
 202}
 203