11c248b7dSInki Dae /* exynos_drm_gem.c
21c248b7dSInki Dae  *
31c248b7dSInki Dae  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
41c248b7dSInki Dae  * Author: Inki Dae <inki.dae@samsung.com>
51c248b7dSInki Dae  *
61c248b7dSInki Dae  * Permission is hereby granted, free of charge, to any person obtaining a
71c248b7dSInki Dae  * copy of this software and associated documentation files (the "Software"),
81c248b7dSInki Dae  * to deal in the Software without restriction, including without limitation
91c248b7dSInki Dae  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101c248b7dSInki Dae  * and/or sell copies of the Software, and to permit persons to whom the
111c248b7dSInki Dae  * Software is furnished to do so, subject to the following conditions:
121c248b7dSInki Dae  *
131c248b7dSInki Dae  * The above copyright notice and this permission notice (including the next
141c248b7dSInki Dae  * paragraph) shall be included in all copies or substantial portions of the
151c248b7dSInki Dae  * Software.
161c248b7dSInki Dae  *
171c248b7dSInki Dae  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181c248b7dSInki Dae  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191c248b7dSInki Dae  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
201c248b7dSInki Dae  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
211c248b7dSInki Dae  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
221c248b7dSInki Dae  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
231c248b7dSInki Dae  * OTHER DEALINGS IN THE SOFTWARE.
241c248b7dSInki Dae  */
251c248b7dSInki Dae 
261c248b7dSInki Dae #include "drmP.h"
271c248b7dSInki Dae #include "drm.h"
281c248b7dSInki Dae 
291c248b7dSInki Dae #include <drm/exynos_drm.h>
301c248b7dSInki Dae 
311c248b7dSInki Dae #include "exynos_drm_drv.h"
321c248b7dSInki Dae #include "exynos_drm_gem.h"
331c248b7dSInki Dae #include "exynos_drm_buf.h"
341c248b7dSInki Dae 
351c248b7dSInki Dae static unsigned int convert_to_vm_err_msg(int msg)
361c248b7dSInki Dae {
371c248b7dSInki Dae 	unsigned int out_msg;
381c248b7dSInki Dae 
391c248b7dSInki Dae 	switch (msg) {
401c248b7dSInki Dae 	case 0:
411c248b7dSInki Dae 	case -ERESTARTSYS:
421c248b7dSInki Dae 	case -EINTR:
431c248b7dSInki Dae 		out_msg = VM_FAULT_NOPAGE;
441c248b7dSInki Dae 		break;
451c248b7dSInki Dae 
461c248b7dSInki Dae 	case -ENOMEM:
471c248b7dSInki Dae 		out_msg = VM_FAULT_OOM;
481c248b7dSInki Dae 		break;
491c248b7dSInki Dae 
501c248b7dSInki Dae 	default:
511c248b7dSInki Dae 		out_msg = VM_FAULT_SIGBUS;
521c248b7dSInki Dae 		break;
531c248b7dSInki Dae 	}
541c248b7dSInki Dae 
551c248b7dSInki Dae 	return out_msg;
561c248b7dSInki Dae }
571c248b7dSInki Dae 
58ee5e770eSJoonyoung Shim static struct exynos_drm_gem_obj *
59ee5e770eSJoonyoung Shim exynos_drm_gem_init(struct drm_device *drm_dev, struct drm_file *file_priv,
60ee5e770eSJoonyoung Shim 		    unsigned int *handle, unsigned int size)
611c248b7dSInki Dae {
621c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj;
631c248b7dSInki Dae 	struct drm_gem_object *obj;
641c248b7dSInki Dae 	int ret;
651c248b7dSInki Dae 
661c248b7dSInki Dae 	exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL);
671c248b7dSInki Dae 	if (!exynos_gem_obj) {
681c248b7dSInki Dae 		DRM_ERROR("failed to allocate exynos gem object.\n");
691c248b7dSInki Dae 		return ERR_PTR(-ENOMEM);
701c248b7dSInki Dae 	}
711c248b7dSInki Dae 
721c248b7dSInki Dae 	obj = &exynos_gem_obj->base;
731c248b7dSInki Dae 
74f088d5a9SInki Dae 	ret = drm_gem_object_init(drm_dev, obj, size);
751c248b7dSInki Dae 	if (ret < 0) {
76f088d5a9SInki Dae 		DRM_ERROR("failed to initialize gem object.\n");
77f088d5a9SInki Dae 		ret = -EINVAL;
78ee5e770eSJoonyoung Shim 		goto err;
791c248b7dSInki Dae 	}
801c248b7dSInki Dae 
811c248b7dSInki Dae 	DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
821c248b7dSInki Dae 
831c248b7dSInki Dae 	/*
841c248b7dSInki Dae 	 * allocate a id of idr table where the obj is registered
851c248b7dSInki Dae 	 * and handle has the id what user can see.
861c248b7dSInki Dae 	 */
871c248b7dSInki Dae 	ret = drm_gem_handle_create(file_priv, obj, handle);
881c248b7dSInki Dae 	if (ret)
892d91cf17SJoonyoung Shim 		goto err_release;
901c248b7dSInki Dae 
911c248b7dSInki Dae 	DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
921c248b7dSInki Dae 
931c248b7dSInki Dae 	/* drop reference from allocate - handle holds it now. */
941c248b7dSInki Dae 	drm_gem_object_unreference_unlocked(obj);
951c248b7dSInki Dae 
961c248b7dSInki Dae 	return exynos_gem_obj;
971c248b7dSInki Dae 
98ee5e770eSJoonyoung Shim err_release:
991c248b7dSInki Dae 	drm_gem_object_release(obj);
1001c248b7dSInki Dae 
101ee5e770eSJoonyoung Shim err:
1021c248b7dSInki Dae 	kfree(exynos_gem_obj);
1031c248b7dSInki Dae 	return ERR_PTR(ret);
1041c248b7dSInki Dae }
1051c248b7dSInki Dae 
106f088d5a9SInki Dae struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
107f088d5a9SInki Dae 						 struct drm_file *file_priv,
108ee5e770eSJoonyoung Shim 						 unsigned int *handle,
109ee5e770eSJoonyoung Shim 						 unsigned long size)
110f088d5a9SInki Dae {
111f088d5a9SInki Dae 
112ee5e770eSJoonyoung Shim 	struct exynos_drm_gem_obj *exynos_gem_obj;
1132c871127SInki Dae 	struct exynos_drm_gem_buf *buffer;
114f088d5a9SInki Dae 
115f088d5a9SInki Dae 	size = roundup(size, PAGE_SIZE);
116f088d5a9SInki Dae 	DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size);
117f088d5a9SInki Dae 
1182c871127SInki Dae 	buffer = exynos_drm_buf_create(dev, size);
119ee5e770eSJoonyoung Shim 	if (!buffer)
120ee5e770eSJoonyoung Shim 		return ERR_PTR(-ENOMEM);
121f088d5a9SInki Dae 
122f088d5a9SInki Dae 	exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size);
123f088d5a9SInki Dae 	if (IS_ERR(exynos_gem_obj)) {
124ca22e3ccSSeung-Woo Kim 		exynos_drm_buf_destroy(dev, buffer);
125ca22e3ccSSeung-Woo Kim 		return exynos_gem_obj;
126f088d5a9SInki Dae 	}
127f088d5a9SInki Dae 
1282c871127SInki Dae 	exynos_gem_obj->buffer = buffer;
129f088d5a9SInki Dae 
130f088d5a9SInki Dae 	return exynos_gem_obj;
131f088d5a9SInki Dae }
132f088d5a9SInki Dae 
1331c248b7dSInki Dae int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
1341c248b7dSInki Dae 				struct drm_file *file_priv)
1351c248b7dSInki Dae {
1361c248b7dSInki Dae 	struct drm_exynos_gem_create *args = data;
137ee5e770eSJoonyoung Shim 	struct exynos_drm_gem_obj *exynos_gem_obj;
1381c248b7dSInki Dae 
139f088d5a9SInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
1401c248b7dSInki Dae 
141ee5e770eSJoonyoung Shim 	exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle,
142ee5e770eSJoonyoung Shim 			args->size);
1431c248b7dSInki Dae 	if (IS_ERR(exynos_gem_obj))
1441c248b7dSInki Dae 		return PTR_ERR(exynos_gem_obj);
1451c248b7dSInki Dae 
1461c248b7dSInki Dae 	return 0;
1471c248b7dSInki Dae }
1481c248b7dSInki Dae 
1491c248b7dSInki Dae int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
1501c248b7dSInki Dae 				    struct drm_file *file_priv)
1511c248b7dSInki Dae {
1521c248b7dSInki Dae 	struct drm_exynos_gem_map_off *args = data;
1531c248b7dSInki Dae 
1541c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
1551c248b7dSInki Dae 
1561c248b7dSInki Dae 	DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
1571c248b7dSInki Dae 			args->handle, (unsigned long)args->offset);
1581c248b7dSInki Dae 
1591c248b7dSInki Dae 	if (!(dev->driver->driver_features & DRIVER_GEM)) {
1601c248b7dSInki Dae 		DRM_ERROR("does not support GEM.\n");
1611c248b7dSInki Dae 		return -ENODEV;
1621c248b7dSInki Dae 	}
1631c248b7dSInki Dae 
1641c248b7dSInki Dae 	return exynos_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
1651c248b7dSInki Dae 			&args->offset);
1661c248b7dSInki Dae }
1671c248b7dSInki Dae 
1681c248b7dSInki Dae static int exynos_drm_gem_mmap_buffer(struct file *filp,
1691c248b7dSInki Dae 				      struct vm_area_struct *vma)
1701c248b7dSInki Dae {
1711c248b7dSInki Dae 	struct drm_gem_object *obj = filp->private_data;
1721c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
1732c871127SInki Dae 	struct exynos_drm_gem_buf *buffer;
1741c248b7dSInki Dae 	unsigned long pfn, vm_size;
1751c248b7dSInki Dae 
1761c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
1771c248b7dSInki Dae 
1781c248b7dSInki Dae 	vma->vm_flags |= (VM_IO | VM_RESERVED);
1791c248b7dSInki Dae 
1801c248b7dSInki Dae 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
1811c248b7dSInki Dae 	vma->vm_file = filp;
1821c248b7dSInki Dae 
1831c248b7dSInki Dae 	vm_size = vma->vm_end - vma->vm_start;
1841c248b7dSInki Dae 	/*
1852c871127SInki Dae 	 * a buffer contains information to physically continuous memory
1861c248b7dSInki Dae 	 * allocated by user request or at framebuffer creation.
1871c248b7dSInki Dae 	 */
1882c871127SInki Dae 	buffer = exynos_gem_obj->buffer;
1891c248b7dSInki Dae 
1901c248b7dSInki Dae 	/* check if user-requested size is valid. */
1912c871127SInki Dae 	if (vm_size > buffer->size)
1921c248b7dSInki Dae 		return -EINVAL;
1931c248b7dSInki Dae 
1941c248b7dSInki Dae 	/*
1951c248b7dSInki Dae 	 * get page frame number to physical memory to be mapped
1961c248b7dSInki Dae 	 * to user space.
1971c248b7dSInki Dae 	 */
1982c871127SInki Dae 	pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT;
1991c248b7dSInki Dae 
2001c248b7dSInki Dae 	DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn);
2011c248b7dSInki Dae 
2021c248b7dSInki Dae 	if (remap_pfn_range(vma, vma->vm_start, pfn, vm_size,
2031c248b7dSInki Dae 				vma->vm_page_prot)) {
2041c248b7dSInki Dae 		DRM_ERROR("failed to remap pfn range.\n");
2051c248b7dSInki Dae 		return -EAGAIN;
2061c248b7dSInki Dae 	}
2071c248b7dSInki Dae 
2081c248b7dSInki Dae 	return 0;
2091c248b7dSInki Dae }
2101c248b7dSInki Dae 
2111c248b7dSInki Dae static const struct file_operations exynos_drm_gem_fops = {
2121c248b7dSInki Dae 	.mmap = exynos_drm_gem_mmap_buffer,
2131c248b7dSInki Dae };
2141c248b7dSInki Dae 
2151c248b7dSInki Dae int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
2161c248b7dSInki Dae 			      struct drm_file *file_priv)
2171c248b7dSInki Dae {
2181c248b7dSInki Dae 	struct drm_exynos_gem_mmap *args = data;
2191c248b7dSInki Dae 	struct drm_gem_object *obj;
2201c248b7dSInki Dae 	unsigned int addr;
2211c248b7dSInki Dae 
2221c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
2231c248b7dSInki Dae 
2241c248b7dSInki Dae 	if (!(dev->driver->driver_features & DRIVER_GEM)) {
2251c248b7dSInki Dae 		DRM_ERROR("does not support GEM.\n");
2261c248b7dSInki Dae 		return -ENODEV;
2271c248b7dSInki Dae 	}
2281c248b7dSInki Dae 
2291c248b7dSInki Dae 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
2301c248b7dSInki Dae 	if (!obj) {
2311c248b7dSInki Dae 		DRM_ERROR("failed to lookup gem object.\n");
2321c248b7dSInki Dae 		return -EINVAL;
2331c248b7dSInki Dae 	}
2341c248b7dSInki Dae 
2351c248b7dSInki Dae 	obj->filp->f_op = &exynos_drm_gem_fops;
2361c248b7dSInki Dae 	obj->filp->private_data = obj;
2371c248b7dSInki Dae 
2381c248b7dSInki Dae 	down_write(&current->mm->mmap_sem);
2391c248b7dSInki Dae 	addr = do_mmap(obj->filp, 0, args->size,
2401c248b7dSInki Dae 			PROT_READ | PROT_WRITE, MAP_SHARED, 0);
2411c248b7dSInki Dae 	up_write(&current->mm->mmap_sem);
2421c248b7dSInki Dae 
2431c248b7dSInki Dae 	drm_gem_object_unreference_unlocked(obj);
2441c248b7dSInki Dae 
2451c248b7dSInki Dae 	if (IS_ERR((void *)addr))
2461c248b7dSInki Dae 		return PTR_ERR((void *)addr);
2471c248b7dSInki Dae 
2481c248b7dSInki Dae 	args->mapped = addr;
2491c248b7dSInki Dae 
2501c248b7dSInki Dae 	DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
2511c248b7dSInki Dae 
2521c248b7dSInki Dae 	return 0;
2531c248b7dSInki Dae }
2541c248b7dSInki Dae 
2551c248b7dSInki Dae int exynos_drm_gem_init_object(struct drm_gem_object *obj)
2561c248b7dSInki Dae {
2571c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
2581c248b7dSInki Dae 
2591c248b7dSInki Dae 	return 0;
2601c248b7dSInki Dae }
2611c248b7dSInki Dae 
262ee5e770eSJoonyoung Shim void exynos_drm_gem_free_object(struct drm_gem_object *obj)
2631c248b7dSInki Dae {
2641c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj;
2651c248b7dSInki Dae 
2661c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
2671c248b7dSInki Dae 
2681c248b7dSInki Dae 	DRM_DEBUG_KMS("handle count = %d\n",
269ee5e770eSJoonyoung Shim 			atomic_read(&obj->handle_count));
2701c248b7dSInki Dae 
271ee5e770eSJoonyoung Shim 	if (obj->map_list.map)
272ee5e770eSJoonyoung Shim 		drm_gem_free_mmap_offset(obj);
2731c248b7dSInki Dae 
2741c248b7dSInki Dae 	/* release file pointer to gem object. */
275ee5e770eSJoonyoung Shim 	drm_gem_object_release(obj);
2761c248b7dSInki Dae 
277ee5e770eSJoonyoung Shim 	exynos_gem_obj = to_exynos_gem_obj(obj);
2781c248b7dSInki Dae 
279ee5e770eSJoonyoung Shim 	exynos_drm_buf_destroy(obj->dev, exynos_gem_obj->buffer);
2801c248b7dSInki Dae 
2811c248b7dSInki Dae 	kfree(exynos_gem_obj);
2821c248b7dSInki Dae }
2831c248b7dSInki Dae 
2841c248b7dSInki Dae int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
285ee5e770eSJoonyoung Shim 			       struct drm_device *dev,
286ee5e770eSJoonyoung Shim 			       struct drm_mode_create_dumb *args)
2871c248b7dSInki Dae {
2881c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj;
2891c248b7dSInki Dae 
2901c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
2911c248b7dSInki Dae 
2921c248b7dSInki Dae 	/*
2931c248b7dSInki Dae 	 * alocate memory to be used for framebuffer.
2941c248b7dSInki Dae 	 * - this callback would be called by user application
2951c248b7dSInki Dae 	 *	with DRM_IOCTL_MODE_CREATE_DUMB command.
2961c248b7dSInki Dae 	 */
2971c248b7dSInki Dae 
2981c248b7dSInki Dae 	args->pitch = args->width * args->bpp >> 3;
2991c248b7dSInki Dae 	args->size = args->pitch * args->height;
3001c248b7dSInki Dae 
301f088d5a9SInki Dae 	exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle,
302f088d5a9SInki Dae 			args->size);
3031c248b7dSInki Dae 	if (IS_ERR(exynos_gem_obj))
3041c248b7dSInki Dae 		return PTR_ERR(exynos_gem_obj);
3051c248b7dSInki Dae 
3061c248b7dSInki Dae 	return 0;
3071c248b7dSInki Dae }
3081c248b7dSInki Dae 
3091c248b7dSInki Dae int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
310ee5e770eSJoonyoung Shim 				   struct drm_device *dev, uint32_t handle,
311ee5e770eSJoonyoung Shim 				   uint64_t *offset)
3121c248b7dSInki Dae {
3131c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj;
3141c248b7dSInki Dae 	struct drm_gem_object *obj;
3152d91cf17SJoonyoung Shim 	int ret = 0;
3161c248b7dSInki Dae 
3171c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
3181c248b7dSInki Dae 
3191c248b7dSInki Dae 	mutex_lock(&dev->struct_mutex);
3201c248b7dSInki Dae 
3211c248b7dSInki Dae 	/*
3221c248b7dSInki Dae 	 * get offset of memory allocated for drm framebuffer.
3231c248b7dSInki Dae 	 * - this callback would be called by user application
3241c248b7dSInki Dae 	 *	with DRM_IOCTL_MODE_MAP_DUMB command.
3251c248b7dSInki Dae 	 */
3261c248b7dSInki Dae 
3271c248b7dSInki Dae 	obj = drm_gem_object_lookup(dev, file_priv, handle);
3281c248b7dSInki Dae 	if (!obj) {
3291c248b7dSInki Dae 		DRM_ERROR("failed to lookup gem object.\n");
3302d91cf17SJoonyoung Shim 		ret = -EINVAL;
3312d91cf17SJoonyoung Shim 		goto unlock;
3321c248b7dSInki Dae 	}
3331c248b7dSInki Dae 
3341c248b7dSInki Dae 	exynos_gem_obj = to_exynos_gem_obj(obj);
3351c248b7dSInki Dae 
3362d91cf17SJoonyoung Shim 	if (!exynos_gem_obj->base.map_list.map) {
3372d91cf17SJoonyoung Shim 		ret = drm_gem_create_mmap_offset(&exynos_gem_obj->base);
3382d91cf17SJoonyoung Shim 		if (ret)
3392d91cf17SJoonyoung Shim 			goto out;
3402d91cf17SJoonyoung Shim 	}
3411c248b7dSInki Dae 
3422d91cf17SJoonyoung Shim 	*offset = (u64)exynos_gem_obj->base.map_list.hash.key << PAGE_SHIFT;
3431c248b7dSInki Dae 	DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
3441c248b7dSInki Dae 
3452d91cf17SJoonyoung Shim out:
3462d91cf17SJoonyoung Shim 	drm_gem_object_unreference(obj);
3472d91cf17SJoonyoung Shim unlock:
3481c248b7dSInki Dae 	mutex_unlock(&dev->struct_mutex);
3492d91cf17SJoonyoung Shim 	return ret;
3501c248b7dSInki Dae }
3511c248b7dSInki Dae 
352ee5e770eSJoonyoung Shim int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
353ee5e770eSJoonyoung Shim 				struct drm_device *dev,
354ee5e770eSJoonyoung Shim 				unsigned int handle)
355ee5e770eSJoonyoung Shim {
356ee5e770eSJoonyoung Shim 	int ret;
357ee5e770eSJoonyoung Shim 
358ee5e770eSJoonyoung Shim 	DRM_DEBUG_KMS("%s\n", __FILE__);
359ee5e770eSJoonyoung Shim 
360ee5e770eSJoonyoung Shim 	/*
361ee5e770eSJoonyoung Shim 	 * obj->refcount and obj->handle_count are decreased and
362ee5e770eSJoonyoung Shim 	 * if both them are 0 then exynos_drm_gem_free_object()
363ee5e770eSJoonyoung Shim 	 * would be called by callback to release resources.
364ee5e770eSJoonyoung Shim 	 */
365ee5e770eSJoonyoung Shim 	ret = drm_gem_handle_delete(file_priv, handle);
366ee5e770eSJoonyoung Shim 	if (ret < 0) {
367ee5e770eSJoonyoung Shim 		DRM_ERROR("failed to delete drm_gem_handle.\n");
368ee5e770eSJoonyoung Shim 		return ret;
369ee5e770eSJoonyoung Shim 	}
370ee5e770eSJoonyoung Shim 
371ee5e770eSJoonyoung Shim 	return 0;
372ee5e770eSJoonyoung Shim }
373ee5e770eSJoonyoung Shim 
3741c248b7dSInki Dae int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
3751c248b7dSInki Dae {
3761c248b7dSInki Dae 	struct drm_gem_object *obj = vma->vm_private_data;
3771c248b7dSInki Dae 	struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
3781c248b7dSInki Dae 	struct drm_device *dev = obj->dev;
3791c248b7dSInki Dae 	unsigned long pfn;
3801c248b7dSInki Dae 	pgoff_t page_offset;
3811c248b7dSInki Dae 	int ret;
3821c248b7dSInki Dae 
3831c248b7dSInki Dae 	page_offset = ((unsigned long)vmf->virtual_address -
3841c248b7dSInki Dae 			vma->vm_start) >> PAGE_SHIFT;
3851c248b7dSInki Dae 
3861c248b7dSInki Dae 	mutex_lock(&dev->struct_mutex);
3871c248b7dSInki Dae 
3882c871127SInki Dae 	pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >>
3892c871127SInki Dae 			PAGE_SHIFT) + page_offset;
3901c248b7dSInki Dae 
3911c248b7dSInki Dae 	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
3921c248b7dSInki Dae 
3931c248b7dSInki Dae 	mutex_unlock(&dev->struct_mutex);
3941c248b7dSInki Dae 
3951c248b7dSInki Dae 	return convert_to_vm_err_msg(ret);
3961c248b7dSInki Dae }
3971c248b7dSInki Dae 
3981c248b7dSInki Dae int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
3991c248b7dSInki Dae {
4001c248b7dSInki Dae 	int ret;
4011c248b7dSInki Dae 
4021c248b7dSInki Dae 	DRM_DEBUG_KMS("%s\n", __FILE__);
4031c248b7dSInki Dae 
4041c248b7dSInki Dae 	/* set vm_area_struct. */
4051c248b7dSInki Dae 	ret = drm_gem_mmap(filp, vma);
4061c248b7dSInki Dae 	if (ret < 0) {
4071c248b7dSInki Dae 		DRM_ERROR("failed to mmap.\n");
4081c248b7dSInki Dae 		return ret;
4091c248b7dSInki Dae 	}
4101c248b7dSInki Dae 
4111c248b7dSInki Dae 	vma->vm_flags &= ~VM_PFNMAP;
4121c248b7dSInki Dae 	vma->vm_flags |= VM_MIXEDMAP;
4131c248b7dSInki Dae 
4141c248b7dSInki Dae 	return ret;
4151c248b7dSInki Dae }
4161c248b7dSInki Dae 
4171c248b7dSInki Dae MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
4181c248b7dSInki Dae MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
4191c248b7dSInki Dae MODULE_LICENSE("GPL");
420