blob: 600a2e91ee765e9b040db4d65deb652bb4973d31 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <mach/msm_subsystem_map.h>
14#include <linux/memory_alloc.h>
15#include <linux/iommu.h>
16#include <asm/sizes.h>
17#include <asm/page.h>
18#include <linux/init.h>
19#include <mach/iommu.h>
20#include <mach/iommu_domains.h>
Laura Abbott9f4a8e62011-08-29 19:08:07 -070021#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022
Laura Abbotte956cce2011-10-25 13:33:20 -070023/* dummy 4k for overmapping */
24char iommu_dummy[2*PAGE_SIZE-4];
25
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026struct msm_iommu_domain {
Laura Abbott9f4a8e62011-08-29 19:08:07 -070027 /* iommu domain to map in */
28 struct iommu_domain *domain;
29 /* total number of allocations from this domain */
30 atomic_t allocation_cnt;
31 /* number of iova pools */
32 int npools;
33 /*
34 * array of gen_pools for allocating iovas.
35 * behavior is undefined if these overlap
36 */
37 struct mem_pool *iova_pools;
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039};
40
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42struct {
43 char *name;
44 int domain;
45} msm_iommu_ctx_names[] = {
46 /* Camera */
47 {
48 .name = "vpe_src",
49 .domain = GLOBAL_DOMAIN,
50 },
51 /* Camera */
52 {
53 .name = "vpe_dst",
54 .domain = GLOBAL_DOMAIN,
55 },
56 /* Camera */
57 {
58 .name = "vfe_imgwr",
59 .domain = GLOBAL_DOMAIN,
60 },
61 /* Camera */
62 {
63 .name = "vfe_misc",
64 .domain = GLOBAL_DOMAIN,
65 },
66 /* Camera */
67 {
68 .name = "ijpeg_src",
69 .domain = GLOBAL_DOMAIN,
70 },
71 /* Camera */
72 {
73 .name = "ijpeg_dst",
74 .domain = GLOBAL_DOMAIN,
75 },
76 /* Camera */
77 {
78 .name = "jpegd_src",
79 .domain = GLOBAL_DOMAIN,
80 },
81 /* Camera */
82 {
83 .name = "jpegd_dst",
84 .domain = GLOBAL_DOMAIN,
85 },
86 /* Display */
87 {
88 .name = "mdp_vg1",
89 .domain = GLOBAL_DOMAIN,
90 },
91 /* Display */
92 {
93 .name = "mdp_vg2",
94 .domain = GLOBAL_DOMAIN,
95 },
96 /* Display */
97 {
98 .name = "mdp_rgb1",
99 .domain = GLOBAL_DOMAIN,
100 },
101 /* Display */
102 {
103 .name = "mdp_rgb2",
104 .domain = GLOBAL_DOMAIN,
105 },
106 /* Rotator */
107 {
108 .name = "rot_src",
109 .domain = GLOBAL_DOMAIN,
110 },
111 /* Rotator */
112 {
113 .name = "rot_dst",
114 .domain = GLOBAL_DOMAIN,
115 },
116 /* Video */
117 {
118 .name = "vcodec_a_mm1",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700119 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 },
121 /* Video */
122 {
123 .name = "vcodec_b_mm2",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700124 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125 },
126 /* Video */
127 {
128 .name = "vcodec_a_stream",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700129 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130 },
131};
132
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700133static struct mem_pool global_pools[] = {
134 [VIDEO_FIRMWARE_POOL] =
135 /* Low addresses, intended for video firmware */
136 {
137 .paddr = SZ_128K,
138 .size = SZ_16M - SZ_128K,
139 },
140 [LOW_256MB_POOL] =
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 /*
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700142 * Video can only access first 256MB of memory
143 * dedicated pool for such allocations
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 */
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700145 {
146 .paddr = SZ_16M,
147 .size = SZ_256M - SZ_16M,
148 },
149 [HIGH_POOL] =
150 /* Remaining address space up to 2G */
151 {
152 .paddr = SZ_256M,
153 .size = SZ_2G - SZ_256M,
154 }
155};
156
157
158static struct msm_iommu_domain msm_iommu_domains[] = {
159 [GLOBAL_DOMAIN] = {
160 .iova_pools = global_pools,
161 .npools = ARRAY_SIZE(global_pools),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162 }
163};
164
Laura Abbotte956cce2011-10-25 13:33:20 -0700165int msm_iommu_map_extra(struct iommu_domain *domain,
166 unsigned long start_iova,
167 unsigned long size,
168 int cached)
169{
170 int i, ret;
171 unsigned long temp_iova;
172
173 for (i = size, temp_iova = start_iova; i > 0; i -= SZ_4K,
174 temp_iova += SZ_4K) {
175 ret = iommu_map(domain, temp_iova,
176 PFN_ALIGN(virt_to_phys(iommu_dummy)),
177 get_order(SZ_4K),
178 0);
179
180 if (ret) {
181 pr_err("%s: could not map %lx to dummy page in domain"
182 " %p\n",
183 __func__, temp_iova, domain);
184 goto out;
185 }
186 }
187
188 return 0;
189
190out:
191
192 for ( ; i < size; i += SZ_4K, temp_iova -= SZ_4K)
193 iommu_unmap(domain, temp_iova, get_order(SZ_4K));
194
195 return -EINVAL;
196
197}
198
199
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700200struct iommu_domain *msm_get_iommu_domain(int domain_num)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700202 if (domain_num >= 0 && domain_num < MAX_DOMAINS)
203 return msm_iommu_domains[domain_num].domain;
204 else
205 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206}
207
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700208unsigned long msm_subsystem_get_domain_no(int subsys_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700210 return GLOBAL_DOMAIN;
211}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700213unsigned long msm_subsystem_get_partition_no(int subsys_id)
214{
215 switch (subsys_id) {
216 case MSM_SUBSYSTEM_VIDEO_FWARE:
217 return VIDEO_FIRMWARE_POOL;
218 case MSM_SUBSYSTEM_VIDEO:
219 return LOW_256MB_POOL;
220 case MSM_SUBSYSTEM_CAMERA:
221 case MSM_SUBSYSTEM_DISPLAY:
222 case MSM_SUBSYSTEM_ROTATOR:
223 return HIGH_POOL;
224 default:
225 return 0xFFFFFFFF;
226 }
227}
228
229unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
230 unsigned int partition_no,
231 unsigned long size,
232 unsigned long align)
233{
234 struct mem_pool *pool;
235 unsigned long iova;
236
237 if (iommu_domain >= MAX_DOMAINS)
238 return 0;
239
240 if (partition_no >= msm_iommu_domains[iommu_domain].npools)
241 return 0;
242
243 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
244
245 if (!pool->gpool)
246 return 0;
247
248 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
249 if (iova)
250 pool->free -= size;
251
252 return iova;
253}
254
255void msm_free_iova_address(unsigned long iova,
256 unsigned int iommu_domain,
257 unsigned int partition_no,
258 unsigned long size)
259{
260 struct mem_pool *pool;
261
262 if (iommu_domain >= MAX_DOMAINS) {
263 WARN(1, "Invalid domain %d\n", iommu_domain);
264 return;
265 }
266
267 if (partition_no >= msm_iommu_domains[iommu_domain].npools) {
268 WARN(1, "Invalid partition %d for domain %d\n",
269 partition_no, iommu_domain);
270 return;
271 }
272
273 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
274
275 if (!pool)
276 return;
277
278 pool->free += size;
279 gen_pool_free(pool->gpool, iova, size);
280}
281
282int msm_use_iommu()
283{
284 /*
285 * For now, just detect if the iommu is attached.
286 */
287 return iommu_found();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288}
289
290static int __init msm_subsystem_iommu_init(void)
291{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700292 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700294 for (i = 0; i < ARRAY_SIZE(msm_iommu_domains); i++) {
295 msm_iommu_domains[i].domain = iommu_domain_alloc(0);
296 if (!msm_iommu_domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700299 for (j = 0; j < msm_iommu_domains[i].npools; j++) {
300 struct mem_pool *pool = &msm_iommu_domains[i].
301 iova_pools[j];
302 mutex_init(&pool->pool_mutex);
303 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
304
305 if (!pool->gpool) {
306 pr_err("%s: domain %d: could not allocate iova"
307 " pool. iommu programming will not work"
308 " with iova space %d\n", __func__,
309 i, j);
310 continue;
311 }
312
313 if (gen_pool_add(pool->gpool, pool->paddr, pool->size,
314 -1)) {
315 pr_err("%s: domain %d: could not add memory to"
316 " iova pool. iommu programming will not"
317 " work with iova space %d\n", __func__,
318 i, j);
319 gen_pool_destroy(pool->gpool);
320 pool->gpool = NULL;
321 continue;
322 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700323 }
324 }
325
326 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
327 int domain_idx;
328 struct device *ctx = msm_iommu_get_ctx(
329 msm_iommu_ctx_names[i].name);
330
331 if (!ctx)
332 continue;
333
334 domain_idx = msm_iommu_ctx_names[i].domain;
335
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700336 if (!msm_iommu_domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 continue;
338
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700339 if (iommu_attach_device(msm_iommu_domains[domain_idx].domain,
340 ctx)) {
341 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 " iommu programming will not occur.\n",
343 __func__, domain_idx,
344 msm_iommu_ctx_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 continue;
346 }
347 }
348
349 return 0;
350}
351device_initcall(msm_subsystem_iommu_init);