UPSTREAM: drm/rockchip: hdmi: add Innosilicon HDMI support
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_drm_gem.c
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_sync_helper.h>
19 #include <drm/drm_vma_manager.h>
20 #include <drm/rockchip_drm.h>
21
22 #include <linux/completion.h>
23 #include <linux/dma-attrs.h>
24 #include <linux/dma-buf.h>
25 #include <linux/reservation.h>
26
27 #include "rockchip_drm_drv.h"
28 #include "rockchip_drm_gem.h"
29
30 static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj,
31                                   bool alloc_kmap)
32 {
33         struct drm_gem_object *obj = &rk_obj->base;
34         struct drm_device *drm = obj->dev;
35
36         init_dma_attrs(&rk_obj->dma_attrs);
37         dma_set_attr(DMA_ATTR_WRITE_COMBINE, &rk_obj->dma_attrs);
38
39         if (!alloc_kmap)
40                 dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs);
41
42         rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
43                                          &rk_obj->dma_addr, GFP_KERNEL,
44                                          &rk_obj->dma_attrs);
45         if (!rk_obj->kvaddr) {
46                 DRM_ERROR("failed to allocate %zu byte dma buffer", obj->size);
47                 return -ENOMEM;
48         }
49
50         return 0;
51 }
52
53 static void rockchip_gem_free_buf(struct rockchip_gem_object *rk_obj)
54 {
55         struct drm_gem_object *obj = &rk_obj->base;
56         struct drm_device *drm = obj->dev;
57
58         dma_free_attrs(drm->dev, obj->size, rk_obj->kvaddr, rk_obj->dma_addr,
59                        &rk_obj->dma_attrs);
60 }
61
62 static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
63                                         struct vm_area_struct *vma)
64
65 {
66         int ret;
67         struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
68         struct drm_device *drm = obj->dev;
69
70         /*
71          * dma_alloc_attrs() allocated a struct page table for rk_obj, so clear
72          * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
73          */
74         vma->vm_flags &= ~VM_PFNMAP;
75         vma->vm_pgoff = 0;
76
77         ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
78                              obj->size, &rk_obj->dma_attrs);
79         if (ret)
80                 drm_gem_vm_close(vma);
81
82         return ret;
83 }
84
85 int rockchip_gem_mmap_buf(struct drm_gem_object *obj,
86                           struct vm_area_struct *vma)
87 {
88         int ret;
89
90         ret = drm_gem_mmap_obj(obj, obj->size, vma);
91         if (ret)
92                 return ret;
93
94         return rockchip_drm_gem_object_mmap(obj, vma);
95 }
96
97 /* drm driver mmap file operations */
98 int rockchip_gem_mmap(struct file *filp, struct vm_area_struct *vma)
99 {
100         struct drm_gem_object *obj;
101         int ret;
102
103         ret = drm_gem_mmap(filp, vma);
104         if (ret)
105                 return ret;
106
107         obj = vma->vm_private_data;
108
109         return rockchip_drm_gem_object_mmap(obj, vma);
110 }
111
112 struct rockchip_gem_object *
113         rockchip_gem_create_object(struct drm_device *drm, unsigned int size,
114                                    bool alloc_kmap)
115 {
116         struct rockchip_gem_object *rk_obj;
117         struct drm_gem_object *obj;
118         int ret;
119
120         size = round_up(size, PAGE_SIZE);
121
122         rk_obj = kzalloc(sizeof(*rk_obj), GFP_KERNEL);
123         if (!rk_obj)
124                 return ERR_PTR(-ENOMEM);
125
126         obj = &rk_obj->base;
127
128         drm_gem_private_object_init(drm, obj, size);
129
130         ret = rockchip_gem_alloc_buf(rk_obj, alloc_kmap);
131         if (ret)
132                 goto err_free_rk_obj;
133
134         return rk_obj;
135
136 err_free_rk_obj:
137         kfree(rk_obj);
138         return ERR_PTR(ret);
139 }
140
141 /*
142  * rockchip_gem_free_object - (struct drm_driver)->gem_free_object callback
143  * function
144  */
145 void rockchip_gem_free_object(struct drm_gem_object *obj)
146 {
147         struct rockchip_gem_object *rk_obj;
148
149         drm_gem_free_mmap_offset(obj);
150
151         rk_obj = to_rockchip_obj(obj);
152
153         rockchip_gem_free_buf(rk_obj);
154
155 #ifdef CONFIG_DRM_DMA_SYNC
156         drm_fence_signal_and_put(&rk_obj->acquire_fence);
157 #endif
158
159         kfree(rk_obj);
160 }
161
162 /*
163  * rockchip_gem_create_with_handle - allocate an object with the given
164  * size and create a gem handle on it
165  *
166  * returns a struct rockchip_gem_object* on success or ERR_PTR values
167  * on failure.
168  */
169 static struct rockchip_gem_object *
170 rockchip_gem_create_with_handle(struct drm_file *file_priv,
171                                 struct drm_device *drm, unsigned int size,
172                                 unsigned int *handle)
173 {
174         struct rockchip_gem_object *rk_obj;
175         struct drm_gem_object *obj;
176         int ret;
177
178         rk_obj = rockchip_gem_create_object(drm, size, false);
179         if (IS_ERR(rk_obj))
180                 return ERR_CAST(rk_obj);
181
182         obj = &rk_obj->base;
183
184         /*
185          * allocate a id of idr table where the obj is registered
186          * and handle has the id what user can see.
187          */
188         ret = drm_gem_handle_create(file_priv, obj, handle);
189         if (ret)
190                 goto err_handle_create;
191
192         /* drop reference from allocate - handle holds it now. */
193         drm_gem_object_unreference_unlocked(obj);
194
195         return rk_obj;
196
197 err_handle_create:
198         rockchip_gem_free_object(obj);
199
200         return ERR_PTR(ret);
201 }
202
203 int rockchip_gem_dumb_map_offset(struct drm_file *file_priv,
204                                  struct drm_device *dev, uint32_t handle,
205                                  uint64_t *offset)
206 {
207         struct drm_gem_object *obj;
208         int ret;
209
210         obj = drm_gem_object_lookup(dev, file_priv, handle);
211         if (!obj) {
212                 DRM_ERROR("failed to lookup gem object.\n");
213                 return -EINVAL;
214         }
215
216         ret = drm_gem_create_mmap_offset(obj);
217         if (ret)
218                 goto out;
219
220         *offset = drm_vma_node_offset_addr(&obj->vma_node);
221         DRM_DEBUG_KMS("offset = 0x%llx\n", *offset);
222
223 out:
224         drm_gem_object_unreference_unlocked(obj);
225
226         return 0;
227 }
228
229 /*
230  * rockchip_gem_dumb_create - (struct drm_driver)->dumb_create callback
231  * function
232  *
233  * This aligns the pitch and size arguments to the minimum required. wrap
234  * this into your own function if you need bigger alignment.
235  */
236 int rockchip_gem_dumb_create(struct drm_file *file_priv,
237                              struct drm_device *dev,
238                              struct drm_mode_create_dumb *args)
239 {
240         struct rockchip_gem_object *rk_obj;
241         int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
242
243         /*
244          * align to 64 bytes since Mali requires it.
245          */
246         args->pitch = ALIGN(min_pitch, 64);
247         args->size = args->pitch * args->height;
248
249         rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size,
250                                                  &args->handle);
251
252         return PTR_ERR_OR_ZERO(rk_obj);
253 }
254
255 int rockchip_gem_map_offset_ioctl(struct drm_device *drm, void *data,
256                                   struct drm_file *file_priv)
257 {
258         struct drm_rockchip_gem_map_off *args = data;
259
260         return rockchip_gem_dumb_map_offset(file_priv, drm, args->handle,
261                                             &args->offset);
262 }
263
264 int rockchip_gem_create_ioctl(struct drm_device *dev, void *data,
265                               struct drm_file *file_priv)
266 {
267         struct drm_rockchip_gem_create *args = data;
268         struct rockchip_gem_object *rk_obj;
269
270         rk_obj = rockchip_gem_create_with_handle(file_priv, dev, args->size,
271                                                  &args->handle);
272         return PTR_ERR_OR_ZERO(rk_obj);
273 }
274
275 static struct reservation_object *drm_gem_get_resv(struct drm_gem_object *gem)
276 {
277         struct dma_buf *dma_buf = gem->dma_buf;
278         return dma_buf ? dma_buf->resv : NULL;
279 }
280
281 #ifdef CONFIG_DRM_DMA_SYNC
282 static void rockchip_gem_acquire_complete(struct drm_reservation_cb *rcb,
283                                         void *context)
284 {
285         struct completion *compl = context;
286         complete(compl);
287 }
288
289 static int rockchip_gem_acquire(struct drm_device *dev,
290                                 struct rockchip_gem_object *rockchip_gem_obj,
291                                 bool exclusive)
292 {
293         struct fence *fence;
294         struct rockchip_drm_private *dev_priv = dev->dev_private;
295         struct reservation_object *resv =
296                 drm_gem_get_resv(&rockchip_gem_obj->base);
297         int ret = 0;
298         struct drm_reservation_cb rcb;
299         DECLARE_COMPLETION_ONSTACK(compl);
300
301         if (!resv)
302                 return ret;
303
304         if (!exclusive &&
305             !rockchip_gem_obj->acquire_exclusive &&
306             rockchip_gem_obj->acquire_fence) {
307                 atomic_inc(&rockchip_gem_obj->acquire_shared_count);
308                 return ret;
309         }
310
311         fence = drm_sw_fence_new(dev_priv->cpu_fence_context,
312                         atomic_add_return(1, &dev_priv->cpu_fence_seqno));
313         if (IS_ERR(fence)) {
314                 ret = PTR_ERR(fence);
315                 DRM_ERROR("Failed to create acquire fence %d.\n", ret);
316                 return ret;
317         }
318         ww_mutex_lock(&resv->lock, NULL);
319         if (!exclusive) {
320                 ret = reservation_object_reserve_shared(resv);
321                 if (ret < 0) {
322                         DRM_ERROR("Failed to reserve space for shared fence %d.\n",
323                                   ret);
324                         goto resv_unlock;
325                 }
326         }
327         drm_reservation_cb_init(&rcb, rockchip_gem_acquire_complete, &compl);
328         ret = drm_reservation_cb_add(&rcb, resv, exclusive);
329         if (ret < 0) {
330                 DRM_ERROR("Failed to add reservation to callback %d.\n", ret);
331                 goto resv_unlock;
332         }
333         drm_reservation_cb_done(&rcb);
334         if (exclusive)
335                 reservation_object_add_excl_fence(resv, fence);
336         else
337                 reservation_object_add_shared_fence(resv, fence);
338
339         ww_mutex_unlock(&resv->lock);
340         mutex_unlock(&dev->struct_mutex);
341         ret = wait_for_completion_interruptible(&compl);
342         mutex_lock(&dev->struct_mutex);
343         if (ret < 0) {
344                 DRM_ERROR("Failed wait for reservation callback %d.\n", ret);
345                 drm_reservation_cb_fini(&rcb);
346                 /* somebody else may be already waiting on it */
347                 drm_fence_signal_and_put(&fence);
348                 return ret;
349         }
350         rockchip_gem_obj->acquire_fence = fence;
351         rockchip_gem_obj->acquire_exclusive = exclusive;
352         atomic_set(&rockchip_gem_obj->acquire_shared_count, 1);
353         return ret;
354
355 resv_unlock:
356         ww_mutex_unlock(&resv->lock);
357         fence_put(fence);
358         return ret;
359 }
360
361 static void rockchip_gem_release(struct rockchip_gem_object *rockchip_gem_obj)
362 {
363         BUG_ON(!rockchip_gem_obj->acquire_fence);
364         if (atomic_sub_and_test(1,
365                         &rockchip_gem_obj->acquire_shared_count))
366                 drm_fence_signal_and_put(&rockchip_gem_obj->acquire_fence);
367 }
368 #endif
369
370 int rockchip_gem_cpu_acquire_ioctl(struct drm_device *dev, void *data,
371                                    struct drm_file *file)
372 {
373         struct drm_rockchip_gem_cpu_acquire *args = data;
374         struct rockchip_drm_file_private *file_priv = file->driver_priv;
375         struct drm_gem_object *obj;
376         struct rockchip_gem_object *rockchip_gem_obj;
377         struct rockchip_gem_object_node *gem_node;
378         int ret = 0;
379
380         DRM_DEBUG_KMS("[BO:%u] flags: 0x%x\n", args->handle, args->flags);
381
382         mutex_lock(&dev->struct_mutex);
383
384         obj = drm_gem_object_lookup(dev, file, args->handle);
385         if (!obj) {
386                 DRM_ERROR("failed to lookup gem object.\n");
387                 ret = -EINVAL;
388                 goto unlock;
389         }
390
391         rockchip_gem_obj = to_rockchip_obj(obj);
392
393         if (!drm_gem_get_resv(&rockchip_gem_obj->base)) {
394                 /* If there is no reservation object present, there is no
395                  * cross-process/cross-device sharing and sync is unnecessary.
396                  */
397                 ret = 0;
398                 goto unref_obj;
399         }
400
401 #ifdef CONFIG_DRM_DMA_SYNC
402         ret = rockchip_gem_acquire(dev, rockchip_gem_obj,
403                         args->flags & DRM_ROCKCHIP_GEM_CPU_ACQUIRE_EXCLUSIVE);
404         if (ret < 0)
405                 goto unref_obj;
406 #endif
407
408         gem_node = kzalloc(sizeof(*gem_node), GFP_KERNEL);
409         if (!gem_node) {
410                 DRM_ERROR("Failed to allocate rockchip_drm_gem_obj_node.\n");
411                 ret = -ENOMEM;
412                 goto release_sync;
413         }
414
415         gem_node->rockchip_gem_obj = rockchip_gem_obj;
416         list_add(&gem_node->list, &file_priv->gem_cpu_acquire_list);
417         mutex_unlock(&dev->struct_mutex);
418         return 0;
419
420 release_sync:
421 #ifdef CONFIG_DRM_DMA_SYNC
422         rockchip_gem_release(rockchip_gem_obj);
423 #endif
424 unref_obj:
425         drm_gem_object_unreference(obj);
426
427 unlock:
428         mutex_unlock(&dev->struct_mutex);
429         return ret;
430 }
431
432 int rockchip_gem_cpu_release_ioctl(struct drm_device *dev, void *data,
433                                    struct drm_file *file)
434 {
435         struct drm_rockchip_gem_cpu_release *args = data;
436         struct rockchip_drm_file_private *file_priv = file->driver_priv;
437         struct drm_gem_object *obj;
438         struct rockchip_gem_object *rockchip_gem_obj;
439         struct list_head *cur;
440         int ret = 0;
441
442         DRM_DEBUG_KMS("[BO:%u]\n", args->handle);
443
444         mutex_lock(&dev->struct_mutex);
445
446         obj = drm_gem_object_lookup(dev, file, args->handle);
447         if (!obj) {
448                 DRM_ERROR("failed to lookup gem object.\n");
449                 ret = -EINVAL;
450                 goto unlock;
451         }
452
453         rockchip_gem_obj = to_rockchip_obj(obj);
454
455         if (!drm_gem_get_resv(&rockchip_gem_obj->base)) {
456                 /* If there is no reservation object present, there is no
457                  * cross-process/cross-device sharing and sync is unnecessary.
458                  */
459                 ret = 0;
460                 goto unref_obj;
461         }
462
463         list_for_each(cur, &file_priv->gem_cpu_acquire_list) {
464                 struct rockchip_gem_object_node *node = list_entry(
465                                 cur, struct rockchip_gem_object_node, list);
466                 if (node->rockchip_gem_obj == rockchip_gem_obj)
467                         break;
468         }
469         if (cur == &file_priv->gem_cpu_acquire_list) {
470                 DRM_ERROR("gem object not acquired for current process.\n");
471                 ret = -EINVAL;
472                 goto unref_obj;
473         }
474
475 #ifdef CONFIG_DRM_DMA_SYNC
476         rockchip_gem_release(rockchip_gem_obj);
477 #endif
478
479         list_del(cur);
480         kfree(list_entry(cur, struct rockchip_gem_object_node, list));
481         /* unreference for the reference held since cpu_acquire_ioctl */
482         drm_gem_object_unreference(obj);
483         ret = 0;
484
485 unref_obj:
486         /* unreference for the reference from drm_gem_object_lookup() */
487         drm_gem_object_unreference(obj);
488
489 unlock:
490         mutex_unlock(&dev->struct_mutex);
491         return ret;
492 }
493
494 /*
495  * Allocate a sg_table for this GEM object.
496  * Note: Both the table's contents, and the sg_table itself must be freed by
497  *       the caller.
498  * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
499  */
500 struct sg_table *rockchip_gem_prime_get_sg_table(struct drm_gem_object *obj)
501 {
502         struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
503         struct drm_device *drm = obj->dev;
504         struct sg_table *sgt;
505         int ret;
506
507         sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
508         if (!sgt)
509                 return ERR_PTR(-ENOMEM);
510
511         ret = dma_get_sgtable_attrs(drm->dev, sgt, rk_obj->kvaddr,
512                                     rk_obj->dma_addr, obj->size,
513                                     &rk_obj->dma_attrs);
514         if (ret) {
515                 DRM_ERROR("failed to allocate sgt, %d\n", ret);
516                 kfree(sgt);
517                 return ERR_PTR(ret);
518         }
519
520         return sgt;
521 }
522
523 void *rockchip_gem_prime_vmap(struct drm_gem_object *obj)
524 {
525         struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj);
526
527         if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &rk_obj->dma_attrs))
528                 return NULL;
529
530         return rk_obj->kvaddr;
531 }
532
533 void rockchip_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
534 {
535         /* Nothing to do */
536 }