blob: 4050e7d536c3dbaea0a209f916ee14e1bb84c9ff [file] [log] [blame]
Shubhraprakash Das79447952012-04-26 18:12:23 -06001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002 *
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 <linux/types.h>
14#include <linux/device.h>
15#include <linux/spinlock.h>
16#include <linux/genalloc.h>
17#include <linux/slab.h>
18#include <linux/iommu.h>
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060019#include <linux/msm_kgsl.h>
20
21#include "kgsl.h"
22#include "kgsl_device.h"
23#include "kgsl_mmu.h"
24#include "kgsl_sharedmem.h"
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -060025#include "kgsl_iommu.h"
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060026
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -060027/*
28 * kgsl_iommu_disable_clk - Disable iommu clocks
29 * @mmu - Pointer to mmu structure
30 *
31 * Disables iommu clocks
32 * Return - void
33 */
34static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
35{
36 struct kgsl_iommu *iommu = mmu->priv;
37 struct msm_iommu_drvdata *iommu_drvdata;
38 int i, j;
39
40 for (i = 0; i < iommu->unit_count; i++) {
41 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
42 for (j = 0; j < iommu_unit->dev_count; j++) {
43 if (!iommu_unit->dev[j].clk_enabled)
44 continue;
45 iommu_drvdata = dev_get_drvdata(
46 iommu_unit->dev[j].dev->parent);
47 if (iommu_drvdata->clk)
48 clk_disable_unprepare(iommu_drvdata->clk);
49 clk_disable_unprepare(iommu_drvdata->pclk);
50 iommu_unit->dev[j].clk_enabled = false;
51 }
52 }
53}
54
55/*
56 * kgsl_iommu_enable_clk - Enable iommu clocks
57 * @mmu - Pointer to mmu structure
58 * @ctx_id - The context bank whose clocks are to be turned on
59 *
60 * Enables iommu clocks of a given context
61 * Return: 0 on success else error code
62 */
63static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
64 int ctx_id)
65{
66 int ret = 0;
67 int i, j;
68 struct kgsl_iommu *iommu = mmu->priv;
69 struct msm_iommu_drvdata *iommu_drvdata;
70
71 for (i = 0; i < iommu->unit_count; i++) {
72 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
73 for (j = 0; j < iommu_unit->dev_count; j++) {
74 if (iommu_unit->dev[j].clk_enabled ||
75 ctx_id != iommu_unit->dev[j].ctx_id)
76 continue;
77 iommu_drvdata =
78 dev_get_drvdata(iommu_unit->dev[j].dev->parent);
79 ret = clk_prepare_enable(iommu_drvdata->pclk);
80 if (ret)
81 goto done;
82 if (iommu_drvdata->clk) {
83 ret = clk_prepare_enable(iommu_drvdata->clk);
84 if (ret) {
85 clk_disable_unprepare(
86 iommu_drvdata->pclk);
87 goto done;
88 }
89 }
90 iommu_unit->dev[j].clk_enabled = true;
91 }
92 }
93done:
94 if (ret)
95 kgsl_iommu_disable_clk(mmu);
96 return ret;
97}
98
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060099static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
100 unsigned int pt_base)
101{
Shubhraprakash Das528aa462012-03-01 14:56:28 -0700102 struct iommu_domain *domain = pt ? pt->priv : NULL;
103 return domain && pt_base && ((unsigned int)domain == pt_base);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600104}
105
106static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
107{
108 struct iommu_domain *domain = mmu_specific_pt;
109 if (domain)
110 iommu_domain_free(domain);
111}
112
113void *kgsl_iommu_create_pagetable(void)
114{
115 struct iommu_domain *domain = iommu_domain_alloc(0);
116 if (!domain)
117 KGSL_CORE_ERR("Failed to create iommu domain\n");
118
119 return domain;
120}
121
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600122/*
123 * kgsl_detach_pagetable_iommu_domain - Detach the IOMMU unit from a
124 * pagetable
125 * @mmu - Pointer to the device mmu structure
126 * @priv - Flag indicating whether the private or user context is to be
127 * detached
128 *
129 * Detach the IOMMU unit with the domain that is contained in the
130 * hwpagetable of the given mmu. After detaching the IOMMU unit is not
131 * in use because the PTBR will not be set after a detach
132 * Return - void
133 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600134static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
135{
136 struct iommu_domain *domain;
137 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600138 int i, j;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600139
140 BUG_ON(mmu->hwpagetable == NULL);
141 BUG_ON(mmu->hwpagetable->priv == NULL);
142
143 domain = mmu->hwpagetable->priv;
144
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600145 for (i = 0; i < iommu->unit_count; i++) {
146 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
147 for (j = 0; j < iommu_unit->dev_count; j++) {
148 if (iommu_unit->dev[j].attached) {
149 iommu_detach_device(domain,
150 iommu_unit->dev[j].dev);
151 iommu_unit->dev[j].attached = false;
152 KGSL_MEM_INFO(mmu->device, "iommu %p detached "
153 "from user dev of MMU: %p\n",
154 domain, mmu);
155 }
156 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600157 }
158}
159
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600160/*
161 * kgsl_attach_pagetable_iommu_domain - Attach the IOMMU unit to a
162 * pagetable, i.e set the IOMMU's PTBR to the pagetable address and
163 * setup other IOMMU registers for the device so that it becomes
164 * active
165 * @mmu - Pointer to the device mmu structure
166 * @priv - Flag indicating whether the private or user context is to be
167 * attached
168 *
169 * Attach the IOMMU unit with the domain that is contained in the
170 * hwpagetable of the given mmu.
171 * Return - 0 on success else error code
172 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600173static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
174{
175 struct iommu_domain *domain;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600176 struct kgsl_iommu *iommu = mmu->priv;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600177 int i, j, ret = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600178
179 BUG_ON(mmu->hwpagetable == NULL);
180 BUG_ON(mmu->hwpagetable->priv == NULL);
181
182 domain = mmu->hwpagetable->priv;
183
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600184 /*
185 * Loop through all the iommu devcies under all iommu units and
186 * attach the domain
187 */
188 for (i = 0; i < iommu->unit_count; i++) {
189 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
190 for (j = 0; j < iommu_unit->dev_count; j++) {
191 if (!iommu_unit->dev[j].attached) {
192 ret = iommu_attach_device(domain,
193 iommu_unit->dev[j].dev);
194 if (ret) {
195 KGSL_MEM_ERR(mmu->device,
196 "Failed to attach device, err %d\n",
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700197 ret);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600198 goto done;
199 }
200 iommu_unit->dev[j].attached = true;
201 KGSL_MEM_INFO(mmu->device,
202 "iommu pt %p attached to dev %p, ctx_id %d\n",
203 domain, iommu_unit->dev[j].dev,
204 iommu_unit->dev[j].ctx_id);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700205 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600206 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600207 }
208done:
209 return ret;
210}
211
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600212/*
213 * _get_iommu_ctxs - Get device pointer to IOMMU contexts
214 * @mmu - Pointer to mmu device
215 * data - Pointer to the platform data containing information about
216 * iommu devices for one iommu unit
217 * unit_id - The IOMMU unit number. This is not a specific ID but just
218 * a serial number. The serial numbers are treated as ID's of the
219 * IOMMU units
220 *
221 * Return - 0 on success else error code
222 */
223static int _get_iommu_ctxs(struct kgsl_mmu *mmu,
224 struct kgsl_device_iommu_data *data, unsigned int unit_id)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700225{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600226 struct kgsl_iommu *iommu = mmu->priv;
227 struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[unit_id];
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700228 int i;
229
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600230 if (data->iommu_ctx_count > KGSL_IOMMU_MAX_DEVS_PER_UNIT) {
231 KGSL_CORE_ERR("Too many iommu devices defined for an "
232 "IOMMU unit\n");
233 return -EINVAL;
234 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700235
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600236 for (i = 0; i < data->iommu_ctx_count; i++) {
237 if (!data->iommu_ctxs[i].iommu_ctx_name)
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700238 continue;
239
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600240 iommu_unit->dev[iommu_unit->dev_count].dev =
241 msm_iommu_get_ctx(data->iommu_ctxs[i].iommu_ctx_name);
242 if (iommu_unit->dev[iommu_unit->dev_count].dev == NULL) {
243 KGSL_CORE_ERR("Failed to get iommu dev handle for "
244 "device %s\n", data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700245 return -EINVAL;
246 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600247 if (KGSL_IOMMU_CONTEXT_USER != data->iommu_ctxs[i].ctx_id &&
248 KGSL_IOMMU_CONTEXT_PRIV != data->iommu_ctxs[i].ctx_id) {
249 KGSL_CORE_ERR("Invalid context ID defined: %d\n",
250 data->iommu_ctxs[i].ctx_id);
251 return -EINVAL;
252 }
253 iommu_unit->dev[iommu_unit->dev_count].ctx_id =
254 data->iommu_ctxs[i].ctx_id;
255 KGSL_DRV_INFO(mmu->device,
256 "Obtained dev handle %p for iommu context %s\n",
257 iommu_unit->dev[iommu_unit->dev_count].dev,
258 data->iommu_ctxs[i].iommu_ctx_name);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700259
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600260 iommu_unit->dev_count++;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700261 }
262
263 return 0;
264}
265
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600266/*
267 * kgsl_get_iommu_ctxt - Get device pointer to IOMMU contexts
268 * @mmu - Pointer to mmu device
269 *
270 * Get the device pointers for the IOMMU user and priv contexts of the
271 * kgsl device
272 * Return - 0 on success else error code
273 */
274static int kgsl_get_iommu_ctxt(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600275{
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600276 struct platform_device *pdev =
277 container_of(mmu->device->parentdev, struct platform_device,
278 dev);
279 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
280 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700281 int i, ret = 0;
282
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600283 /* Go through the IOMMU data and get all the context devices */
284 if (KGSL_IOMMU_MAX_UNITS < pdata_dev->iommu_count) {
285 KGSL_CORE_ERR("Too many IOMMU units defined\n");
286 ret = -EINVAL;
287 goto done;
288 }
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700289
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600290 for (i = 0; i < pdata_dev->iommu_count; i++) {
291 ret = _get_iommu_ctxs(mmu, &pdata_dev->iommu_data[i], i);
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700292 if (ret)
293 break;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600294 }
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600295 iommu->unit_count = pdata_dev->iommu_count;
296done:
Jordan Crouse46cf4bb2012-02-21 08:54:52 -0700297 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600298}
299
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600300/*
301 * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
302 * of the respective iommu units
303 * @mmu - Pointer to mmu structure
304 *
305 * Return - 0 on success else error code
306 */
307static int kgsl_set_register_map(struct kgsl_mmu *mmu)
308{
309 struct platform_device *pdev =
310 container_of(mmu->device->parentdev, struct platform_device,
311 dev);
312 struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
313 struct kgsl_iommu *iommu = mmu->device->mmu.priv;
314 struct kgsl_iommu_unit *iommu_unit;
315 int i = 0, ret = 0;
316
317 for (; i < pdata_dev->iommu_count; i++) {
318 struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
319 iommu_unit = &iommu->iommu_units[i];
320 /* set up the IOMMU register map for the given IOMMU unit */
321 if (!data.physstart || !data.physend) {
322 KGSL_CORE_ERR("The register range for IOMMU unit not"
323 " specified\n");
324 ret = -EINVAL;
325 goto err;
326 }
327 iommu_unit->reg_map.hostptr = ioremap(data.physstart,
328 data.physend - data.physstart + 1);
329 if (!iommu_unit->reg_map.hostptr) {
330 KGSL_CORE_ERR("Failed to map SMMU register address "
331 "space from %x to %x\n", data.physstart,
332 data.physend - data.physstart + 1);
333 ret = -ENOMEM;
334 i--;
335 goto err;
336 }
337 iommu_unit->reg_map.size = data.physend - data.physstart + 1;
338 iommu_unit->reg_map.physaddr = data.physstart;
339 }
340 iommu->unit_count = pdata_dev->iommu_count;
341 return ret;
342err:
343 /* Unmap any mapped IOMMU regions */
344 for (; i >= 0; i--) {
345 iommu_unit = &iommu->iommu_units[i];
346 iounmap(iommu_unit->reg_map.hostptr);
347 iommu_unit->reg_map.size = 0;
348 iommu_unit->reg_map.physaddr = 0;
349 }
350 return ret;
351}
352
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600353static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600354 struct kgsl_pagetable *pagetable)
355{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600356 if (mmu->flags & KGSL_FLAGS_STARTED) {
357 /* page table not current, then setup mmu to use new
358 * specified page table
359 */
360 if (mmu->hwpagetable != pagetable) {
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600361 kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600362 kgsl_detach_pagetable_iommu_domain(mmu);
363 mmu->hwpagetable = pagetable;
364 if (mmu->hwpagetable)
365 kgsl_attach_pagetable_iommu_domain(mmu);
366 }
367 }
368}
369
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600370static int kgsl_iommu_init(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600371{
372 /*
373 * intialize device mmu
374 *
375 * call this with the global lock held
376 */
377 int status = 0;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600378 struct kgsl_iommu *iommu;
379
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600380 iommu = kzalloc(sizeof(struct kgsl_iommu), GFP_KERNEL);
381 if (!iommu) {
382 KGSL_CORE_ERR("kzalloc(%d) failed\n",
383 sizeof(struct kgsl_iommu));
384 return -ENOMEM;
385 }
386
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600387 mmu->priv = iommu;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600388 status = kgsl_get_iommu_ctxt(mmu);
389 if (status)
390 goto done;
Shubhraprakash Dase9eefd72012-05-01 01:44:59 -0600391 status = kgsl_set_register_map(mmu);
392 if (status)
393 goto done;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600394
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600395 dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600396 __func__);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600397done:
398 if (status) {
399 kfree(iommu);
400 mmu->priv = NULL;
401 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600402 return status;
403}
404
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600405static int kgsl_iommu_start(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600406{
407 int status;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600408
409 if (mmu->flags & KGSL_FLAGS_STARTED)
410 return 0;
411
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600412 kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600413 if (mmu->defaultpagetable == NULL)
414 mmu->defaultpagetable =
415 kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
416 /* Return error if the default pagetable doesn't exist */
417 if (mmu->defaultpagetable == NULL)
418 return -ENOMEM;
419 mmu->hwpagetable = mmu->defaultpagetable;
420
421 status = kgsl_attach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600422 if (!status) {
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600423 mmu->flags |= KGSL_FLAGS_STARTED;
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600424 } else {
425 kgsl_detach_pagetable_iommu_domain(mmu);
426 mmu->hwpagetable = NULL;
427 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600428
429 return status;
430}
431
432static int
433kgsl_iommu_unmap(void *mmu_specific_pt,
434 struct kgsl_memdesc *memdesc)
435{
436 int ret;
437 unsigned int range = memdesc->size;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600438 struct iommu_domain *domain = (struct iommu_domain *)
439 mmu_specific_pt;
440
441 /* All GPU addresses as assigned are page aligned, but some
442 functions purturb the gpuaddr with an offset, so apply the
443 mask here to make sure we have the right address */
444
445 unsigned int gpuaddr = memdesc->gpuaddr & KGSL_MMU_ALIGN_MASK;
446
447 if (range == 0 || gpuaddr == 0)
448 return 0;
449
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600450 ret = iommu_unmap_range(domain, gpuaddr, range);
451 if (ret)
452 KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
453 "with err: %d\n", domain, gpuaddr,
454 range, ret);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600455
456 return 0;
457}
458
459static int
460kgsl_iommu_map(void *mmu_specific_pt,
461 struct kgsl_memdesc *memdesc,
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600462 unsigned int protflags,
463 unsigned int *tlb_flags)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600464{
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600465 int ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600466 unsigned int iommu_virt_addr;
Jordan Croused17e9aa2011-10-12 16:57:48 -0600467 struct iommu_domain *domain = mmu_specific_pt;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600468
469 BUG_ON(NULL == domain);
470
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600471
Jordan Croused17e9aa2011-10-12 16:57:48 -0600472 iommu_virt_addr = memdesc->gpuaddr;
473
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600474 ret = iommu_map_range(domain, iommu_virt_addr, memdesc->sg,
Olav Hauganf310cf22012-05-08 08:42:49 -0700475 memdesc->size, (IOMMU_READ | IOMMU_WRITE));
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600476 if (ret) {
477 KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
478 "failed with err: %d\n", domain,
479 iommu_virt_addr, memdesc->sg, memdesc->size,
Stepan Moskovchenko6ee3be82011-11-08 15:24:53 -0800480 0, ret);
Shubhraprakash Das08894b92011-10-14 11:42:25 -0600481 return ret;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600482 }
483
Shubhraprakash Dasf764e462012-04-26 15:38:09 -0600484#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
485 /*
486 * Flushing only required if per process pagetables are used. With
487 * global case, flushing will happen inside iommu_map function
488 */
489 if (!ret)
490 *tlb_flags = UINT_MAX;
491#endif
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600492 return ret;
493}
494
Shubhraprakash Das79447952012-04-26 18:12:23 -0600495static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600496{
497 /*
498 * stop device mmu
499 *
500 * call this with the global lock held
501 */
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600502
503 if (mmu->flags & KGSL_FLAGS_STARTED) {
504 /* detach iommu attachment */
505 kgsl_detach_pagetable_iommu_domain(mmu);
Shubhraprakash Daseb6df1d2012-05-01 00:55:35 -0600506 mmu->hwpagetable = NULL;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600507
508 mmu->flags &= ~KGSL_FLAGS_STARTED;
509 }
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600510}
511
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600512static int kgsl_iommu_close(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600513{
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600514 if (mmu->defaultpagetable)
515 kgsl_mmu_putpagetable(mmu->defaultpagetable);
516
517 return 0;
518}
519
520static unsigned int
Shubhraprakash Das1c528262012-04-26 17:38:13 -0600521kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600522{
Shubhraprakash Das2b8716b2012-05-04 16:58:40 -0600523 unsigned int pt_base;
524 struct kgsl_iommu *iommu = mmu->priv;
525 /* Return the current pt base by reading IOMMU pt_base register */
526 kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
527 pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
528 (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
529 KGSL_IOMMU_TTBR0);
530 kgsl_iommu_disable_clk(mmu);
531 return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
532 KGSL_IOMMU_TTBR0_PA_SHIFT);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600533}
534
535struct kgsl_mmu_ops iommu_ops = {
536 .mmu_init = kgsl_iommu_init,
537 .mmu_close = kgsl_iommu_close,
538 .mmu_start = kgsl_iommu_start,
539 .mmu_stop = kgsl_iommu_stop,
540 .mmu_setstate = kgsl_iommu_setstate,
541 .mmu_device_setstate = NULL,
542 .mmu_pagefault = NULL,
543 .mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
Shubhraprakash Das9fb38ac2012-05-01 00:41:30 -0600544 .mmu_enable_clk = kgsl_iommu_enable_clk,
545 .mmu_disable_clk = kgsl_iommu_disable_clk,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600546};
547
548struct kgsl_mmu_pt_ops iommu_pt_ops = {
549 .mmu_map = kgsl_iommu_map,
550 .mmu_unmap = kgsl_iommu_unmap,
551 .mmu_create_pagetable = kgsl_iommu_create_pagetable,
552 .mmu_destroy_pagetable = kgsl_iommu_destroy_pagetable,
553 .mmu_pt_equal = kgsl_iommu_pt_equal,
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600554};