• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Based on work from:
3  *   Andrew Andrianov <andrew@ncrmnt.org>
4  *   Google
5  *   The Linux Foundation
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <linux/init.h>
13 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15 #include <linux/of.h>
16 #include <linux/of_platform.h>
17 #include <linux/of_address.h>
18 #include <linux/clk.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/cma.h>
21 #include <linux/dma-contiguous.h>
22 #include <linux/io.h>
23 #include <linux/of_reserved_mem.h>
24 #include "ion.h"
25 #include "ion_priv.h"
26 #include "ion_of.h"
27 
ion_parse_dt_heap_common(struct device_node * heap_node,struct ion_platform_heap * heap,struct ion_of_heap * compatible)28 static int ion_parse_dt_heap_common(struct device_node *heap_node,
29 				    struct ion_platform_heap *heap,
30 				    struct ion_of_heap *compatible)
31 {
32 	int i;
33 
34 	for (i = 0; compatible[i].name; i++) {
35 		if (of_device_is_compatible(heap_node, compatible[i].compat))
36 			break;
37 	}
38 
39 	if (!compatible[i].name)
40 		return -ENODEV;
41 
42 	heap->id = compatible[i].heap_id;
43 	heap->type = compatible[i].type;
44 	heap->name = compatible[i].name;
45 	heap->align = compatible[i].align;
46 
47 	/* Some kind of callback function pointer? */
48 
49 	pr_info("%s: id %d type %d name %s align %lx\n", __func__,
50 		heap->id, heap->type, heap->name, heap->align);
51 	return 0;
52 }
53 
ion_setup_heap_common(struct platform_device * parent,struct device_node * heap_node,struct ion_platform_heap * heap)54 static int ion_setup_heap_common(struct platform_device *parent,
55 				 struct device_node *heap_node,
56 				 struct ion_platform_heap *heap)
57 {
58 	int ret = 0;
59 
60 	switch (heap->type) {
61 	case ION_HEAP_TYPE_CARVEOUT:
62 	case ION_HEAP_TYPE_CHUNK:
63 		if (heap->base && heap->size)
64 			return 0;
65 
66 		ret = of_reserved_mem_device_init(heap->priv);
67 		break;
68 	default:
69 		break;
70 	}
71 
72 	return ret;
73 }
74 
ion_parse_dt(struct platform_device * pdev,struct ion_of_heap * compatible)75 struct ion_platform_data *ion_parse_dt(struct platform_device *pdev,
76 				       struct ion_of_heap *compatible)
77 {
78 	int num_heaps, ret;
79 	const struct device_node *dt_node = pdev->dev.of_node;
80 	struct device_node *node;
81 	struct ion_platform_heap *heaps;
82 	struct ion_platform_data *data;
83 	int i = 0;
84 
85 	num_heaps = of_get_available_child_count(dt_node);
86 
87 	if (!num_heaps)
88 		return ERR_PTR(-EINVAL);
89 
90 	heaps = devm_kzalloc(&pdev->dev,
91 			     sizeof(struct ion_platform_heap) * num_heaps,
92 			     GFP_KERNEL);
93 	if (!heaps)
94 		return ERR_PTR(-ENOMEM);
95 
96 	data = devm_kzalloc(&pdev->dev, sizeof(struct ion_platform_data),
97 			    GFP_KERNEL);
98 	if (!data)
99 		return ERR_PTR(-ENOMEM);
100 
101 	for_each_available_child_of_node(dt_node, node) {
102 		struct platform_device *heap_pdev;
103 
104 		ret = ion_parse_dt_heap_common(node, &heaps[i], compatible);
105 		if (ret)
106 			return ERR_PTR(ret);
107 
108 		heap_pdev = of_platform_device_create(node, heaps[i].name,
109 						      &pdev->dev);
110 		if (!heap_pdev)
111 			return ERR_PTR(-ENOMEM);
112 		heap_pdev->dev.platform_data = &heaps[i];
113 
114 		heaps[i].priv = &heap_pdev->dev;
115 
116 		ret = ion_setup_heap_common(pdev, node, &heaps[i]);
117 		if (ret)
118 			goto out_err;
119 		i++;
120 	}
121 
122 	data->heaps = heaps;
123 	data->nr = num_heaps;
124 	return data;
125 
126 out_err:
127 	for ( ; i >= 0; i--)
128 		if (heaps[i].priv)
129 			of_device_unregister(to_platform_device(heaps[i].priv));
130 
131 	return ERR_PTR(ret);
132 }
133 
ion_destroy_platform_data(struct ion_platform_data * data)134 void ion_destroy_platform_data(struct ion_platform_data *data)
135 {
136 	int i;
137 
138 	for (i = 0; i < data->nr; i++)
139 		if (data->heaps[i].priv)
140 			of_device_unregister(to_platform_device(
141 				data->heaps[i].priv));
142 }
143 
144 #ifdef CONFIG_OF_RESERVED_MEM
145 #include <linux/of.h>
146 #include <linux/of_fdt.h>
147 #include <linux/of_reserved_mem.h>
148 
rmem_ion_device_init(struct reserved_mem * rmem,struct device * dev)149 static int rmem_ion_device_init(struct reserved_mem *rmem, struct device *dev)
150 {
151 	struct platform_device *pdev = to_platform_device(dev);
152 	struct ion_platform_heap *heap = pdev->dev.platform_data;
153 
154 	heap->base = rmem->base;
155 	heap->base = rmem->size;
156 	pr_debug("%s: heap %s base %pa size %pa dev %p\n", __func__,
157 		 heap->name, &rmem->base, &rmem->size, dev);
158 	return 0;
159 }
160 
rmem_ion_device_release(struct reserved_mem * rmem,struct device * dev)161 static void rmem_ion_device_release(struct reserved_mem *rmem,
162 				    struct device *dev)
163 {
164 	return;
165 }
166 
167 static const struct reserved_mem_ops rmem_dma_ops = {
168 	.device_init	= rmem_ion_device_init,
169 	.device_release	= rmem_ion_device_release,
170 };
171 
rmem_ion_setup(struct reserved_mem * rmem)172 static int __init rmem_ion_setup(struct reserved_mem *rmem)
173 {
174 	phys_addr_t size = rmem->size;
175 
176 	size = size / 1024;
177 
178 	pr_info("Ion memory setup at %pa size %pa MiB\n",
179 		&rmem->base, &size);
180 	rmem->ops = &rmem_dma_ops;
181 	return 0;
182 }
183 
184 RESERVEDMEM_OF_DECLARE(ion, "ion-region", rmem_ion_setup);
185 #endif
186