blob: dbc1389e531aaf1fe6845e9e03ffb6fc682ad84e [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
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700230unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
231 unsigned int partition_no,
232 unsigned long size,
233 unsigned long align)
234{
235 struct mem_pool *pool;
236 unsigned long iova;
237
238 if (iommu_domain >= MAX_DOMAINS)
239 return 0;
240
241 if (partition_no >= msm_iommu_domains[iommu_domain].npools)
242 return 0;
243
244 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
245
246 if (!pool->gpool)
247 return 0;
248
249 iova = gen_pool_alloc_aligned(pool->gpool, size, ilog2(align));
250 if (iova)
251 pool->free -= size;
252
253 return iova;
254}
255
256void msm_free_iova_address(unsigned long iova,
257 unsigned int iommu_domain,
258 unsigned int partition_no,
259 unsigned long size)
260{
261 struct mem_pool *pool;
262
263 if (iommu_domain >= MAX_DOMAINS) {
264 WARN(1, "Invalid domain %d\n", iommu_domain);
265 return;
266 }
267
268 if (partition_no >= msm_iommu_domains[iommu_domain].npools) {
269 WARN(1, "Invalid partition %d for domain %d\n",
270 partition_no, iommu_domain);
271 return;
272 }
273
274 pool = &msm_iommu_domains[iommu_domain].iova_pools[partition_no];
275
276 if (!pool)
277 return;
278
279 pool->free += size;
280 gen_pool_free(pool->gpool, iova, size);
281}
282
283int msm_use_iommu()
284{
Olav Haugan2d191032012-02-28 09:46:31 -0800285 return iommu_found();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286}
287
288static int __init msm_subsystem_iommu_init(void)
289{
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700290 int i, j;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700292 for (i = 0; i < ARRAY_SIZE(msm_iommu_domains); i++) {
293 msm_iommu_domains[i].domain = iommu_domain_alloc(0);
294 if (!msm_iommu_domains[i].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295 continue;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700297 for (j = 0; j < msm_iommu_domains[i].npools; j++) {
298 struct mem_pool *pool = &msm_iommu_domains[i].
299 iova_pools[j];
300 mutex_init(&pool->pool_mutex);
Olav Haugan2d191032012-02-28 09:46:31 -0800301 if (pool->size) {
302 pool->gpool = gen_pool_create(PAGE_SHIFT, -1);
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700303
Olav Haugan2d191032012-02-28 09:46:31 -0800304 if (!pool->gpool) {
305 pr_err("%s: could not allocate pool\n",
306 __func__);
307 pr_err("%s: domain %d iova space %d\n",
308 __func__, i, j);
309 continue;
310 }
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700311
Olav Haugan2d191032012-02-28 09:46:31 -0800312 if (gen_pool_add(pool->gpool, pool->paddr,
313 pool->size, -1)) {
314 pr_err("%s: could not add memory\n",
315 __func__);
316 pr_err("%s: domain %d pool %d\n",
317 __func__, i, j);
318 gen_pool_destroy(pool->gpool);
319 pool->gpool = NULL;
320 continue;
321 }
322 } else {
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700323 pool->gpool = NULL;
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325 }
326 }
327
328 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
329 int domain_idx;
330 struct device *ctx = msm_iommu_get_ctx(
331 msm_iommu_ctx_names[i].name);
332
333 if (!ctx)
334 continue;
335
336 domain_idx = msm_iommu_ctx_names[i].domain;
337
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700338 if (!msm_iommu_domains[domain_idx].domain)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339 continue;
340
Laura Abbott9f4a8e62011-08-29 19:08:07 -0700341 if (iommu_attach_device(msm_iommu_domains[domain_idx].domain,
342 ctx)) {
343 WARN(1, "%s: could not attach domain %d to context %s."
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344 " iommu programming will not occur.\n",
345 __func__, domain_idx,
346 msm_iommu_ctx_names[i].name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700347 continue;
348 }
349 }
350
351 return 0;
352}
353device_initcall(msm_subsystem_iommu_init);