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;
113 }
115 static int omap_ion_probe(struct platform_device *pdev)
116 {
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;
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);
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;
240 }
242 static int omap_ion_remove(struct platform_device *pdev)
243 {
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;
255 }
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)
263 {
264 export_fd_to_ion_handles = pvr_export_fd;
265 }
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)
270 {
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;
302 }
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)
320 {
321 return platform_driver_register(&ion_driver);
322 }
324 static void __exit ion_exit(void)
325 {
326 platform_driver_unregister(&ion_driver);
327 }
329 module_init(ion_init);
330 module_exit(ion_exit);