Merge branch develop-3.10
[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 <linux/dma-contiguous.h>
25 #include <linux/memblock.h>
26
27 #ifdef CONFIG_OF
28 #include <linux/of.h>
29 #include <linux/of_gpio.h>
30 #include <video/of_display_timing.h>
31 #include <linux/of_fdt.h>
32 #endif
33
34 struct ion_device *rockchip_ion_dev;
35 EXPORT_SYMBOL(rockchip_ion_dev);
36
37 static int num_heaps;
38 static struct ion_heap **heaps;
39
40 struct ion_heap_desc {
41         unsigned int id;
42         enum ion_heap_type type;
43         const char *name;
44 };
45
46 extern struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
47                                                 int id);
48 extern int ion_handle_put(struct ion_handle *handle);
49
50 #define ION_CMA_HEAP_NAME               "cma"
51 #define ION_IOMMU_HEAP_NAME             "iommu"
52 #define ION_VMALLOC_HEAP_NAME           "vmalloc"
53 #define ION_DRM_HEAP_NAME               "drm"
54 #define ION_CARVEOUT_HEAP_NAME          "carveout"
55
56 #define MAX_ION_HEAP            10
57
58 static struct ion_platform_heap ion_plat_heap[MAX_ION_HEAP];
59 struct ion_platform_data ion_pdata = {
60         .nr = 0,
61         .heaps = ion_plat_heap,
62 };
63
64 static struct ion_heap_desc ion_heap_meta[] = {
65         {
66                 .id     = ION_VMALLOC_HEAP_ID,
67                 .type   = ION_HEAP_TYPE_SYSTEM,
68                 .name   = ION_VMALLOC_HEAP_NAME,
69         },
70         {
71                 .id     = ION_CMA_HEAP_ID,
72                 .type   = ION_HEAP_TYPE_DMA,
73                 .name   = ION_CMA_HEAP_NAME,
74         },
75         {
76                 .id     = ION_DRM_HEAP_ID,
77                 .type   = ION_HEAP_TYPE_DRM,
78                 .name   = ION_DRM_HEAP_NAME,
79         },
80         {
81                 .id     = ION_CARVEOUT_HEAP_ID,
82                 .type   = ION_HEAP_TYPE_CARVEOUT,
83                 .name   = ION_CARVEOUT_HEAP_NAME,
84         },
85 };
86
87 struct device rockchip_ion_cma_dev = {
88         .coherent_dma_mask = DMA_BIT_MASK(32),
89         .init_name = "rockchip_ion_cma",
90 };
91
92 static int rockchip_ion_populate_heap(struct ion_platform_heap *heap)
93 {
94         unsigned int i;
95         int ret = -EINVAL;
96         unsigned int len = ARRAY_SIZE(ion_heap_meta);
97         for (i = 0; i < len; ++i) {
98                 if (ion_heap_meta[i].id == heap->id) {
99                         heap->name = ion_heap_meta[i].name;
100                         heap->type = ion_heap_meta[i].type;
101                         if(heap->id == ION_CMA_HEAP_ID)
102                                 heap->priv = &rockchip_ion_cma_dev;
103                         ret = 0;
104                         break;
105                 }
106         }
107         if (ret)
108                 pr_err("%s: Unable to populate heap, error: %d", __func__, ret);
109         return ret;
110 }
111
112 struct ion_client *rockchip_ion_client_create(const char *name)
113 {
114         return ion_client_create(rockchip_ion_dev, name);
115 }
116 EXPORT_SYMBOL(rockchip_ion_client_create);
117
118 static long rockchip_custom_ioctl (struct ion_client *client, unsigned int cmd,
119                               unsigned long arg)
120 {
121         pr_debug("[%s %d] cmd=%X\n", __func__, __LINE__, cmd);
122
123         switch (cmd) {
124         case ION_IOC_GET_PHYS:
125         {
126                 struct ion_phys_data data;
127                 struct ion_handle *handle;
128                 int ret;
129                 
130                 if (copy_from_user(&data, (void __user *)arg,
131                                         sizeof(struct ion_phys_data)))
132                         return -EFAULT;
133
134                 handle = ion_handle_get_by_id(client, data.handle);
135                 if (IS_ERR(handle))
136                         return PTR_ERR(handle);
137
138                 ret = ion_phys(client, handle, &data.phys, (size_t *)&data.size);
139                 pr_debug("ret=%d, phys=0x%lX\n", ret, data.phys);
140                 ion_handle_put(handle);
141                 if(ret < 0)
142                         return ret;
143                 if (copy_to_user((void __user *)arg, &data, sizeof(struct ion_phys_data)))
144                         return -EFAULT;
145                 break;
146         }
147         default:
148                 return -ENOTTY;
149         }
150         
151         return 0;
152 }
153
154 static int rockchip_ion_probe(struct platform_device *pdev)
155 {
156         struct ion_platform_data *pdata;
157         struct ion_device *idev;
158         int err;
159         int i;
160
161         err = device_register(&rockchip_ion_cma_dev);
162         if (err) {
163                 pr_err("Could not register %s\n", dev_name(&rockchip_ion_cma_dev));
164                 return err;
165         }
166
167         if (pdev->dev.of_node) {
168                 pdata = &ion_pdata;
169                 if (IS_ERR(pdata)) {
170                         return PTR_ERR(pdata);
171                 }
172         } else {
173                 pdata = pdev->dev.platform_data;
174         }
175
176         num_heaps = pdata->nr;
177         heaps = kzalloc(sizeof(struct ion_heap *) * num_heaps, GFP_KERNEL);
178
179         idev = ion_device_create(rockchip_custom_ioctl);
180         if (IS_ERR_OR_NULL(idev)) {
181                 kfree(heaps);
182                 return PTR_ERR(idev);
183         }
184         rockchip_ion_dev = idev;
185         /* create the heaps as specified in the board file */
186         for (i = 0; i < num_heaps; i++) {
187                 struct ion_platform_heap *heap_data = &pdata->heaps[i];
188
189                 heaps[i] = ion_heap_create(heap_data);
190                 if (IS_ERR_OR_NULL(heaps[i])) {
191                         err = PTR_ERR(heaps[i]);
192                         goto err;
193                 }
194                 ion_device_add_heap(idev, heaps[i]);
195         }
196         platform_set_drvdata(pdev, idev);
197
198         pr_info("Rockchip ion module is successfully loaded (%s)\n", ROCKCHIP_ION_VERSION);
199         return 0;
200 err:
201         for (i = 0; i < num_heaps; i++) {
202                 if (heaps[i])
203                 ion_heap_destroy(heaps[i]);
204         }
205         kfree(heaps);
206         return err;
207 }
208
209 static int rockchip_ion_remove(struct platform_device *pdev)
210 {
211         struct ion_device *idev = platform_get_drvdata(pdev);
212         int i;
213
214         ion_device_destroy(idev);
215         for (i = 0; i < num_heaps; i++)
216                 ion_heap_destroy(heaps[i]);
217         kfree(heaps);
218         return 0;
219 }
220
221 int __init rockchip_ion_find_heap(unsigned long node, const char *uname,
222                                 int depth, void *data)
223 {
224         const __be32 *prop;
225         int len;
226         struct ion_platform_heap* heap;
227         struct ion_platform_data* pdata = (struct ion_platform_data*)data;
228
229         if (pdata==NULL || pdata->nr >= MAX_ION_HEAP) {
230                 // break now
231                 pr_err("ion heap is too much!\n");
232                 return 1;
233         }
234
235         if (!of_flat_dt_is_compatible(node, "rockchip,ion-heap"))
236                 return 0;
237
238         prop = of_get_flat_dt_prop(node, "rockchip,ion_heap", &len);
239         if (!prop || (len != sizeof(__be32)))
240                 return 0;
241
242         heap = &pdata->heaps[pdata->nr++];
243         heap->base = heap->size = heap->align = 0;
244         heap->id = be32_to_cpu(prop[0]);
245         rockchip_ion_populate_heap(heap);
246
247         prop = of_get_flat_dt_prop(node, "reg", &len);
248         if (prop && (len >= 2*sizeof(__be32))) {
249                 heap->base = be32_to_cpu(prop[0]);
250                 heap->size = be32_to_cpu(prop[1]);
251                 if (len==3*sizeof(__be32))
252                         heap->align = be32_to_cpu(prop[2]);
253         }
254
255         pr_info("ion heap(%s): base(%lx) size(%zx) align(%lx)\n", heap->name,
256                         heap->base, heap->size, heap->align);
257         return 0;
258 }
259
260 static const struct of_device_id rockchip_ion_dt_ids[] = {
261         { .compatible = "rockchip,ion", },
262         {}
263 };
264
265 static struct platform_driver ion_driver = {
266         .probe = rockchip_ion_probe,
267         .remove = rockchip_ion_remove,
268         .driver = {
269                 .name = "ion-rockchip",
270                 .owner  = THIS_MODULE,
271                 .of_match_table = of_match_ptr(rockchip_ion_dt_ids),
272         },
273 };
274
275 static int __init ion_init(void)
276 {
277         return platform_driver_register(&ion_driver);
278 }
279
280 static void __exit ion_exit(void)
281 {
282         platform_driver_unregister(&ion_driver);
283 }
284
285 subsys_initcall(ion_init);
286 module_exit(ion_exit);
287