Merge branch 'p-ti-android-3.8.y-video'
[android-sdk/kernel-video.git] / drivers / gpu / ion / omap / omap_ion.c
1 /*
2  * drivers/gpu/omap/omap_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  */
17 #include <linux/err.h>
18 #include <linux/ion.h>
19 #include <linux/omap_ion.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/uaccess.h>
23 #include "../ion_priv.h"
24 #include "omap_ion_priv.h"
25 #include <linux/module.h>
26 #include <linux/of.h>
29 struct ion_device *omap_ion_device;
30 EXPORT_SYMBOL(omap_ion_device);
32 static int num_heaps;
33 static struct ion_heap **heaps;
34 static struct ion_heap *tiler_heap;
35 static struct ion_heap *nonsecure_tiler_heap;
37 static struct ion_platform_data omap_ion_data = {
38         .nr = 5,
39         .heaps = {
40                 {
41                         .type = ION_HEAP_TYPE_CARVEOUT,
42                         .id = OMAP_ION_HEAP_SECURE_INPUT,
43                         .name = "secure_input",
44                 },
45                 {       .type = OMAP_ION_HEAP_TYPE_TILER,
46                         .id = OMAP_ION_HEAP_TILER,
47                         .name = "tiler",
48                 },
49                 {
50                         .type = OMAP_ION_HEAP_TYPE_TILER,
51                         .id = OMAP_ION_HEAP_NONSECURE_TILER,
52                         .name = "nonsecure_tiler",
53                 },
54                 {
55                         .type = ION_HEAP_TYPE_SYSTEM,
56                         .id = OMAP_ION_HEAP_SYSTEM,
57                         .name = "system",
58                 },
59                 {
60                         .type = OMAP_ION_HEAP_TYPE_TILER_RESERVATION,
61                         .id = OMAP_ION_HEAP_TILER_RESERVATION,
62                         .name = "tiler_reservation",
63                 },
64         },
65 };
68 int omap_ion_tiler_alloc(struct ion_client *client,
69                          struct omap_ion_tiler_alloc_data *data)
70 {
71         return omap_tiler_alloc(tiler_heap, client, data);
72 }
73 EXPORT_SYMBOL(omap_ion_tiler_alloc);
75 int omap_ion_nonsecure_tiler_alloc(struct ion_client *client,
76                          struct omap_ion_tiler_alloc_data *data)
77 {
78         if (!nonsecure_tiler_heap)
79                 return -ENOMEM;
80         return omap_tiler_alloc(nonsecure_tiler_heap, client, data);
81 }
82 EXPORT_SYMBOL(omap_ion_nonsecure_tiler_alloc);
84 static long omap_ion_ioctl(struct ion_client *client, unsigned int cmd,
85                     unsigned long arg)
86 {
87         switch (cmd) {
88         case OMAP_ION_TILER_ALLOC:
89         {
90                 struct omap_ion_tiler_alloc_data data;
91                 int ret;
93                 if (!tiler_heap) {
94                         pr_err("%s: Tiler heap requested but no tiler heap "
95                                         "exists on this platform\n", __func__);
96                         return -EINVAL;
97                 }
98                 if (copy_from_user(&data, (void __user *)arg, sizeof(data)))
99                         return -EFAULT;
100                 ret = omap_ion_tiler_alloc(client, &data);
101                 if (ret)
102                         return ret;
103                 if (copy_to_user((void __user *)arg, &data,
104                                  sizeof(data)))
105                         return -EFAULT;
106                 break;
107         }
108         default:
109                 pr_err("%s: Unknown custom ioctl\n", __func__);
110                 return -ENOTTY;
111         }
112         return 0;
115 static int omap_ion_probe(struct platform_device *pdev)
117         int err;
118         int i;
119         struct device_node *node = pdev->dev.of_node;
120         uint omap_ion_heap_secure_input_base = 0;
121         uint omap_ion_heap_tiler_base = 0;
122         uint omap_ion_heap_nonsecure_tiler_base = 0;
123         uint omap_ion_heap_secure_input_size = 0;
124         uint omap_ion_heap_tiler_size = 0;
125         uint omap_ion_heap_nonsecure_tiler_size = 0;
126         
127         if (node) {
128                 of_property_read_u32(node, "ti,omap_ion_heap_secure_input_base",
129                                      &omap_ion_heap_secure_input_base);
130                 of_property_read_u32(node, "ti,omap_ion_heap_tiler_base",
131                                      &omap_ion_heap_tiler_base);
132                 of_property_read_u32(node, "ti,omap_ion_heap_nonsecure_tiler_base",
133                                      &omap_ion_heap_nonsecure_tiler_base);
134                 if (omap_ion_heap_secure_input_base == 0
135                         || omap_ion_heap_tiler_base == 0
136                         || omap_ion_heap_nonsecure_tiler_base == 0) {
137                         pr_err("%s: carveout memory address is null. please check dts file\n"
138                                 "omap_ion_heap_secure_input_base = 0x%x\n"
139                                 "omap_ion_heap_tiler_base = 0x%x\n"
140                                 "omap_ion_heap_nonsecure_tiler_base = 0x%x\n"
141                                 , __func__
142                                 , omap_ion_heap_secure_input_base
143                                 , omap_ion_heap_tiler_base
144                                 , omap_ion_heap_tiler_base);
145                         return -EFAULT;
146                 }
148                 of_property_read_u32(node, "ti,omap_ion_heap_secure_input_size",
149                                      &omap_ion_heap_secure_input_size);
150                 of_property_read_u32(node, "ti,omap_ion_heap_tiler_size",
151                                      &omap_ion_heap_tiler_size);
152                 of_property_read_u32(node, "ti,omap_ion_heap_nonsecure_tiler_size",
153                                      &omap_ion_heap_nonsecure_tiler_size);
154                 if (omap_ion_heap_secure_input_size == 0
155                         || omap_ion_heap_tiler_size == 0
156                         || omap_ion_heap_nonsecure_tiler_size == 0) {
157                         pr_err("%s: carveout memory address is null. please check dts file\n"
158                                 "omap_ion_heap_secure_input_size = 0x%x\n"
159                                 "omap_ion_heap_tiler_size = 0x%x\n"
160                                 "omap_ion_heap_nonsecure_tiler_size = 0x%x\n"
161                                 , __func__
162                                 , omap_ion_heap_secure_input_size
163                                 , omap_ion_heap_tiler_size
164                                 , omap_ion_heap_nonsecure_tiler_size);
165                         return -EINVAL;
166                 }
168         } else {
169                 pr_err("%s: no matching device tree node\n", __func__);
170                 return -ENODEV;
171         }
173         omap_ion_device = ion_device_create(omap_ion_ioctl);
174         if (IS_ERR_OR_NULL(omap_ion_device))
175                 return PTR_ERR(omap_ion_device);
178         num_heaps = omap_ion_data.nr;
180         heaps = kzalloc(sizeof(struct ion_heap *)*num_heaps, GFP_KERNEL);
181         
183         for (i = 0; i < num_heaps; i++) {
184                 struct ion_platform_heap *heap_data = &omap_ion_data.heaps[i];
185                 if (heap_data->type == (enum ion_heap_type)OMAP_ION_HEAP_TYPE_TILER) {
186                         if (heap_data->id == OMAP_ION_HEAP_NONSECURE_TILER) {
187                                 heap_data->base = omap_ion_heap_nonsecure_tiler_base;
188                                 heap_data->size = omap_ion_heap_nonsecure_tiler_size;
189                         } else {
190                                 heap_data->base = omap_ion_heap_tiler_base;
191                                 heap_data->size = omap_ion_heap_tiler_size;
192                         }
193                 } else if (heap_data->type ==
194                                 ION_HEAP_TYPE_CARVEOUT && heap_data->id == OMAP_ION_HEAP_SECURE_INPUT) {
195                         heap_data->base = omap_ion_heap_secure_input_base;
196                         heap_data->size = omap_ion_heap_secure_input_size;
197                 }
198         }
200         /* create the heaps as specified in the board file */
201         for (i = 0; i < num_heaps; i++) {
202                 struct ion_platform_heap *heap_data = &omap_ion_data.heaps[i];
203                 if (heap_data->type == (enum ion_heap_type)OMAP_ION_HEAP_TYPE_TILER) {
204                         heaps[i] = omap_tiler_heap_create(heap_data);
205                         if (heap_data->id == OMAP_ION_HEAP_NONSECURE_TILER)
206                                 nonsecure_tiler_heap = heaps[i];
207                         else
208                                 tiler_heap = heaps[i];
209                 } else if (heap_data->type ==
210                                 (enum ion_heap_type)OMAP_ION_HEAP_TYPE_TILER_RESERVATION) {
211                         heaps[i] = omap_tiler_heap_create(heap_data);
212                 } else {
213                         heap_data->size = omap_ion_heap_secure_input_size;
214                         heaps[i] = ion_heap_create(heap_data);
215                 }
216                 if (IS_ERR_OR_NULL(heaps[i])) {
217                         err = PTR_ERR(heaps[i]);
218                         goto err;
219                 }
220                 ion_device_add_heap(omap_ion_device, heaps[i]);
221                 pr_info("%s: adding heap %s of type %d with %lx@%x\n",
222                         __func__, heap_data->name, heap_data->type,
223                         heap_data->base, heap_data->size);
225         }
227         platform_set_drvdata(pdev, omap_ion_device);
228         return 0;
229 err:
230         for (i = 0; i < num_heaps; i++) {
231                 if (heaps[i]) {
232                         if (heaps[i]->type == (enum ion_heap_type)OMAP_ION_HEAP_TYPE_TILER)
233                                 omap_tiler_heap_destroy(heaps[i]);
234                         else
235                                 ion_heap_destroy(heaps[i]);
236                 }
237         }
238         kfree(heaps);
239         return err;
242 static int omap_ion_remove(struct platform_device *pdev)
244         struct ion_device *idev = platform_get_drvdata(pdev);
245         int i;
247         ion_device_destroy(idev);
248         for (i = 0; i < num_heaps; i++)
249                 if (heaps[i]->type == (enum ion_heap_type)OMAP_ION_HEAP_TYPE_TILER)
250                         omap_tiler_heap_destroy(heaps[i]);
251                 else
252                         ion_heap_destroy(heaps[i]);
253         kfree(heaps);
254         return 0;
257 static void (*export_fd_to_ion_handles)(int fd,
258                 struct ion_client **client,
259                 struct ion_handle **handles,
260                 int *num_handles);
262 void omap_ion_register_pvr_export(void *pvr_export_fd)
264         export_fd_to_ion_handles = pvr_export_fd;
266 EXPORT_SYMBOL(omap_ion_register_pvr_export);
268 int omap_ion_share_fd_to_buffers(int fd, struct ion_buffer **buffers,
269                 int *num_handles)
271         struct ion_handle **handles;
272         struct ion_client *client;
273         int i = 0, ret = 0;
274         int share_fd;
276         handles = kzalloc(*num_handles * sizeof(struct ion_handle *),
277                           GFP_KERNEL);
278         if (!handles)
279                 return -ENOMEM;
281         if (export_fd_to_ion_handles) {
282                 export_fd_to_ion_handles(fd,
283                                 &client,
284                                 handles,
285                                 num_handles);
286         } else {
287                 pr_err("%s: export_fd_to_ion_handles not initialized",
288                                 __func__);
289                 ret = -EINVAL;
290                 goto exit;
291         }
293         for (i = 0; i < *num_handles; i++) {
294                 if (handles[i])
295                         share_fd = ion_share_dma_buf(client, handles[i]);
296                         buffers[i] = ion_handle_buffer(handles[i]);
297         }
299 exit:
300         kfree(handles);
301         return ret;
303 EXPORT_SYMBOL(omap_ion_share_fd_to_buffers);
305 static const struct of_device_id omap_ion_of_match[] = {
306         {.compatible = "ti,ion-omap", },
307         { },
308 };
311 static struct platform_driver ion_driver = {
312         .probe = omap_ion_probe,
313         .remove = omap_ion_remove,
314         .driver = { .name = "ion-omap",
315                                 .of_match_table = omap_ion_of_match
316         }
317 };
319 static int __init ion_init(void)
321         return platform_driver_register(&ion_driver);
324 static void __exit ion_exit(void)
326         platform_driver_unregister(&ion_driver);
329 module_init(ion_init);
330 module_exit(ion_exit);