blob: 1959f5d4311e3185b9d4cb7bbd5c136a0fffbe12 [file] [log] [blame]
Olav Hauganab77b1b2012-02-28 09:19:22 -08001/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
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>
Olav Haugan16cdb412012-03-27 13:02:17 -070016#include <linux/vmalloc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070017#include <asm/sizes.h>
18#include <asm/page.h>
19#include <linux/init.h>
20#include <mach/iommu.h>
21#include <mach/iommu_domains.h>
Laura Abbott9f4a8e62011-08-29 19:08:07 -070022#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070023
Laura Abbotte956cce2011-10-25 13:33:20 -070024/* dummy 4k for overmapping */
25char iommu_dummy[2*PAGE_SIZE-4];
26
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027struct msm_iommu_domain {
Laura Abbott9f4a8e62011-08-29 19:08:07 -070028 /* iommu domain to map in */
29 struct iommu_domain *domain;
30 /* total number of allocations from this domain */
31 atomic_t allocation_cnt;
32 /* number of iova pools */
33 int npools;
34 /*
35 * array of gen_pools for allocating iovas.
36 * behavior is undefined if these overlap
37 */
38 struct mem_pool *iova_pools;
39
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040};
41
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042
43struct {
44 char *name;
45 int domain;
46} msm_iommu_ctx_names[] = {
Olav Haugan2d191032012-02-28 09:46:31 -080047 /* Camera */
48 {
49 .name = "vpe_src",
50 .domain = CAMERA_DOMAIN,
51 },
52 /* Camera */
53 {
54 .name = "vpe_dst",
55 .domain = CAMERA_DOMAIN,
56 },
57 /* Camera */
58 {
59 .name = "vfe_imgwr",
60 .domain = CAMERA_DOMAIN,
61 },
62 /* Camera */
63 {
64 .name = "vfe_misc",
65 .domain = CAMERA_DOMAIN,
66 },
67 /* Camera */
68 {
69 .name = "ijpeg_src",
70 .domain = CAMERA_DOMAIN,
71 },
72 /* Camera */
73 {
74 .name = "ijpeg_dst",
75 .domain = CAMERA_DOMAIN,
76 },
77 /* Camera */
78 {
79 .name = "jpegd_src",
80 .domain = CAMERA_DOMAIN,
81 },
82 /* Camera */
83 {
84 .name = "jpegd_dst",
85 .domain = CAMERA_DOMAIN,
86 },
87 /* Rotator */
88 {
89 .name = "rot_src",
90 .domain = ROTATOR_DOMAIN,
91 },
92 /* Rotator */
93 {
94 .name = "rot_dst",
95 .domain = ROTATOR_DOMAIN,
96 },
97 /* Video */
98 {
99 .name = "vcodec_a_mm1",
100 .domain = VIDEO_DOMAIN,
101 },
102 /* Video */
103 {
104 .name = "vcodec_b_mm2",
105 .domain = VIDEO_DOMAIN,
106 },
107 /* Video */
108 {
109 .name = "vcodec_a_stream",
110 .domain = VIDEO_DOMAIN,
111 },
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700112};
113
Olav Haugan2d191032012-02-28 09:46:31 -0800114static struct mem_pool video_pools[] = {
115 /*
116 * Video hardware has the following requirements:
117 * 1. All video addresses used by the video hardware must be at a higher
118 * address than video firmware address.
119 * 2. Video hardware can only access a range of 256MB from the base of
120 * the video firmware.
121 */
122 [VIDEO_FIRMWARE_POOL] =
123 /* Low addresses, intended for video firmware */
124 {
125 .paddr = SZ_128K,
126 .size = SZ_16M - SZ_128K,
127 },
128 [VIDEO_MAIN_POOL] =
129 /* Main video pool */
130 {
131 .paddr = SZ_16M,
132 .size = SZ_256M - SZ_16M,
133 },
134 [GEN_POOL] =
135 /* Remaining address space up to 2G */
136 {
137 .paddr = SZ_256M,
138 .size = SZ_2G - SZ_256M,
139 },
140};
141
142static struct mem_pool camera_pools[] = {
143 [GEN_POOL] =
144 /* One address space for camera */
145 {
146 .paddr = SZ_128K,
147 .size = SZ_2G - SZ_128K,
148 },
149};
150
151static struct mem_pool display_pools[] = {
152 [GEN_POOL] =
153 /* One address space for display */
154 {
155 .paddr = SZ_128K,
156 .size = SZ_2G - SZ_128K,
157 },
158};
159
160static struct mem_pool rotator_pools[] = {
161 [GEN_POOL] =
162 /* One address space for rotator */
163 {
164 .paddr = SZ_128K,
165 .size = SZ_2G - SZ_128K,
166 },
167};
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700168
169static struct msm_iommu_domain msm_iommu_domains[] = {
Olav Haugan2d191032012-02-28 09:46:31 -0800170 [VIDEO_DOMAIN] = {
171 .iova_pools = video_pools,
172 .npools = ARRAY_SIZE(video_pools),
173 },
174 [CAMERA_DOMAIN] = {
175 .iova_pools = camera_pools,
176 .npools = ARRAY_SIZE(camera_pools),
177 },
178 [DISPLAY_DOMAIN] = {
179 .iova_pools = display_pools,
180 .npools = ARRAY_SIZE(display_pools),
181 },
182 [ROTATOR_DOMAIN] = {
183 .iova_pools = rotator_pools,
184 .npools = ARRAY_SIZE(rotator_pools),
185 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186};
187
Laura Abbotte956cce2011-10-25 13:33:20 -0700188int msm_iommu_map_extra(struct iommu_domain *domain,
189 unsigned long start_iova,
190 unsigned long size,
191 int cached)
192{
Olav Haugan16cdb412012-03-27 13:02:17 -0700193 int i, ret = 0;
194 struct scatterlist *sglist;
195 unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
196 struct page *dummy_page = phys_to_page(
197 PFN_ALIGN(virt_to_phys(iommu_dummy)));
Laura Abbotte956cce2011-10-25 13:33:20 -0700198
Olav Haugan16cdb412012-03-27 13:02:17 -0700199 sglist = vmalloc(sizeof(*sglist) * nrpages);
200 if (!sglist) {
201 ret = -ENOMEM;
202 goto err1;
Laura Abbotte956cce2011-10-25 13:33:20 -0700203 }
204
Olav Haugan16cdb412012-03-27 13:02:17 -0700205 sg_init_table(sglist, nrpages);
Laura Abbotte956cce2011-10-25 13:33:20 -0700206
Olav Haugan16cdb412012-03-27 13:02:17 -0700207 for (i = 0; i < nrpages; i++)
208 sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
Laura Abbotte956cce2011-10-25 13:33:20 -0700209
Olav Haugan16cdb412012-03-27 13:02:17 -0700210 ret = iommu_map_range(domain, start_iova, sglist, size, cached);
211 if (ret) {
212 pr_err("%s: could not map extra %lx in domain %p\n",
213 __func__, start_iova, domain);
214 }
Laura Abbotte956cce2011-10-25 13:33:20 -0700215
Olav Haugan16cdb412012-03-27 13:02:17 -0700216 vfree(sglist);
217err1:
218 return ret;
Laura Abbotte956cce2011-10-25 13:33:20 -0700219}
220
221
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700222struct iommu_domain *msm_get_iommu_domain(int domain_num)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700223{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700224 if (domain_num >= 0 && domain_num < MAX_DOMAINS)
225 return msm_iommu_domains[domain_num].domain;
226 else
227 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228}
229
Olav Hauganab77b1b2012-02-28 09:19:22 -0800230static unsigned long subsystem_to_domain_tbl[] = {
231 VIDEO_DOMAIN,
232 VIDEO_DOMAIN,
233 CAMERA_DOMAIN,
234 DISPLAY_DOMAIN,
235 ROTATOR_DOMAIN,
236 0xFFFFFFFF
237};
238
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700239unsigned long msm_subsystem_get_domain_no(int subsys_id)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240{
Olav Hauganab77b1b2012-02-28 09:19:22 -0800241 if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
242 subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
243 return subsystem_to_domain_tbl[subsys_id];
244 else
245 return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700246}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700248unsigned long msm_subsystem_get_partition_no(int subsys_id)
249{
250 switch (subsys_id) {
251 case MSM_SUBSYSTEM_VIDEO_FWARE:
252 return VIDEO_FIRMWARE_POOL;
253 case MSM_SUBSYSTEM_VIDEO:
Olav Hauganee365362012-02-16 09:31:37 -0800254 return VIDEO_MAIN_POOL;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700255 case MSM_SUBSYSTEM_CAMERA:
256 case MSM_SUBSYSTEM_DISPLAY:
257 case MSM_SUBSYSTEM_ROTATOR:
Olav Hauganee365362012-02-16 09:31:37 -0800258 return GEN_POOL;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700259 default:
260 return 0xFFFFFFFF;
261 }
262}
263
264unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
265 unsigned int partition_no,
266 unsigned long size,
267 unsigned long align)
268{
269 struct mem_pool *pool;
270 unsigned long iova;
271
272 if (iommu_domain >= MAX_DOMAINS)
273 return 0;
274
275 if (partition_no >= msm_iommu_domains[iommu_domain].npools)
276 return 0;
277
278 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
279
280 if (!pool->gpool)
281 return 0;
282
283 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
284 if (iova)
285 pool->free -= size;
286
287 return iova;
288}
289
290void msm_free_iova_address(unsigned long iova,
291 unsigned int iommu_domain,
292 unsigned int partition_no,
293 unsigned long size)
294{
295 struct mem_pool *pool;
296
297 if (iommu_domain >= MAX_DOMAINS) {
298 WARN(1, "Invalid domain %d\n", iommu_domain);
299 return;
300 }
301
302 if (partition_no >= msm_iommu_domains[iommu_domain].npools) {
303 WARN(1, "Invalid partition %d for domain %d\n",
304 partition_no, iommu_domain);
305 return;
306 }
307
308 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
309
310 if (!pool)
311 return;
312
313 pool->free += size;
314 gen_pool_free(pool->gpool, iova, size);
315}
316
317int msm_use_iommu()
318{
Olav Haugan2d191032012-02-28 09:46:31 -0800319 return iommu_found();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700320}
321
322static int __init msm_subsystem_iommu_init(void)
323{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700324 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700326 for (i = 0; i < ARRAY_SIZE(msm_iommu_domains); i++) {
327 msm_iommu_domains[i].domain = iommu_domain_alloc(0);
328 if (!msm_iommu_domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700331 for (j = 0; j < msm_iommu_domains[i].npools; j++) {
332 struct mem_pool *pool = &msm_iommu_domains[i].
333 iova_pools[j];
334 mutex_init(&pool->pool_mutex);
Olav Haugan2d191032012-02-28 09:46:31 -0800335 if (pool->size) {
336 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700337
Olav Haugan2d191032012-02-28 09:46:31 -0800338 if (!pool->gpool) {
339 pr_err("%s: could not allocate pool\n",
340 __func__);
341 pr_err("%s: domain %d iova space %d\n",
342 __func__, i, j);
343 continue;
344 }
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700345
Olav Haugan2d191032012-02-28 09:46:31 -0800346 if (gen_pool_add(pool->gpool, pool->paddr,
347 pool->size, -1)) {
348 pr_err("%s: could not add memory\n",
349 __func__);
350 pr_err("%s: domain %d pool %d\n",
351 __func__, i, j);
352 gen_pool_destroy(pool->gpool);
353 pool->gpool = NULL;
354 continue;
355 }
356 } else {
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700357 pool->gpool = NULL;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700358 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 }
360 }
361
362 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
363 int domain_idx;
364 struct device *ctx = msm_iommu_get_ctx(
365 msm_iommu_ctx_names[i].name);
366
367 if (!ctx)
368 continue;
369
370 domain_idx = msm_iommu_ctx_names[i].domain;
371
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700372 if (!msm_iommu_domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700373 continue;
374
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700375 if (iommu_attach_device(msm_iommu_domains[domain_idx].domain,
376 ctx)) {
377 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 " iommu programming will not occur.\n",
379 __func__, domain_idx,
380 msm_iommu_ctx_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 continue;
382 }
383 }
384
385 return 0;
386}
387device_initcall(msm_subsystem_iommu_init);