linux/drivers/gpu/drm/exynos/exynos_drm_fb.c
<<
>>
Prefs
   1/* exynos_drm_fb.c
   2 *
   3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
   4 * Authors:
   5 *      Inki Dae <inki.dae@samsung.com>
   6 *      Joonyoung Shim <jy0922.shim@samsung.com>
   7 *      Seung-Woo Kim <sw0312.kim@samsung.com>
   8 *
   9 * This program is free software; you can redistribute  it and/or modify it
  10 * under  the terms of  the GNU General  Public License as published by the
  11 * Free Software Foundation;  either version 2 of the  License, or (at your
  12 * option) any later version.
  13 */
  14
  15#include <drm/drmP.h>
  16#include <drm/drm_crtc.h>
  17#include <drm/drm_crtc_helper.h>
  18#include <drm/drm_fb_helper.h>
  19#include <drm/drm_atomic.h>
  20#include <drm/drm_atomic_helper.h>
  21#include <uapi/drm/exynos_drm.h>
  22
  23#include "exynos_drm_drv.h"
  24#include "exynos_drm_fb.h"
  25#include "exynos_drm_fbdev.h"
  26#include "exynos_drm_iommu.h"
  27#include "exynos_drm_crtc.h"
  28
  29#define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb)
  30
  31/*
  32 * exynos specific framebuffer structure.
  33 *
  34 * @fb: drm framebuffer obejct.
  35 * @exynos_gem: array of exynos specific gem object containing a gem object.
  36 */
  37struct exynos_drm_fb {
  38        struct drm_framebuffer  fb;
  39        struct exynos_drm_gem   *exynos_gem[MAX_FB_BUFFER];
  40        dma_addr_t                      dma_addr[MAX_FB_BUFFER];
  41};
  42
  43static int check_fb_gem_memory_type(struct drm_device *drm_dev,
  44                                    struct exynos_drm_gem *exynos_gem)
  45{
  46        unsigned int flags;
  47
  48        /*
  49         * if exynos drm driver supports iommu then framebuffer can use
  50         * all the buffer types.
  51         */
  52        if (is_drm_iommu_supported(drm_dev))
  53                return 0;
  54
  55        flags = exynos_gem->flags;
  56
  57        /*
  58         * Physically non-contiguous memory type for framebuffer is not
  59         * supported without IOMMU.
  60         */
  61        if (IS_NONCONTIG_BUFFER(flags)) {
  62                DRM_ERROR("Non-contiguous GEM memory is not supported.\n");
  63                return -EINVAL;
  64        }
  65
  66        return 0;
  67}
  68
  69static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
  70{
  71        struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
  72        unsigned int i;
  73
  74        drm_framebuffer_cleanup(fb);
  75
  76        for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) {
  77                struct drm_gem_object *obj;
  78
  79                if (exynos_fb->exynos_gem[i] == NULL)
  80                        continue;
  81
  82                obj = &exynos_fb->exynos_gem[i]->base;
  83                drm_gem_object_unreference_unlocked(obj);
  84        }
  85
  86        kfree(exynos_fb);
  87        exynos_fb = NULL;
  88}
  89
  90static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
  91                                        struct drm_file *file_priv,
  92                                        unsigned int *handle)
  93{
  94        struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
  95
  96        return drm_gem_handle_create(file_priv,
  97                                     &exynos_fb->exynos_gem[0]->base, handle);
  98}
  99
 100static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
 101        .destroy        = exynos_drm_fb_destroy,
 102        .create_handle  = exynos_drm_fb_create_handle,
 103};
 104
 105struct drm_framebuffer *
 106exynos_drm_framebuffer_init(struct drm_device *dev,
 107                            const struct drm_mode_fb_cmd2 *mode_cmd,
 108                            struct exynos_drm_gem **exynos_gem,
 109                            int count)
 110{
 111        struct exynos_drm_fb *exynos_fb;
 112        int i;
 113        int ret;
 114
 115        exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
 116        if (!exynos_fb)
 117                return ERR_PTR(-ENOMEM);
 118
 119        for (i = 0; i < count; i++) {
 120                ret = check_fb_gem_memory_type(dev, exynos_gem[i]);
 121                if (ret < 0)
 122                        goto err;
 123
 124                exynos_fb->exynos_gem[i] = exynos_gem[i];
 125                exynos_fb->dma_addr[i] = exynos_gem[i]->dma_addr
 126                                                + mode_cmd->offsets[i];
 127        }
 128
 129        drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
 130
 131        ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs);
 132        if (ret < 0) {
 133                DRM_ERROR("failed to initialize framebuffer\n");
 134                goto err;
 135        }
 136
 137        return &exynos_fb->fb;
 138
 139err:
 140        kfree(exynos_fb);
 141        return ERR_PTR(ret);
 142}
 143
 144static struct drm_framebuffer *
 145exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 146                      const struct drm_mode_fb_cmd2 *mode_cmd)
 147{
 148        struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
 149        struct drm_gem_object *obj;
 150        struct drm_framebuffer *fb;
 151        int i;
 152        int ret;
 153
 154        for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
 155                obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
 156                if (!obj) {
 157                        DRM_ERROR("failed to lookup gem object\n");
 158                        ret = -ENOENT;
 159                        goto err;
 160                }
 161
 162                exynos_gem[i] = to_exynos_gem(obj);
 163        }
 164
 165        fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);
 166        if (IS_ERR(fb)) {
 167                ret = PTR_ERR(fb);
 168                goto err;
 169        }
 170
 171        return fb;
 172
 173err:
 174        while (i--)
 175                drm_gem_object_unreference_unlocked(&exynos_gem[i]->base);
 176
 177        return ERR_PTR(ret);
 178}
 179
 180dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
 181{
 182        struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 183
 184        if (index >= MAX_FB_BUFFER)
 185                return DMA_ERROR_CODE;
 186
 187        return exynos_fb->dma_addr[index];
 188}
 189
 190static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
 191        .fb_create = exynos_user_fb_create,
 192        .output_poll_changed = exynos_drm_output_poll_changed,
 193        .atomic_check = exynos_atomic_check,
 194        .atomic_commit = exynos_atomic_commit,
 195};
 196
 197void exynos_drm_mode_config_init(struct drm_device *dev)
 198{
 199        dev->mode_config.min_width = 0;
 200        dev->mode_config.min_height = 0;
 201
 202        /*
 203         * set max width and height as default value(4096x4096).
 204         * this value would be used to check framebuffer size limitation
 205         * at drm_mode_addfb().
 206         */
 207        dev->mode_config.max_width = 4096;
 208        dev->mode_config.max_height = 4096;
 209
 210        dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
 211}
 212