blob: e849cdb2e5ce18badc3f8591bf10b1dd155ef92e [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
23struct msm_iommu_domain {
Laura Abbott9f4a8e62011-08-29 19:08:07 -070024 /* iommu domain to map in */
25 struct iommu_domain *domain;
26 /* total number of allocations from this domain */
27 atomic_t allocation_cnt;
28 /* number of iova pools */
29 int npools;
30 /*
31 * array of gen_pools for allocating iovas.
32 * behavior is undefined if these overlap
33 */
34 struct mem_pool *iova_pools;
35
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036};
37
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39struct {
40 char *name;
41 int domain;
42} msm_iommu_ctx_names[] = {
43 /* Camera */
44 {
45 .name = "vpe_src",
46 .domain = GLOBAL_DOMAIN,
47 },
48 /* Camera */
49 {
50 .name = "vpe_dst",
51 .domain = GLOBAL_DOMAIN,
52 },
53 /* Camera */
54 {
55 .name = "vfe_imgwr",
56 .domain = GLOBAL_DOMAIN,
57 },
58 /* Camera */
59 {
60 .name = "vfe_misc",
61 .domain = GLOBAL_DOMAIN,
62 },
63 /* Camera */
64 {
65 .name = "ijpeg_src",
66 .domain = GLOBAL_DOMAIN,
67 },
68 /* Camera */
69 {
70 .name = "ijpeg_dst",
71 .domain = GLOBAL_DOMAIN,
72 },
73 /* Camera */
74 {
75 .name = "jpegd_src",
76 .domain = GLOBAL_DOMAIN,
77 },
78 /* Camera */
79 {
80 .name = "jpegd_dst",
81 .domain = GLOBAL_DOMAIN,
82 },
83 /* Display */
84 {
85 .name = "mdp_vg1",
86 .domain = GLOBAL_DOMAIN,
87 },
88 /* Display */
89 {
90 .name = "mdp_vg2",
91 .domain = GLOBAL_DOMAIN,
92 },
93 /* Display */
94 {
95 .name = "mdp_rgb1",
96 .domain = GLOBAL_DOMAIN,
97 },
98 /* Display */
99 {
100 .name = "mdp_rgb2",
101 .domain = GLOBAL_DOMAIN,
102 },
103 /* Rotator */
104 {
105 .name = "rot_src",
106 .domain = GLOBAL_DOMAIN,
107 },
108 /* Rotator */
109 {
110 .name = "rot_dst",
111 .domain = GLOBAL_DOMAIN,
112 },
113 /* Video */
114 {
115 .name = "vcodec_a_mm1",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700116 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117 },
118 /* Video */
119 {
120 .name = "vcodec_b_mm2",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700121 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 },
123 /* Video */
124 {
125 .name = "vcodec_a_stream",
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700126 .domain = GLOBAL_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127 },
128};
129
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700130static struct mem_pool global_pools[] = {
131 [VIDEO_FIRMWARE_POOL] =
132 /* Low addresses, intended for video firmware */
133 {
134 .paddr = SZ_128K,
135 .size = SZ_16M - SZ_128K,
136 },
137 [LOW_256MB_POOL] =
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 /*
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700139 * Video can only access first 256MB of memory
140 * dedicated pool for such allocations
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700141 */
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700142 {
143 .paddr = SZ_16M,
144 .size = SZ_256M - SZ_16M,
145 },
146 [HIGH_POOL] =
147 /* Remaining address space up to 2G */
148 {
149 .paddr = SZ_256M,
150 .size = SZ_2G - SZ_256M,
151 }
152};
153
154
155static struct msm_iommu_domain msm_iommu_domains[] = {
156 [GLOBAL_DOMAIN] = {
157 .iova_pools = global_pools,
158 .npools = ARRAY_SIZE(global_pools),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 }
160};
161
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700162struct iommu_domain *msm_get_iommu_domain(int domain_num)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700163{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700164 if (domain_num >= 0 && domain_num < MAX_DOMAINS)
165 return msm_iommu_domains[domain_num].domain;
166 else
167 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168}
169
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700170unsigned long msm_subsystem_get_domain_no(int subsys_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700172 return GLOBAL_DOMAIN;
173}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700175unsigned long msm_subsystem_get_partition_no(int subsys_id)
176{
177 switch (subsys_id) {
178 case MSM_SUBSYSTEM_VIDEO_FWARE:
179 return VIDEO_FIRMWARE_POOL;
180 case MSM_SUBSYSTEM_VIDEO:
181 return LOW_256MB_POOL;
182 case MSM_SUBSYSTEM_CAMERA:
183 case MSM_SUBSYSTEM_DISPLAY:
184 case MSM_SUBSYSTEM_ROTATOR:
185 return HIGH_POOL;
186 default:
187 return 0xFFFFFFFF;
188 }
189}
190
191unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
192 unsigned int partition_no,
193 unsigned long size,
194 unsigned long align)
195{
196 struct mem_pool *pool;
197 unsigned long iova;
198
199 if (iommu_domain >= MAX_DOMAINS)
200 return 0;
201
202 if (partition_no >= msm_iommu_domains[iommu_domain].npools)
203 return 0;
204
205 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
206
207 if (!pool->gpool)
208 return 0;
209
210 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
211 if (iova)
212 pool->free -= size;
213
214 return iova;
215}
216
217void msm_free_iova_address(unsigned long iova,
218 unsigned int iommu_domain,
219 unsigned int partition_no,
220 unsigned long size)
221{
222 struct mem_pool *pool;
223
224 if (iommu_domain >= MAX_DOMAINS) {
225 WARN(1, "Invalid domain %d\n", iommu_domain);
226 return;
227 }
228
229 if (partition_no >= msm_iommu_domains[iommu_domain].npools) {
230 WARN(1, "Invalid partition %d for domain %d\n",
231 partition_no, iommu_domain);
232 return;
233 }
234
235 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
236
237 if (!pool)
238 return;
239
240 pool->free += size;
241 gen_pool_free(pool->gpool, iova, size);
242}
243
244int msm_use_iommu()
245{
246 /*
247 * For now, just detect if the iommu is attached.
248 */
249 return iommu_found();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250}
251
252static int __init msm_subsystem_iommu_init(void)
253{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700254 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700256 for (i = 0; i < ARRAY_SIZE(msm_iommu_domains); i++) {
257 msm_iommu_domains[i].domain = iommu_domain_alloc(0);
258 if (!msm_iommu_domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700260
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700261 for (j = 0; j < msm_iommu_domains[i].npools; j++) {
262 struct mem_pool *pool = &msm_iommu_domains[i].
263 iova_pools[j];
264 mutex_init(&pool->pool_mutex);
265 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
266
267 if (!pool->gpool) {
268 pr_err("%s: domain %d: could not allocate iova"
269 " pool. iommu programming will not work"
270 " with iova space %d\n", __func__,
271 i, j);
272 continue;
273 }
274
275 if (gen_pool_add(pool->gpool, pool->paddr, pool->size,
276 -1)) {
277 pr_err("%s: domain %d: could not add memory to"
278 " iova pool. iommu programming will not"
279 " work with iova space %d\n", __func__,
280 i, j);
281 gen_pool_destroy(pool->gpool);
282 pool->gpool = NULL;
283 continue;
284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 }
286 }
287
288 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
289 int domain_idx;
290 struct device *ctx = msm_iommu_get_ctx(
291 msm_iommu_ctx_names[i].name);
292
293 if (!ctx)
294 continue;
295
296 domain_idx = msm_iommu_ctx_names[i].domain;
297
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700298 if (!msm_iommu_domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 continue;
300
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700301 if (iommu_attach_device(msm_iommu_domains[domain_idx].domain,
302 ctx)) {
303 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 " iommu programming will not occur.\n",
305 __func__, domain_idx,
306 msm_iommu_ctx_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307 continue;
308 }
309 }
310
311 return 0;
312}
313device_initcall(msm_subsystem_iommu_init);