1 /*
2 * drivers/staging/android/ion/rockchip/rockchip_ion.c
3 *
4 * Copyright (C) 2014 ROCKCHIP, 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/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20 #include <linux/dma-buf.h>
21 #include <linux/dma-contiguous.h>
22 #include <linux/of.h>
23 #include <linux/of_reserved_mem.h>
24 #include <linux/rockchip_ion.h>
25
26 #include "../ion_priv.h"
27
28 struct ion_device *rockchip_ion_dev;
29 static struct ion_heap **heaps;
30
31 struct ion_heap_desc {
32 unsigned int id;
33 enum ion_heap_type type;
34 const char *name;
35 };
36
37 static struct ion_heap_desc ion_heap_meta[] = {
38 {
39 .id = ION_HEAP_TYPE_SYSTEM,
40 .type = ION_HEAP_TYPE_SYSTEM,
41 .name = "system-heap",
42 }, {
43 .id = ION_HEAP_TYPE_CARVEOUT,
44 .type = ION_HEAP_TYPE_CARVEOUT,
45 .name = "carveout-heap",
46 }, {
47 .id = ION_HEAP_TYPE_DMA,
48 .type = ION_HEAP_TYPE_DMA,
49 .name = "cma-heap",
50 },
51 };
52
53 /* Return result of step for heap array. */
rk_ion_of_heap(struct ion_platform_heap * myheap,struct device_node * node)54 static int rk_ion_of_heap(struct ion_platform_heap *myheap,
55 struct device_node *node)
56 {
57 unsigned int reg[2] = {0,};
58 int itype;
59
60 for (itype = 0; itype < ARRAY_SIZE(ion_heap_meta); itype++) {
61 if (strcmp(ion_heap_meta[itype].name, node->name))
62 continue;
63
64 myheap->name = node->name;
65 myheap->align = SZ_1M;
66 myheap->id = ion_heap_meta[itype].id;
67 if (!strcmp("cma-heap", node->name)) {
68 myheap->type = ION_HEAP_TYPE_DMA;
69 if (!of_property_read_u32_array(node, "reg", reg, 2)) {
70 myheap->base = reg[0];
71 myheap->size = reg[1];
72 }
73 return 1;
74 }
75
76 if (!strcmp("system-heap", node->name)) {
77 myheap->type = ION_HEAP_TYPE_SYSTEM;
78 return 1;
79 }
80 }
81
82 return 0;
83 }
84
rk_ion_of(struct device_node * node)85 static struct ion_platform_data *rk_ion_of(struct device_node *node)
86 {
87 struct ion_platform_data *pdata;
88 int iheap = 0;
89 struct device_node *child;
90 struct ion_platform_heap *myheap;
91
92 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
93 if (!pdata)
94 return NULL;
95
96 pdata->nr = of_get_child_count(node);
97 again:
98 pdata->heaps = kcalloc(pdata->nr, sizeof(*myheap), GFP_KERNEL);
99 for_each_child_of_node(node, child) {
100 iheap += rk_ion_of_heap(&pdata->heaps[iheap], child);
101 }
102
103 if (pdata->nr != iheap) {
104 pdata->nr = iheap;
105 iheap = 0;
106 kfree(pdata->heaps);
107 pr_err("%s: mismatch, repeating\n", __func__);
108 goto again;
109 }
110
111 return pdata;
112 }
113
rk_ion_probe(struct platform_device * pdev)114 static int rk_ion_probe(struct platform_device *pdev)
115 {
116 int err;
117 int i;
118 struct ion_platform_data *pdata = pdev->dev.platform_data;
119 struct ion_device *idev;
120
121 err = of_reserved_mem_device_init(&pdev->dev);
122 if (err)
123 pr_debug("No reserved memory region assign to ion\n");
124
125 if (!pdata) {
126 pdata = rk_ion_of(pdev->dev.of_node);
127 pdev->dev.platform_data = pdata;
128 }
129
130 heaps = kcalloc(pdata->nr, sizeof(*heaps), GFP_KERNEL);
131
132 idev = ion_device_create(NULL);
133 if (IS_ERR_OR_NULL(idev)) {
134 kfree(heaps);
135 return PTR_ERR(idev);
136 }
137
138 ion_device_set_platform(idev, &pdev->dev);
139 rockchip_ion_dev = idev;
140
141 /* create the heaps as specified in the board file */
142 for (i = 0; i < pdata->nr; i++) {
143 struct ion_platform_heap *heap_data = &pdata->heaps[i];
144
145 heap_data->priv = &pdev->dev;
146 heaps[i] = ion_heap_create(heap_data);
147 if (IS_ERR_OR_NULL(heaps[i])) {
148 err = PTR_ERR(heaps[i]);
149 goto err;
150 }
151 pr_info("rockchip ion: success to create - %s\n",
152 heaps[i]->name);
153 ion_device_add_heap(idev, heaps[i]);
154 }
155 platform_set_drvdata(pdev, idev);
156
157 return 0;
158 err:
159 for (i = 0; i < pdata->nr; i++) {
160 if (heaps[i])
161 ion_heap_destroy(heaps[i]);
162 }
163
164 kfree(heaps);
165 return err;
166 }
167
rk_ion_remove(struct platform_device * pdev)168 static int rk_ion_remove(struct platform_device *pdev)
169 {
170 struct ion_platform_data *pdata = pdev->dev.platform_data;
171 struct ion_device *idev = platform_get_drvdata(pdev);
172 int i;
173
174 ion_device_destroy(idev);
175 for (i = 0; i < pdata->nr; i++)
176 ion_heap_destroy(heaps[i]);
177
178 kfree(heaps);
179 return 0;
180 }
181
rockchip_ion_client_create(const char * name)182 struct ion_client *rockchip_ion_client_create(const char *name)
183 {
184 if (!rockchip_ion_dev) {
185 pr_err("rockchip ion idev is NULL\n");
186 return NULL;
187 }
188
189 return ion_client_create(rockchip_ion_dev, name);
190 }
191 EXPORT_SYMBOL_GPL(rockchip_ion_client_create);
192
193 static const struct of_device_id rk_ion_match[] = {
194 { .compatible = "rockchip,ion", },
195 {}
196 };
197
198 static struct platform_driver ion_driver = {
199 .probe = rk_ion_probe,
200 .remove = rk_ion_remove,
201 .driver = {
202 .name = "ion-rk",
203 .owner = THIS_MODULE,
204 .of_match_table = of_match_ptr(rk_ion_match),
205 },
206 };
207
rk_ion_init(void)208 static int __init rk_ion_init(void)
209 {
210 return platform_driver_register(&ion_driver);
211 }
212
rk_ion_exit(void)213 static void __exit rk_ion_exit(void)
214 {
215 platform_driver_unregister(&ion_driver);
216 }
217
218 subsys_initcall(rk_ion_init);
219 module_exit(rk_ion_exit);
220
221 MODULE_AUTHOR("Meiyou.chen <cmy@rock-chips.com>");
222 MODULE_DESCRIPTION("ROCKCHIP Ion driver");
223 MODULE_LICENSE("GPL v2");
224 MODULE_DEVICE_TABLE(of, rk_ion_match);
225