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