blob: eb4582e7511e322edf77710b295dbb8909cfca4d [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>
21
22struct msm_iommu_domain {
23 int domain_idx;
24 int iova_pool_idx;
25};
26
27enum {
28 GLOBAL_DOMAIN,
29 VIDEO_DOMAIN,
30 EMPTY_DOMAIN,
31 MAX_DOMAINS
32};
33
34enum {
35 GLOBAL_MEMORY_POOL,
36 VIDEO_FIRMWARE_POOL,
37 VIDEO_ALLOC_POOL,
38};
39
40struct {
41 char *name;
42 int domain;
43} msm_iommu_ctx_names[] = {
44 /* Camera */
45 {
46 .name = "vpe_src",
47 .domain = GLOBAL_DOMAIN,
48 },
49 /* Camera */
50 {
51 .name = "vpe_dst",
52 .domain = GLOBAL_DOMAIN,
53 },
54 /* Camera */
55 {
56 .name = "vfe_imgwr",
57 .domain = GLOBAL_DOMAIN,
58 },
59 /* Camera */
60 {
61 .name = "vfe_misc",
62 .domain = GLOBAL_DOMAIN,
63 },
64 /* Camera */
65 {
66 .name = "ijpeg_src",
67 .domain = GLOBAL_DOMAIN,
68 },
69 /* Camera */
70 {
71 .name = "ijpeg_dst",
72 .domain = GLOBAL_DOMAIN,
73 },
74 /* Camera */
75 {
76 .name = "jpegd_src",
77 .domain = GLOBAL_DOMAIN,
78 },
79 /* Camera */
80 {
81 .name = "jpegd_dst",
82 .domain = GLOBAL_DOMAIN,
83 },
84 /* Display */
85 {
86 .name = "mdp_vg1",
87 .domain = GLOBAL_DOMAIN,
88 },
89 /* Display */
90 {
91 .name = "mdp_vg2",
92 .domain = GLOBAL_DOMAIN,
93 },
94 /* Display */
95 {
96 .name = "mdp_rgb1",
97 .domain = GLOBAL_DOMAIN,
98 },
99 /* Display */
100 {
101 .name = "mdp_rgb2",
102 .domain = GLOBAL_DOMAIN,
103 },
104 /* Rotator */
105 {
106 .name = "rot_src",
107 .domain = GLOBAL_DOMAIN,
108 },
109 /* Rotator */
110 {
111 .name = "rot_dst",
112 .domain = GLOBAL_DOMAIN,
113 },
114 /* Video */
115 {
116 .name = "vcodec_a_mm1",
117 .domain = VIDEO_DOMAIN,
118 },
119 /* Video */
120 {
121 .name = "vcodec_b_mm2",
122 .domain = VIDEO_DOMAIN,
123 },
124 /* Video */
125 {
126 .name = "vcodec_a_stream",
127 .domain = VIDEO_DOMAIN,
128 },
129};
130
131static struct iommu_domain *msm_iommu_domains[MAX_DOMAINS];
132
133static struct mem_pool msm_iommu_iova_pools[] = {
134 [GLOBAL_MEMORY_POOL] = {
135 .paddr = SZ_4K,
136 .size = SZ_2G - SZ_4K,
137 },
138 /*
139 * The video hardware has several constraints:
140 * 1) The start address for firmware must be 128K aligned
141 * 2) The video firmware must exist at a lower address than
142 * all other video allocations
143 * 3) Video allocations cannot be more than 256MB away from the
144 * firmware
145 *
146 * Splitting the video pools makes sure that firmware will
147 * always be lower than regular allocations and the maximum
148 * size of 256MB will be enforced.
149 */
150 [VIDEO_FIRMWARE_POOL] = {
151 .paddr = SZ_128K,
152 .size = SZ_16M - SZ_128K,
153 },
154 [VIDEO_ALLOC_POOL] = {
155 .paddr = SZ_16M,
156 .size = SZ_256M - SZ_16M - SZ_128K,
157 }
158};
159
160static struct msm_iommu_domain msm_iommu_subsystems[] = {
161 [JPEGD_SUBSYS_ID] = {
162 .domain_idx = GLOBAL_DOMAIN,
163 .iova_pool_idx = GLOBAL_MEMORY_POOL,
164 },
165 [VPE_SUBSYS_ID] = {
166 .domain_idx = GLOBAL_DOMAIN,
167 .iova_pool_idx = GLOBAL_MEMORY_POOL,
168 },
169 [MDP0_SUBSYS_ID] = {
170 .domain_idx = GLOBAL_DOMAIN,
171 .iova_pool_idx = GLOBAL_MEMORY_POOL,
172 },
173 [MDP1_SUBSYS_ID] = {
174 .domain_idx = GLOBAL_DOMAIN,
175 .iova_pool_idx = GLOBAL_MEMORY_POOL,
176 },
177 [ROT_SUBSYS_ID] = {
178 .domain_idx = GLOBAL_DOMAIN,
179 .iova_pool_idx = GLOBAL_MEMORY_POOL,
180 },
181 [IJPEG_SUBSYS_ID] = {
182 .domain_idx = GLOBAL_DOMAIN,
183 .iova_pool_idx = GLOBAL_MEMORY_POOL,
184 },
185 [VFE_SUBSYS_ID] = {
186 .domain_idx = GLOBAL_DOMAIN,
187 .iova_pool_idx = GLOBAL_MEMORY_POOL,
188 },
189 [VCODEC_A_SUBSYS_ID] = {
190 .domain_idx = VIDEO_DOMAIN,
191 .iova_pool_idx = VIDEO_ALLOC_POOL,
192 },
193 [VCODEC_B_SUBSYS_ID] = {
194 .domain_idx = VIDEO_DOMAIN,
195 .iova_pool_idx = VIDEO_ALLOC_POOL,
196 },
197 [VIDEO_FWARE_ID] = {
198 .domain_idx = VIDEO_DOMAIN,
199 .iova_pool_idx = VIDEO_FIRMWARE_POOL,
200 }
201};
202
203struct iommu_domain *msm_subsystem_get_domain(int subsys_id)
204{
205 int id = msm_iommu_subsystems[subsys_id].domain_idx;
206
207 return msm_iommu_domains[id];
208}
209
210struct mem_pool *msm_subsystem_get_pool(int subsys_id)
211{
212 int id = msm_iommu_subsystems[subsys_id].iova_pool_idx;
213
214 return &msm_iommu_iova_pools[id];
215}
216
217static int __init msm_subsystem_iommu_init(void)
218{
219 int i;
220
221 for (i = 0; i < (ARRAY_SIZE(msm_iommu_domains) - 1); i++)
222 msm_iommu_domains[i] = iommu_domain_alloc();
223
224 for (i = 0; i < ARRAY_SIZE(msm_iommu_iova_pools); i++) {
225 mutex_init(&msm_iommu_iova_pools[i].pool_mutex);
226 msm_iommu_iova_pools[i].gpool = gen_pool_create(PAGE_SHIFT, -1);
227
228 if (!msm_iommu_iova_pools[i].gpool) {
229 pr_err("%s: could not allocate iova pool. iommu"
230 " programming will not work with iova space"
231 " %d\n", __func__, i);
232 continue;
233 }
234
235 if (gen_pool_add(msm_iommu_iova_pools[i].gpool,
236 msm_iommu_iova_pools[i].paddr,
237 msm_iommu_iova_pools[i].size,
238 -1)) {
239 pr_err("%s: could not add memory to iova pool. iommu"
240 " programming will not work with iova space"
241 " %d\n", __func__, i);
242 gen_pool_destroy(msm_iommu_iova_pools[i].gpool);
243 msm_iommu_iova_pools[i].gpool = NULL;
244 continue;
245 }
246 }
247
248 for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
249 int domain_idx;
250 struct device *ctx = msm_iommu_get_ctx(
251 msm_iommu_ctx_names[i].name);
252
253 if (!ctx)
254 continue;
255
256 domain_idx = msm_iommu_ctx_names[i].domain;
257
258 if (!msm_iommu_domains[domain_idx])
259 continue;
260
261 if (iommu_attach_device(msm_iommu_domains[domain_idx], ctx)) {
262 pr_err("%s: could not attach domain %d to context %s."
263 " iommu programming will not occur.\n",
264 __func__, domain_idx,
265 msm_iommu_ctx_names[i].name);
266 msm_iommu_subsystems[i].domain_idx = EMPTY_DOMAIN;
267 continue;
268 }
269 }
270
271 return 0;
272}
273device_initcall(msm_subsystem_iommu_init);