48c76eef0e8772f5bc9f0a210eafadcaf70175b0
[firefly-linux-kernel-4.4.55.git] / drivers / staging / android / ion / rockchip / rockchip_ion.c
1 /*
2  * drivers/gpu/rockchip/rockchip_ion.c
3  *
4  * Copyright (C) 2011 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
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
17 #include <linux/err.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20 #include <linux/rockchip_ion.h>
21 #include <linux/uaccess.h>
22 #include "../ion_priv.h"
23 #include <linux/dma-buf.h>
24 #include <asm-generic/dma-contiguous.h>
25
26 #ifdef CONFIG_OF
27 #include <linux/of.h>
28 #include <linux/of_gpio.h>
29 #include <video/of_display_timing.h>
30 #include <linux/of_fdt.h>
31 #endif
32
33 static struct ion_device *idev;
34 static int num_heaps;
35 static struct ion_heap **heaps;
36
37 struct ion_heap_desc {
38         unsigned int id;
39         enum ion_heap_type type;
40         const char *name;
41 };
42
43 extern struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
44                                                 int id);
45 extern int ion_handle_put(struct ion_handle *handle);
46
47 static struct ion_heap_desc ion_heap_meta[] = {
48         {
49                 .id             = ION_SYSTEM_HEAP_ID,
50                 .type   = ION_HEAP_TYPE_SYSTEM,
51                 .name   = ION_SYSTEM_HEAP_NAME,
52         },
53         {
54                 .id             = ION_CMA_HEAP_ID,
55                 .type   = ION_HEAP_TYPE_DMA,
56                 .name   = ION_CMA_HEAP_NAME,
57         },
58         {
59                 .id             = ION_IOMMU_HEAP_ID,
60                 .type   = ION_HEAP_TYPE_DMA,//ION_HEAP_TYPE_IOMMU,
61                 .name   = ION_IOMMU_HEAP_NAME,
62         },
63         {
64                 .id     = ION_DRM_HEAP_ID,
65                 .type   = ION_HEAP_TYPE_DMA,
66                 .name   = ION_DRM_HEAP_NAME,
67         },
68 };
69
70 struct device rockchip_ion_cma_dev = {
71         .coherent_dma_mask = DMA_BIT_MASK(32),
72         .init_name = "rockchip_ion_cma",
73 };
74
75 static int rockchip_ion_populate_heap(struct ion_platform_heap *heap)
76 {
77         unsigned int i;
78         int ret = -EINVAL;
79         unsigned int len = ARRAY_SIZE(ion_heap_meta);
80         for (i = 0; i < len; ++i) {
81                 if (ion_heap_meta[i].id == heap->id) {
82                         heap->name = ion_heap_meta[i].name;
83                         heap->type = ion_heap_meta[i].type;
84                         if(heap->id == ION_CMA_HEAP_ID)
85                                 heap->priv = &rockchip_ion_cma_dev;
86                         ret = 0;
87                         break;
88                 }
89         }
90         if (ret)
91                 pr_err("%s: Unable to populate heap, error: %d", __func__, ret);
92         return ret;
93 }
94
95 static int rockchip_ion_get_heap_size(struct device_node *node,
96                                  struct ion_platform_heap *heap)
97 {
98         unsigned int val;
99         int ret = 0;
100
101         ret = of_property_read_u32(node, "rockchip,memory-reservation-size", &val);
102         if (!ret) {
103                 heap->size = val;
104         } else {
105                 ret = 0;
106         }
107
108         return ret;
109 }
110
111 static struct ion_platform_data *rockchip_ion_parse_dt(
112                                         struct device *dev)
113 {
114         struct device_node *dt_node = dev->of_node;
115         struct ion_platform_data *pdata = 0;
116         struct device_node *node;
117         uint32_t val = 0;
118         int ret = 0;
119         uint32_t num_heaps = 0;
120         int idx = 0;
121
122         for_each_child_of_node(dt_node, node)
123                 num_heaps++;
124
125         pr_info("%s: num_heaps = %d\n", __func__, num_heaps);
126         
127         if (!num_heaps)
128                 return ERR_PTR(-EINVAL);
129
130         pdata = kzalloc(sizeof(struct ion_platform_data) +
131                         num_heaps*sizeof(struct ion_platform_heap), GFP_KERNEL);
132         if (!pdata)
133                 return ERR_PTR(-ENOMEM);
134         pdata->heaps = (struct ion_platform_heap*)((void*)pdata+sizeof(struct ion_platform_data));
135         pdata->nr = num_heaps;
136         
137         for_each_child_of_node(dt_node, node) {
138                 ret = of_property_read_u32(node, "reg", &val);
139                 if (ret) {
140                         pr_err("%s: Unable to find reg key", __func__);
141                         goto free_heaps;
142                 }
143                 pdata->heaps[idx].id = val;
144
145                 ret = rockchip_ion_populate_heap(&pdata->heaps[idx]);
146                 if (ret)
147                         goto free_heaps;
148
149 //              rockchip_ion_get_heap_align(node, &pdata->heaps[idx]);
150                 ret = rockchip_ion_get_heap_size(node, &pdata->heaps[idx]);
151                 if (ret)
152                         goto free_heaps;
153
154 //              rockchip_ion_get_heap_adjacent(node, &pdata->heaps[idx]);
155                 pr_info("%d:  %d  %d  %s  0x%p\n", idx, pdata->heaps[idx].type, pdata->heaps[idx].id, pdata->heaps[idx].name, pdata->heaps[idx].priv);
156
157                 ++idx;
158         }
159
160         return pdata;
161
162 free_heaps:
163         kfree(pdata);
164         return ERR_PTR(ret);
165 }
166
167 #ifdef CONFIG_CMA
168
169 // struct "cma" quoted from drivers/base/dma-contiguous.c
170 struct cma {
171         unsigned long   base_pfn;
172         unsigned long   count;
173         unsigned long   *bitmap;
174 };
175
176 // struct "ion_cma_heap" quoted from drivers/staging/android/ion/ion_cma_heap.c
177 struct ion_cma_heap {
178         struct ion_heap heap;
179         struct device *dev;
180 };
181
182 static int ion_cma_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
183                                       void *unused)
184 {
185         struct ion_cma_heap *cma_heap = container_of(heap,
186                                                         struct ion_cma_heap,
187                                                         heap);
188         struct device *dev = cma_heap->dev;
189         struct cma *cma = dev_get_cma_area(dev);
190         int i;
191         int rows = cma->count/(SZ_1M >> PAGE_SHIFT);
192         phys_addr_t base = __pfn_to_phys(cma->base_pfn);
193
194         seq_printf(s, "Heap bitmap:\n");
195
196         for(i = rows - 1; i>= 0; i--){
197                 seq_printf(s, "%.4uM@0x%08x: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
198                                 i+1, base+(i)*SZ_1M,
199                                 cma->bitmap[i*8 + 7],
200                                 cma->bitmap[i*8 + 6],
201                                 cma->bitmap[i*8 + 5],
202                                 cma->bitmap[i*8 + 4],
203                                 cma->bitmap[i*8 + 3],
204                                 cma->bitmap[i*8 + 2],
205                                 cma->bitmap[i*8 + 1],
206                                 cma->bitmap[i*8]);
207         }
208         seq_printf(s, "Heap size: %luM, Heap base: 0x%08x\n",
209                 (cma->count)>>8, base);
210
211         return 0;
212 }
213
214 #endif
215
216 struct ion_client *rockchip_ion_client_create(const char *name)
217 {
218         return ion_client_create(idev, name);
219 }
220 EXPORT_SYMBOL(rockchip_ion_client_create);
221
222 static long rockchip_custom_ioctl (struct ion_client *client, unsigned int cmd,
223                               unsigned long arg)
224 {
225         pr_debug("[%s %d] cmd=%X\n", __func__, __LINE__, cmd);
226
227         switch (cmd) {
228         case ION_IOC_CLEAN_CACHES:
229         case ION_IOC_INV_CACHES:
230         case ION_IOC_CLEAN_INV_CACHES:
231                 break;
232         case ION_IOC_GET_PHYS:
233         {
234                 struct ion_phys_data data;
235                 struct ion_handle *handle;
236                 int ret;
237                 
238                 if (copy_from_user(&data, (void __user *)arg,
239                                         sizeof(struct ion_phys_data)))
240                         return -EFAULT;
241
242                 handle = ion_handle_get_by_id(client, data.handle);
243                 if (IS_ERR(handle))
244                         return PTR_ERR(handle);
245
246                 ret = ion_phys(client, handle, &data.phys, (size_t *)&data.size);
247                 pr_debug("ret=%d, phys=0x%lX\n", ret, data.phys);
248                 ion_handle_put(handle);
249                 if(ret < 0)
250                         return ret;
251                 if (copy_to_user((void __user *)arg, &data, sizeof(struct ion_phys_data)))
252                         return -EFAULT;
253                 break;
254         }
255         case ION_IOC_GET_SHARE_ID:
256         {
257                 struct ion_share_id_data data;
258                 struct dma_buf *dmabuf = NULL;
259
260                 if (copy_from_user(&data, (void __user *)arg,
261                                         sizeof(struct ion_share_id_data)))
262                         return -EFAULT;
263
264                 dmabuf = dma_buf_get(data.fd);
265                 if (IS_ERR(dmabuf))
266                         return PTR_ERR(dmabuf);
267
268                 data.id = (unsigned int)dmabuf;
269 //              dma_buf_put(dmabuf);
270
271                 if (copy_to_user((void __user *)arg, &data, sizeof(struct ion_share_id_data)))
272                         return -EFAULT;
273
274                 break;
275         }
276         case ION_IOC_SHARE_BY_ID:
277         {
278                 struct ion_share_id_data data;
279                 int fd = 0;
280
281                 if (copy_from_user(&data, (void __user *)arg,
282                                         sizeof(struct ion_share_id_data)))
283                         return -EFAULT;
284
285                 fd = dma_buf_fd((struct dma_buf*)data.id, O_CLOEXEC);
286                 if (fd < 0)
287                         return fd;
288
289                 data.fd = fd;
290
291                 if (copy_to_user((void __user *)arg, &data, sizeof(struct ion_share_id_data)))
292                         return -EFAULT;
293
294                 break;
295         }
296         default:
297                 return -ENOTTY;
298         }
299         
300         return 0;
301 }
302
303 static int rockchip_ion_probe(struct platform_device *pdev)
304 {
305         struct ion_platform_data *pdata;
306         unsigned int pdata_needs_to_be_freed;
307         int err;
308         int i;
309
310         if (pdev->dev.of_node) {
311                 pdata = rockchip_ion_parse_dt(&pdev->dev);
312                 if (IS_ERR(pdata)) {
313                         return PTR_ERR(pdata);
314                 }
315                 pdata_needs_to_be_freed = 1;
316         } else {
317                 pdata = pdev->dev.platform_data;
318                 pdata_needs_to_be_freed = 0;
319         }
320
321         num_heaps = pdata->nr;
322         heaps = kzalloc(sizeof(struct ion_heap *) * num_heaps, GFP_KERNEL);
323
324         idev = ion_device_create(rockchip_custom_ioctl);
325         if (IS_ERR_OR_NULL(idev)) {
326                 kfree(heaps);
327                 return PTR_ERR(idev);
328         }
329         /* create the heaps as specified in the board file */
330         for (i = 0; i < num_heaps; i++) {
331                 struct ion_platform_heap *heap_data = &pdata->heaps[i];
332
333                 heaps[i] = ion_heap_create(heap_data);
334                 if (IS_ERR_OR_NULL(heaps[i])) {
335                         err = PTR_ERR(heaps[i]);
336                         goto err;
337                 }
338 #ifdef CONFIG_CMA
339                 if (ION_HEAP_TYPE_DMA==heap_data->type)
340                         heaps[i]->debug_show = ion_cma_heap_debug_show;
341 #endif
342                 ion_device_add_heap(idev, heaps[i]);
343         }
344         platform_set_drvdata(pdev, idev);
345         if (pdata_needs_to_be_freed)
346                 kfree(pdata);
347
348         pr_info("Rockchip ion module is successfully loaded\n");
349         return 0;
350 err:
351         for (i = 0; i < num_heaps; i++) {
352                 if (heaps[i])
353                 ion_heap_destroy(heaps[i]);
354         }
355         if (pdata_needs_to_be_freed)
356                 kfree(pdata);
357         kfree(heaps);
358         return err;
359 }
360
361 static int rockchip_ion_remove(struct platform_device *pdev)
362 {
363         struct ion_device *idev = platform_get_drvdata(pdev);
364         int i;
365
366         ion_device_destroy(idev);
367         for (i = 0; i < num_heaps; i++)
368                 ion_heap_destroy(heaps[i]);
369         kfree(heaps);
370         return 0;
371 }
372
373 int __init rockchip_ion_find_reserve_mem(unsigned long node, const char *uname,
374                                 int depth, void *data)
375 {
376 #ifdef CONFIG_CMA
377         __be32 *prop;
378         unsigned long len;
379         phys_addr_t size;
380         phys_addr_t base;
381
382         if (!of_flat_dt_is_compatible(node, "rockchip,ion-reserve"))
383                 return 0;
384
385         prop = of_get_flat_dt_prop(node, "memory-reservation", &len);
386         if (!prop || (len != 2 * sizeof(unsigned long)))
387                 return 0;
388
389         base = be32_to_cpu(prop[0]);
390         size = be32_to_cpu(prop[1]);
391
392         pr_info("%s: reserve cma memory: %x %x\n", __func__, base, size);
393
394         dma_declare_contiguous(&rockchip_ion_cma_dev, size, base, 0);
395 #endif
396
397         return 1;
398 }
399
400 static const struct of_device_id rockchip_ion_dt_ids[] = {
401         { .compatible = "rockchip,ion", },
402         {}
403 };
404
405 static struct platform_driver ion_driver = {
406         .probe = rockchip_ion_probe,
407         .remove = rockchip_ion_remove,
408         .driver = {
409                 .name = "ion-rockchip",
410                 .owner  = THIS_MODULE,
411                 .of_match_table = of_match_ptr(rockchip_ion_dt_ids),
412         },
413 };
414
415 static int __init ion_init(void)
416 {
417         return platform_driver_register(&ion_driver);
418 }
419
420 static void __exit ion_exit(void)
421 {
422         platform_driver_unregister(&ion_driver);
423 }
424
425 subsys_initcall(ion_init);
426 module_exit(ion_exit);
427