mmc: host: rk_sdmmc:
[firefly-linux-kernel-4.4.55.git] / drivers / iommu / rockchip-iovmm.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License version 2 as
4  * published by the Free Software Foundation.
5  */
6
7 #ifdef CONFIG_ROCKCHIP_IOMMU_DEBUG
8 #define DEBUG
9 #endif
10
11 #include <linux/kernel.h>
12 #include <linux/hardirq.h>
13 #include <linux/slab.h>
14 #include <linux/scatterlist.h>
15 #include <linux/err.h>
16
17 #include <linux/of.h>
18 #include <linux/of_platform.h>
19
20 #include "rockchip-iommu.h"
21
22 static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
23 {
24         struct rk_vm_region *region;
25
26         list_for_each_entry(region, &vmm->regions_list, node)
27                 if (region->start == iova)
28                         return region;
29
30         return NULL;
31 }
32
33 int iovmm_activate(struct device *dev)
34 {
35         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
36
37         return iommu_attach_device(vmm->domain, dev);
38 }
39
40 void iovmm_deactivate(struct device *dev)
41 {
42         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
43
44         iommu_detach_device(vmm->domain, dev);
45 }
46
47 dma_addr_t iovmm_map(struct device *dev,struct scatterlist *sg, off_t offset,size_t size)
48 {
49         off_t start_off;
50         dma_addr_t addr, start = 0;
51         size_t mapped_size = 0;
52         struct rk_vm_region *region;
53         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
54         int order;
55         int ret;
56         
57         for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
58                 offset -= sg_dma_len(sg);
59
60         start_off = offset_in_page(sg_phys(sg) + offset);
61         size = PAGE_ALIGN(size + start_off);
62
63         order = __fls(min_t(size_t, size, SZ_1M));
64
65         region = kmalloc(sizeof(*region), GFP_KERNEL);
66         if (!region) 
67         {
68                 ret = -ENOMEM;
69                 goto err_map_nomem;
70         }
71
72         //start = (dma_addr_t)gen_pool_alloc_aligned(vmm->vmm_pool, size, order);
73         
74         start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool, size);
75         if (!start) 
76         {
77                 ret = -ENOMEM;
78                 goto err_map_noiomem;
79         }
80
81         addr = start;
82         do {
83                 phys_addr_t phys;
84                 size_t len;
85
86                 phys = sg_phys(sg);
87                 len = sg_dma_len(sg);
88
89                 /* if back to back sg entries are contiguous consolidate them */
90                 while (sg_next(sg) &&sg_phys(sg) + sg_dma_len(sg) == sg_phys(sg_next(sg))) 
91                 {
92                         len += sg_dma_len(sg_next(sg));
93                         sg = sg_next(sg);
94                 }
95
96                 if (offset > 0) 
97                 {
98                         len -= offset;
99                         phys += offset;
100                         offset = 0;
101                 }
102
103                 if (offset_in_page(phys))
104                 {
105                         len += offset_in_page(phys);
106                         phys = round_down(phys, PAGE_SIZE);
107                 }
108
109                 len = PAGE_ALIGN(len);
110
111                 if (len > (size - mapped_size))
112                         len = size - mapped_size;
113
114                 ret = iommu_map(vmm->domain, addr, phys, len, 0);
115                 if (ret)
116                         break;
117
118                 addr += len;
119                 mapped_size += len;
120         } while ((sg = sg_next(sg)) && (mapped_size < size));
121
122         BUG_ON(mapped_size > size);
123
124         if (mapped_size < size)
125                 goto err_map_map;
126
127         region->start = start + start_off;
128         region->size = size;
129
130         INIT_LIST_HEAD(&region->node);
131
132         spin_lock(&vmm->lock);
133
134         list_add(&region->node, &vmm->regions_list);
135
136         spin_unlock(&vmm->lock);
137
138         rockchip_sysmmu_tlb_invalidate(dev);
139         /*
140         pr_err("IOVMM: Allocated VM region @ %#x/%#X bytes.\n",region->start, region->size);
141         */
142         return region->start;
143
144 err_map_map:
145         iommu_unmap(vmm->domain, start, mapped_size);
146         gen_pool_free(vmm->vmm_pool, start, size);
147 err_map_noiomem:
148         kfree(region);
149 err_map_nomem:
150         pr_err("IOVMM: Failed to allocated VM region for %#x bytes.\n",size);
151         return (dma_addr_t)ret;
152 }
153
154 void iovmm_unmap(struct device *dev, dma_addr_t iova)
155 {
156         struct rk_vm_region *region;
157         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
158         size_t unmapped_size;
159
160         /* This function must not be called in IRQ handlers */
161         BUG_ON(in_irq());
162
163         spin_lock(&vmm->lock);
164
165         region = find_region(vmm, iova);
166         if (WARN_ON(!region)) 
167         {
168                 spin_unlock(&vmm->lock);
169                 return;
170         }
171
172         list_del(&region->node);
173
174         spin_unlock(&vmm->lock);
175
176         region->start = round_down(region->start, PAGE_SIZE);
177
178         unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
179
180         rockchip_sysmmu_tlb_invalidate(dev);
181
182         gen_pool_free(vmm->vmm_pool, region->start, region->size);
183
184         WARN_ON(unmapped_size != region->size);
185         /*
186         pr_err("IOVMM: Unmapped %#x bytes from %#x.\n",unmapped_size, region->start);
187         */
188         kfree(region);
189 }
190
191 int iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
192 {
193         struct rk_vm_region *region;
194         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
195         int ret;
196
197         if (WARN_ON((phys + size) >= IOVA_START)) 
198         {
199                 dev_err(dev,"Unable to create one to one mapping for %#x @ %#x\n",size, phys);
200                 return -EINVAL;
201         }
202
203         region = kmalloc(sizeof(*region), GFP_KERNEL);
204         if (!region)
205                 return -ENOMEM;
206
207         if (WARN_ON(phys & ~PAGE_MASK))
208                 phys = round_down(phys, PAGE_SIZE);
209
210
211         ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
212         if (ret < 0) 
213         {
214                 kfree(region);
215                 return ret;
216         }
217
218         region->start = (dma_addr_t)phys;
219         region->size = size;
220         INIT_LIST_HEAD(&region->node);
221
222         spin_lock(&vmm->lock);
223
224         list_add(&region->node, &vmm->regions_list);
225
226         spin_unlock(&vmm->lock);
227         
228         rockchip_sysmmu_tlb_invalidate(dev);
229
230         return 0;
231 }
232
233 void iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
234 {
235         struct rk_vm_region *region;
236         struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
237         size_t unmapped_size;
238
239         /* This function must not be called in IRQ handlers */
240         BUG_ON(in_irq());
241
242         if (WARN_ON(phys & ~PAGE_MASK))
243                 phys = round_down(phys, PAGE_SIZE);
244
245         spin_lock(&vmm->lock);
246
247         region = find_region(vmm, (dma_addr_t)phys);
248         if (WARN_ON(!region)) 
249         {
250                 spin_unlock(&vmm->lock);
251                 return;
252         }
253
254         list_del(&region->node);
255
256         spin_unlock(&vmm->lock);
257
258         unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
259         rockchip_sysmmu_tlb_invalidate(dev);
260         WARN_ON(unmapped_size != region->size);
261         dev_dbg(dev, "IOVMM: Unmapped %#x bytes from %#x.\n",unmapped_size, region->start);
262
263         kfree(region);
264 }
265
266 int rockchip_init_iovmm(struct device *sysmmu, struct rk_iovmm *vmm)
267 {
268         int ret = 0;
269
270         vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
271         if (!vmm->vmm_pool) 
272         {
273                 ret = -ENOMEM;
274                 goto err_setup_genalloc;
275         }
276
277         /* (1GB - 4KB) addr space from 0x10000000 */
278         ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
279         if (ret)
280                 goto err_setup_domain;
281
282         vmm->domain = iommu_domain_alloc(&platform_bus_type);
283         if (!vmm->domain) 
284         {
285                 ret = -ENOMEM;
286                 goto err_setup_domain;
287         }
288
289         spin_lock_init(&vmm->lock);
290
291         INIT_LIST_HEAD(&vmm->regions_list);
292         
293         pr_info("IOVMM: Created %#x B IOVMM from %#x.\n",IOVM_SIZE, IOVA_START);
294         return 0;
295 err_setup_domain:
296         gen_pool_destroy(vmm->vmm_pool);
297 err_setup_genalloc:
298         dev_dbg(sysmmu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
299
300         return ret;
301 }
302
303 /****
304 1,success : pointer to the device inside of platform device 
305 2,fail       : NULL
306 ****/
307 struct device *rockchip_get_sysmmu_device_by_compatible(const char *compt)
308 {
309         struct device_node *dn = NULL;
310         struct platform_device *pd = NULL;
311         struct device *ret = NULL ;
312
313 #if 0
314         dn = of_find_node_by_name(NULL,name);
315 #endif
316
317         dn = of_find_compatible_node(NULL,NULL,compt);
318         if(!dn)
319         {
320                 printk("can't find device node %s \r\n",compt);
321                 return NULL;
322         }
323         
324         pd = of_find_device_by_node(dn);
325         if(!pd)
326         {       
327                 printk("can't find platform device in device node %s \r\n",compt);
328                 return  NULL;
329         }
330         ret = &pd->dev;
331         
332         return ret;
333
334 }
335