tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / gpu / drm / sprd / sprd_drm_buf.c
1 /* sprd_drm_buf.c
2  *
3  * Copyright (c) 2014 Spreadtrum Communications, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include "drmP.h"
17 #include "drm.h"
18 #include "sprd_drm.h"
19 #include "video/ion_sprd.h"
20 #include "sprd_drm_drv.h"
21 #include "sprd_drm_gem.h"
22 #include "sprd_drm_buf.h"
23
24 static int lowlevel_buffer_allocate(struct drm_device *dev,
25                 unsigned int flags, struct sprd_drm_gem_buf *buf)
26 {
27         struct scatterlist *sg = NULL;
28         struct sprd_drm_private *private;
29         unsigned int nr_pages = 0, i = 0, heap_id_mask;
30         unsigned long sgt_size = 0;
31         int ret = 0, mem_flags = 0;
32
33         DRM_DEBUG_KMS("%s\n", __FILE__);
34
35         if (buf->dma_addr) {
36                 DRM_DEBUG_KMS("already allocated.\n");
37                 return 0;
38         }
39
40         buf->page_size = buf->size;
41         private = dev->dev_private;
42         DRM_DEBUG_KMS("sprd_drm_ion_client:%p size:0x%x\n",
43                         private->sprd_drm_ion_client,buf->size);
44
45         if (IS_DEV_SYSTEM_BUFFER(flags))
46                 heap_id_mask = ION_HEAP_ID_MASK_SYSTEM;
47         else if (IS_DEV_MM_BUFFER(flags))
48                 heap_id_mask = ION_HEAP_ID_MASK_MM;
49         else if (IS_DEV_OVERLAY_BUFFER(flags))
50                 heap_id_mask = ION_HEAP_ID_MASK_OVERLAY;
51         else if (IS_DEV_GSP_BUFFER(flags))
52                 heap_id_mask = ION_HEAP_ID_MASK_GSP;
53         else
54                 heap_id_mask = ION_HEAP_ID_MASK_OVERLAY;
55
56 #ifdef CONFIG_SPRD_IOMMU
57         if (IS_NONCONTIG_BUFFER(flags)) {
58                 if (heap_id_mask == ION_HEAP_ID_MASK_MM)
59                         heap_id_mask = ION_HEAP_ID_MASK_MM_IOMMU;
60                 else if (heap_id_mask == ION_HEAP_ID_MASK_GSP)
61                         heap_id_mask = ION_HEAP_ID_MASK_GSP_IOMMU;
62                 else
63                         heap_id_mask = ION_HEAP_ID_MASK_SYSTEM;
64         }
65 #endif
66
67         if (IS_CACHABLE_BUFFER(flags))
68                 mem_flags = ION_FLAG_CACHED;
69
70         buf->ion_handle = ion_alloc(private->sprd_drm_ion_client, buf->size,
71                         SZ_4K, heap_id_mask, mem_flags);
72
73         if (IS_ERR((void *)buf->ion_handle)) {
74                 DRM_ERROR("%s Could not allocate\n", __func__);
75                 return -ENOMEM;
76         }
77         buf->sgt = ion_sg_table(private->sprd_drm_ion_client, buf->ion_handle);
78         if (!buf->sgt) {
79                 DRM_ERROR("failed to get sg table.\n");
80                 ret = -ENOMEM;
81                 goto err;
82         }
83
84         buf->dma_addr = sg_dma_address(buf->sgt->sgl);
85         if (!buf->dma_addr) {
86                 DRM_ERROR("failed to get dma addr.\n");
87                 ret = -EINVAL;
88                 goto err;
89         }
90         for_each_sg(buf->sgt->sgl, sg, buf->sgt->nents, i)
91                 nr_pages++;
92
93         sgt_size = sizeof(struct page) * nr_pages;
94         buf->pages = kzalloc(sgt_size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY);
95         if (!buf->pages) {
96                 unsigned int order;
97                 order = get_order(sgt_size);
98                 DRM_INFO("%s:sglist kzalloc failed: order:%d, trying vzalloc\n",
99                                         __func__, order);
100                 buf->pages = vzalloc(sgt_size);
101                 if (!buf->pages) {
102                         DRM_ERROR("failed to allocate pages.\n");
103                         ret = -ENOMEM;
104                         goto err;
105                 }
106         }
107
108         for_each_sg(buf->sgt->sgl, sg, buf->sgt->nents, i) {
109                 buf->pages[i] = phys_to_page(sg_dma_address(sg));
110                 buf->page_size = sg_dma_len(sg);
111         }
112
113         DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
114                         (unsigned long)buf->dma_addr,
115                         buf->size);
116
117         return ret;
118 err:
119         ion_free(private->sprd_drm_ion_client, buf->ion_handle);
120         buf->dma_addr = (dma_addr_t)NULL;
121         buf->sgt = NULL;
122
123         return ret;
124 }
125
126 static void lowlevel_buffer_deallocate(struct drm_device *dev,
127                 unsigned int flags, struct sprd_drm_gem_buf *buf)
128 {
129         struct sprd_drm_private *private;
130
131         private = dev->dev_private;
132         DRM_DEBUG_KMS("%s.\n", __FILE__);
133
134         if (is_vmalloc_addr(buf->pages))
135                 vfree(buf->pages);
136         else
137                 kfree(buf->pages);
138         buf->pages = NULL;
139
140         ion_free(private->sprd_drm_ion_client, buf->ion_handle);
141
142         buf->dma_addr = (dma_addr_t)NULL;
143         buf->sgt = NULL;
144 }
145
146 struct sprd_drm_gem_buf *sprd_drm_init_buf(struct drm_device *dev,
147                                                 unsigned int size)
148 {
149         struct sprd_drm_gem_buf *buffer;
150
151         DRM_DEBUG_KMS("%s.\n", __FILE__);
152         DRM_DEBUG_KMS("desired size = 0x%x\n", size);
153
154         buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
155         if (!buffer) {
156                 DRM_ERROR("failed to allocate sprd_drm_gem_buf.\n");
157                 return NULL;
158         }
159
160         buffer->size = size;
161         return buffer;
162 }
163
164 void sprd_drm_fini_buf(struct drm_device *dev,
165                                 struct sprd_drm_gem_buf *buffer)
166 {
167         DRM_DEBUG_KMS("%s.\n", __FILE__);
168
169         if (!buffer) {
170                 DRM_DEBUG_KMS("buffer is null.\n");
171                 return;
172         }
173
174         kfree(buffer);
175         buffer = NULL;
176 }
177
178 int sprd_drm_alloc_buf(struct drm_device *dev,
179                 struct sprd_drm_gem_buf *buf, unsigned int flags)
180 {
181
182         /*
183          * allocate memory region and set the memory information
184          * to vaddr and dma_addr of a buffer object.
185          */
186         if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
187                 return -ENOMEM;
188
189         return 0;
190 }
191
192 void sprd_drm_free_buf(struct drm_device *dev,
193                 unsigned int flags, struct sprd_drm_gem_buf *buffer)
194 {
195         lowlevel_buffer_deallocate(dev, flags, buffer);
196 }