2 * Copyright (c) 2015 MediaTek Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <drm/drm_gem.h>
16 #include <linux/dma-buf.h>
18 #include "mtk_drm_drv.h"
19 #include "mtk_drm_gem.h"
21 static struct mtk_drm_gem_obj
*mtk_drm_gem_init(struct drm_device
*dev
,
24 struct mtk_drm_gem_obj
*mtk_gem_obj
;
27 size
= round_up(size
, PAGE_SIZE
);
29 mtk_gem_obj
= kzalloc(sizeof(*mtk_gem_obj
), GFP_KERNEL
);
31 return ERR_PTR(-ENOMEM
);
33 ret
= drm_gem_object_init(dev
, &mtk_gem_obj
->base
, size
);
35 DRM_ERROR("failed to initialize gem object\n");
43 struct mtk_drm_gem_obj
*mtk_drm_gem_create(struct drm_device
*dev
,
44 size_t size
, bool alloc_kmap
)
46 struct mtk_drm_private
*priv
= dev
->dev_private
;
47 struct mtk_drm_gem_obj
*mtk_gem
;
48 struct drm_gem_object
*obj
;
51 mtk_gem
= mtk_drm_gem_init(dev
, size
);
53 return ERR_CAST(mtk_gem
);
57 mtk_gem
->dma_attrs
= DMA_ATTR_WRITE_COMBINE
;
60 mtk_gem
->dma_attrs
|= DMA_ATTR_NO_KERNEL_MAPPING
;
62 mtk_gem
->cookie
= dma_alloc_attrs(priv
->dma_dev
, obj
->size
,
63 &mtk_gem
->dma_addr
, GFP_KERNEL
,
65 if (!mtk_gem
->cookie
) {
66 DRM_ERROR("failed to allocate %zx byte dma buffer", obj
->size
);
72 mtk_gem
->kvaddr
= mtk_gem
->cookie
;
74 DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n",
75 mtk_gem
->cookie
, &mtk_gem
->dma_addr
,
81 drm_gem_object_release(obj
);
86 void mtk_drm_gem_free_object(struct drm_gem_object
*obj
)
88 struct mtk_drm_gem_obj
*mtk_gem
= to_mtk_gem_obj(obj
);
89 struct mtk_drm_private
*priv
= obj
->dev
->dev_private
;
92 drm_prime_gem_destroy(obj
, mtk_gem
->sg
);
94 dma_free_attrs(priv
->dma_dev
, obj
->size
, mtk_gem
->cookie
,
95 mtk_gem
->dma_addr
, mtk_gem
->dma_attrs
);
97 /* release file pointer to gem object. */
98 drm_gem_object_release(obj
);
103 int mtk_drm_gem_dumb_create(struct drm_file
*file_priv
, struct drm_device
*dev
,
104 struct drm_mode_create_dumb
*args
)
106 struct mtk_drm_gem_obj
*mtk_gem
;
109 args
->pitch
= DIV_ROUND_UP(args
->width
* args
->bpp
, 8);
110 args
->size
= args
->pitch
* args
->height
;
112 mtk_gem
= mtk_drm_gem_create(dev
, args
->size
, false);
114 return PTR_ERR(mtk_gem
);
117 * allocate a id of idr table where the obj is registered
118 * and handle has the id what user can see.
120 ret
= drm_gem_handle_create(file_priv
, &mtk_gem
->base
, &args
->handle
);
122 goto err_handle_create
;
124 /* drop reference from allocate - handle holds it now. */
125 drm_gem_object_unreference_unlocked(&mtk_gem
->base
);
130 mtk_drm_gem_free_object(&mtk_gem
->base
);
134 int mtk_drm_gem_dumb_map_offset(struct drm_file
*file_priv
,
135 struct drm_device
*dev
, uint32_t handle
,
138 struct drm_gem_object
*obj
;
141 obj
= drm_gem_object_lookup(file_priv
, handle
);
143 DRM_ERROR("failed to lookup gem object.\n");
147 ret
= drm_gem_create_mmap_offset(obj
);
151 *offset
= drm_vma_node_offset_addr(&obj
->vma_node
);
152 DRM_DEBUG_KMS("offset = 0x%llx\n", *offset
);
155 drm_gem_object_unreference_unlocked(obj
);
159 static int mtk_drm_gem_object_mmap(struct drm_gem_object
*obj
,
160 struct vm_area_struct
*vma
)
164 struct mtk_drm_gem_obj
*mtk_gem
= to_mtk_gem_obj(obj
);
165 struct mtk_drm_private
*priv
= obj
->dev
->dev_private
;
168 * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear
169 * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
171 vma
->vm_flags
&= ~VM_PFNMAP
;
174 ret
= dma_mmap_attrs(priv
->dma_dev
, vma
, mtk_gem
->cookie
,
175 mtk_gem
->dma_addr
, obj
->size
, mtk_gem
->dma_attrs
);
177 drm_gem_vm_close(vma
);
182 int mtk_drm_gem_mmap_buf(struct drm_gem_object
*obj
, struct vm_area_struct
*vma
)
186 ret
= drm_gem_mmap_obj(obj
, obj
->size
, vma
);
190 return mtk_drm_gem_object_mmap(obj
, vma
);
193 int mtk_drm_gem_mmap(struct file
*filp
, struct vm_area_struct
*vma
)
195 struct drm_gem_object
*obj
;
198 ret
= drm_gem_mmap(filp
, vma
);
202 obj
= vma
->vm_private_data
;
204 return mtk_drm_gem_object_mmap(obj
, vma
);
208 * Allocate a sg_table for this GEM object.
209 * Note: Both the table's contents, and the sg_table itself must be freed by
211 * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
213 struct sg_table
*mtk_gem_prime_get_sg_table(struct drm_gem_object
*obj
)
215 struct mtk_drm_gem_obj
*mtk_gem
= to_mtk_gem_obj(obj
);
216 struct mtk_drm_private
*priv
= obj
->dev
->dev_private
;
217 struct sg_table
*sgt
;
220 sgt
= kzalloc(sizeof(*sgt
), GFP_KERNEL
);
222 return ERR_PTR(-ENOMEM
);
224 ret
= dma_get_sgtable_attrs(priv
->dma_dev
, sgt
, mtk_gem
->cookie
,
225 mtk_gem
->dma_addr
, obj
->size
,
228 DRM_ERROR("failed to allocate sgt, %d\n", ret
);
236 struct drm_gem_object
*mtk_gem_prime_import_sg_table(struct drm_device
*dev
,
237 struct dma_buf_attachment
*attach
, struct sg_table
*sg
)
239 struct mtk_drm_gem_obj
*mtk_gem
;
241 struct scatterlist
*s
;
245 mtk_gem
= mtk_drm_gem_init(dev
, attach
->dmabuf
->size
);
248 return ERR_PTR(PTR_ERR(mtk_gem
));
250 expected
= sg_dma_address(sg
->sgl
);
251 for_each_sg(sg
->sgl
, s
, sg
->nents
, i
) {
252 if (sg_dma_address(s
) != expected
) {
253 DRM_ERROR("sg_table is not contiguous");
257 expected
= sg_dma_address(s
) + sg_dma_len(s
);
260 mtk_gem
->dma_addr
= sg_dma_address(sg
->sgl
);
263 return &mtk_gem
->base
;