linux/drivers/gpu/drm/rockchip/rockchip_drm_gem.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 <drm/drm.h>
  16#include <drm/drmP.h>
  17#include <drm/drm_gem.h>
  18#include <drm/drm_vma_manager.h>
  19
  20#include <linux/dma-attrs.h>
  21
  22#include "rockchip_drm_drv.h"
  23#include "rockchip_drm_gem.h"
  24
  25static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
  26                                  bool alloc_kmap)
  27{
  28        struct drm_gem_object *obj = &rk_obj->base;
  29        struct drm_device *drm = obj->dev;
  30
  31        init_dma_attrs(&rk_obj->dma_attrs);
  32        dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
  33
  34        if (!alloc_kmap)
  35                dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
  36
  37        rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
  38                                         &rk_obj->dma_addr, GFP_KERNEL,
  39                                         &rk_obj->dma_attrs);
  40        if (!rk_obj->kvaddr) {
  41                DRM_ERROR("failed to allocate %#x byte dma buffer", obj->size);
  42                return -ENOMEM;
  43        }
  44
  45        return 0;
  46}
  47
  48static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
  49{
  50        struct drm_gem_object *obj = &rk_obj->base;
  51        struct drm_device *drm = obj->dev;
  52
  53        dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
  54                       &rk_obj->dma_attrs);
  55}
  56
  57static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
  58                                        struct vm_area_struct *vma)
  59
  60{
  61        int ret;
  62        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
  63        struct drm_device *drm = obj->dev;
  64
  65        /*
  66         * dma_alloc_attrs() allocated a struct page table for rk_obj, so clear
  67         * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
  68         */
  69        vma->vm_flags &= ~VM_PFNMAP;
  70        vma->vm_pgoff = 0;
  71
  72        ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
  73                             obj->size, &rk_obj->dma_attrs);
  74        if (ret)
  75                drm_gem_vm_close(vma);
  76
  77        return ret;
  78}
  79
  80int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
  81                          struct vm_area_struct *vma)
  82{
  83        int ret;
  84
  85        ret = drm_gem_mmap_obj(obj, obj->size, vma);
  86        if (ret)
  87                return ret;
  88
  89        return rockchip_drm_gem_object_mmap(obj, vma);
  90}
  91
  92/* drm driver mmap file operations */
  93int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
  94{
  95        struct drm_gem_object *obj;
  96        int ret;
  97
  98        ret = drm_gem_mmap(filp, vma);
  99        if (ret)
 100                return ret;
 101
 102        obj = vma->vm_private_data;
 103
 104        return rockchip_drm_gem_object_mmap(obj, vma);
 105}
 106
 107struct rockchip_gem_object *
 108        rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
 109                                   bool alloc_kmap)
 110{
 111        struct rockchip_gem_object *rk_obj;
 112        struct drm_gem_object *obj;
 113        int ret;
 114
 115        size = round_up(size, PAGE_SIZE);
 116
 117        rk_obj = kzalloc(sizeof(*rk_obj), GFP_KERNEL);
 118        if (!rk_obj)
 119                return ERR_PTR(-ENOMEM);
 120
 121        obj = &rk_obj->base;
 122
 123        drm_gem_private_object_init(drm, obj, size);
 124
 125        ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
 126        if (ret)
 127                goto err_free_rk_obj;
 128
 129        return rk_obj;
 130
 131err_free_rk_obj:
 132        kfree(rk_obj);
 133        return ERR_PTR(ret);
 134}
 135
 136/*
 137 * rockchip_gem_free_object - (struct drm_driver)->gem_free_object callback
 138 * function
 139 */
 140void rockchip_gem_free_object(struct drm_gem_object *obj)
 141{
 142        struct rockchip_gem_object *rk_obj;
 143
 144        drm_gem_free_mmap_offset(obj);
 145
 146        rk_obj = to_rockchip_obj(obj);
 147
 148        rockchip_gem_free_buf(rk_obj);
 149
 150        kfree(rk_obj);
 151}
 152
 153/*
 154 * rockchip_gem_create_with_handle - allocate an object with the given
 155 * size and create a gem handle on it
 156 *
 157 * returns a struct rockchip_gem_object* on success or ERR_PTR values
 158 * on failure.
 159 */
 160static struct rockchip_gem_object *
 161rockchip_gem_create_with_handle(struct drm_file *file_priv,
 162                                struct drm_device *drm, unsigned int size,
 163                                unsigned int *handle)
 164{
 165        struct rockchip_gem_object *rk_obj;
 166        struct drm_gem_object *obj;
 167        int ret;
 168
 169        rk_obj = rockchip_gem_create_object(drm, size, false);
 170        if (IS_ERR(rk_obj))
 171                return ERR_CAST(rk_obj);
 172
 173        obj = &rk_obj->base;
 174
 175        /*
 176         * allocate a id of idr table where the obj is registered
 177         * and handle has the id what user can see.
 178         */
 179        ret = drm_gem_handle_create(file_priv, obj, handle);
 180        if (ret)
 181                goto err_handle_create;
 182
 183        /* drop reference from allocate - handle holds it now. */
 184        drm_gem_object_unreference_unlocked(obj);
 185
 186        return rk_obj;
 187
 188err_handle_create:
 189        rockchip_gem_free_object(obj);
 190
 191        return ERR_PTR(ret);
 192}
 193
 194int rockchip_gem_dumb_map_offset(struct drm_file *file_priv,
 195                                 struct drm_device *dev, uint32_t handle,
 196                                 uint64_t *offset)
 197{
 198        struct drm_gem_object *obj;
 199        int ret;
 200
 201        obj = drm_gem_object_lookup(dev, file_priv, handle);
 202        if (!obj) {
 203                DRM_ERROR("failed to lookup gem object.\n");
 204                return -EINVAL;
 205        }
 206
 207        ret = drm_gem_create_mmap_offset(obj);
 208        if (ret)
 209                goto out;
 210
 211        *offset = drm_vma_node_offset_addr(&obj->vma_node);
 212        DRM_DEBUG_KMS("offset = 0x%llx\n", *offset);
 213
 214out:
 215        drm_gem_object_unreference_unlocked(obj);
 216
 217        return 0;
 218}
 219
 220/*
 221 * rockchip_gem_dumb_create - (struct drm_driver)->dumb_create callback
 222 * function
 223 *
 224 * This aligns the pitch and size arguments to the minimum required. wrap
 225 * this into your own function if you need bigger alignment.
 226 */
 227int rockchip_gem_dumb_create(struct drm_file *file_priv,
 228                             struct drm_device *dev,
 229                             struct drm_mode_create_dumb *args)
 230{
 231        struct rockchip_gem_object *rk_obj;
 232        int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
 233
 234        /*
 235         * align to 64 bytes since Mali requires it.
 236         */
 237        args->pitch = ALIGN(min_pitch, 64);
 238        args->size = args->pitch * args->height;
 239
 240        rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size,
 241                                                 &args->handle);
 242
 243        return PTR_ERR_OR_ZERO(rk_obj);
 244}
 245
 246/*
 247 * Allocate a sg_table for this GEM object.
 248 * Note: Both the table's contents, and the sg_table itself must be freed by
 249 *       the caller.
 250 * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
 251 */
 252struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
 253{
 254        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 255        struct drm_device *drm = obj->dev;
 256        struct sg_table *sgt;
 257        int ret;
 258
 259        sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
 260        if (!sgt)
 261                return ERR_PTR(-ENOMEM);
 262
 263        ret = dma_get_sgtable_attrs(drm->dev, sgt, rk_obj->kvaddr,
 264                                    rk_obj->dma_addr, obj->size,
 265                                    &rk_obj->dma_attrs);
 266        if (ret) {
 267                DRM_ERROR("failed to allocate sgt, %d\n", ret);
 268                kfree(sgt);
 269                return ERR_PTR(ret);
 270        }
 271
 272        return sgt;
 273}
 274
 275void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
 276{
 277        struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
 278
 279        if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
 280                return NULL;
 281
 282        return rk_obj->kvaddr;
 283}
 284
 285void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 286{
 287        /* Nothing to do */
 288}
 289