Linux Audio

Check our new training course

Loading...
v4.6
  1/* 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 * You should have received a copy of the GNU General Public License
 13 * along with this program; if not, write to the Free Software
 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 15 * 02110-1301, USA.
 16 */
 17
 18#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 19
 20#include <linux/kernel.h>
 21#include <linux/module.h>
 22#include <linux/platform_device.h>
 23#include <linux/io.h>
 24#include <linux/clk.h>
 25#include <linux/iommu.h>
 26#include <linux/interrupt.h>
 27#include <linux/err.h>
 28#include <linux/slab.h>
 29
 30#include "msm_iommu_hw-8xxx.h"
 31#include "msm_iommu.h"
 32
 33struct iommu_ctx_iter_data {
 34	/* input */
 35	const char *name;
 36
 37	/* output */
 38	struct device *dev;
 39};
 40
 41static struct platform_device *msm_iommu_root_dev;
 42
 43static int each_iommu_ctx(struct device *dev, void *data)
 44{
 45	struct iommu_ctx_iter_data *res = data;
 46	struct msm_iommu_ctx_dev *c = dev->platform_data;
 47
 48	if (!res || !c || !c->name || !res->name)
 49		return -EINVAL;
 50
 51	if (!strcmp(res->name, c->name)) {
 52		res->dev = dev;
 53		return 1;
 54	}
 55	return 0;
 56}
 57
 58static int each_iommu(struct device *dev, void *data)
 59{
 60	return device_for_each_child(dev, data, each_iommu_ctx);
 61}
 62
 63struct device *msm_iommu_get_ctx(const char *ctx_name)
 64{
 65	struct iommu_ctx_iter_data r;
 66	int found;
 67
 68	if (!msm_iommu_root_dev) {
 69		pr_err("No root IOMMU device.\n");
 70		goto fail;
 71	}
 72
 73	r.name = ctx_name;
 74	found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
 75
 76	if (!found) {
 77		pr_err("Could not find context <%s>\n", ctx_name);
 78		goto fail;
 79	}
 80
 81	return r.dev;
 82fail:
 83	return NULL;
 84}
 85EXPORT_SYMBOL(msm_iommu_get_ctx);
 86
 87static void msm_iommu_reset(void __iomem *base, int ncb)
 88{
 89	int ctx;
 90
 91	SET_RPUE(base, 0);
 92	SET_RPUEIE(base, 0);
 93	SET_ESRRESTORE(base, 0);
 94	SET_TBE(base, 0);
 95	SET_CR(base, 0);
 96	SET_SPDMBE(base, 0);
 97	SET_TESTBUSCR(base, 0);
 98	SET_TLBRSW(base, 0);
 99	SET_GLOBAL_TLBIALL(base, 0);
100	SET_RPU_ACR(base, 0);
101	SET_TLBLKCRWE(base, 1);
102
103	for (ctx = 0; ctx < ncb; ctx++) {
104		SET_BPRCOSH(base, ctx, 0);
105		SET_BPRCISH(base, ctx, 0);
106		SET_BPRCNSH(base, ctx, 0);
107		SET_BPSHCFG(base, ctx, 0);
108		SET_BPMTCFG(base, ctx, 0);
109		SET_ACTLR(base, ctx, 0);
110		SET_SCTLR(base, ctx, 0);
111		SET_FSRRESTORE(base, ctx, 0);
112		SET_TTBR0(base, ctx, 0);
113		SET_TTBR1(base, ctx, 0);
114		SET_TTBCR(base, ctx, 0);
115		SET_BFBCR(base, ctx, 0);
116		SET_PAR(base, ctx, 0);
117		SET_FAR(base, ctx, 0);
118		SET_CTX_TLBIALL(base, ctx, 0);
119		SET_TLBFLPTER(base, ctx, 0);
120		SET_TLBSLPTER(base, ctx, 0);
121		SET_TLBLKCR(base, ctx, 0);
122		SET_PRRR(base, ctx, 0);
123		SET_NMRR(base, ctx, 0);
124		SET_CONTEXTIDR(base, ctx, 0);
125	}
126}
127
128static int msm_iommu_probe(struct platform_device *pdev)
129{
130	struct resource *r;
131	struct clk *iommu_clk;
132	struct clk *iommu_pclk;
133	struct msm_iommu_drvdata *drvdata;
134	struct msm_iommu_dev *iommu_dev = dev_get_platdata(&pdev->dev);
135	void __iomem *regs_base;
 
136	int ret, irq, par;
137
138	if (pdev->id == -1) {
139		msm_iommu_root_dev = pdev;
140		return 0;
141	}
142
143	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
144
145	if (!drvdata) {
146		ret = -ENOMEM;
147		goto fail;
148	}
149
150	if (!iommu_dev) {
151		ret = -ENODEV;
152		goto fail;
153	}
154
155	iommu_pclk = clk_get(NULL, "smmu_pclk");
156	if (IS_ERR(iommu_pclk)) {
157		ret = -ENODEV;
158		goto fail;
159	}
160
161	ret = clk_prepare_enable(iommu_pclk);
162	if (ret)
163		goto fail_enable;
164
165	iommu_clk = clk_get(&pdev->dev, "iommu_clk");
166
167	if (!IS_ERR(iommu_clk))	{
168		if (clk_get_rate(iommu_clk) == 0)
169			clk_set_rate(iommu_clk, 1);
170
171		ret = clk_prepare_enable(iommu_clk);
172		if (ret) {
173			clk_put(iommu_clk);
174			goto fail_pclk;
175		}
176	} else
177		iommu_clk = NULL;
178
179	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
180	regs_base = devm_ioremap_resource(&pdev->dev, r);
181	if (IS_ERR(regs_base)) {
182		ret = PTR_ERR(regs_base);
 
 
 
 
 
 
 
 
 
 
183		goto fail_clk;
184	}
185
 
 
 
 
 
 
 
 
 
186	irq = platform_get_irq_byname(pdev, "secure_irq");
187	if (irq < 0) {
188		ret = -ENODEV;
189		goto fail_clk;
190	}
191
192	msm_iommu_reset(regs_base, iommu_dev->ncb);
193
194	SET_M(regs_base, 0, 1);
195	SET_PAR(regs_base, 0, 0);
196	SET_V2PCFG(regs_base, 0, 1);
197	SET_V2PPR(regs_base, 0, 0);
198	par = GET_PAR(regs_base, 0);
199	SET_V2PCFG(regs_base, 0, 0);
200	SET_M(regs_base, 0, 0);
201
202	if (!par) {
203		pr_err("%s: Invalid PAR value detected\n", iommu_dev->name);
204		ret = -ENODEV;
205		goto fail_clk;
206	}
207
208	ret = request_irq(irq, msm_iommu_fault_handler, 0,
209			"msm_iommu_secure_irpt_handler", drvdata);
210	if (ret) {
211		pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
212		goto fail_clk;
213	}
214
215
216	drvdata->pclk = iommu_pclk;
217	drvdata->clk = iommu_clk;
218	drvdata->base = regs_base;
219	drvdata->irq = irq;
220	drvdata->ncb = iommu_dev->ncb;
221
222	pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
223		iommu_dev->name, regs_base, irq, iommu_dev->ncb);
224
225	platform_set_drvdata(pdev, drvdata);
226
227	clk_disable(iommu_clk);
 
228
229	clk_disable(iommu_pclk);
230
231	return 0;
 
 
 
 
232fail_clk:
233	if (iommu_clk) {
234		clk_disable(iommu_clk);
235		clk_put(iommu_clk);
236	}
237fail_pclk:
238	clk_disable_unprepare(iommu_pclk);
239fail_enable:
240	clk_put(iommu_pclk);
241fail:
242	kfree(drvdata);
243	return ret;
244}
245
246static int msm_iommu_remove(struct platform_device *pdev)
247{
248	struct msm_iommu_drvdata *drv = NULL;
249
250	drv = platform_get_drvdata(pdev);
251	if (drv) {
252		if (drv->clk) {
253			clk_unprepare(drv->clk);
254			clk_put(drv->clk);
255		}
256		clk_unprepare(drv->pclk);
257		clk_put(drv->pclk);
258		memset(drv, 0, sizeof(*drv));
259		kfree(drv);
260	}
261	return 0;
262}
263
264static int msm_iommu_ctx_probe(struct platform_device *pdev)
265{
266	struct msm_iommu_ctx_dev *c = dev_get_platdata(&pdev->dev);
267	struct msm_iommu_drvdata *drvdata;
268	struct msm_iommu_ctx_drvdata *ctx_drvdata;
269	int i, ret;
270
271	if (!c || !pdev->dev.parent)
272		return -EINVAL;
273
274	drvdata = dev_get_drvdata(pdev->dev.parent);
275	if (!drvdata)
276		return -ENODEV;
277
278	ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
279	if (!ctx_drvdata)
280		return -ENOMEM;
281
282	ctx_drvdata->num = c->num;
283	ctx_drvdata->pdev = pdev;
284
285	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
286	platform_set_drvdata(pdev, ctx_drvdata);
287
288	ret = clk_prepare_enable(drvdata->pclk);
289	if (ret)
290		goto fail;
291
292	if (drvdata->clk) {
293		ret = clk_prepare_enable(drvdata->clk);
294		if (ret) {
295			clk_disable_unprepare(drvdata->pclk);
296			goto fail;
297		}
298	}
299
300	/* Program the M2V tables for this context */
301	for (i = 0; i < MAX_NUM_MIDS; i++) {
302		int mid = c->mids[i];
303		if (mid == -1)
304			break;
305
306		SET_M2VCBR_N(drvdata->base, mid, 0);
307		SET_CBACR_N(drvdata->base, c->num, 0);
308
309		/* Set VMID = 0 */
310		SET_VMID(drvdata->base, mid, 0);
311
312		/* Set the context number for that MID to this context */
313		SET_CBNDX(drvdata->base, mid, c->num);
314
315		/* Set MID associated with this context bank to 0*/
316		SET_CBVMID(drvdata->base, c->num, 0);
317
318		/* Set the ASID for TLB tagging for this context */
319		SET_CONTEXTIDR_ASID(drvdata->base, c->num, c->num);
320
321		/* Set security bit override to be Non-secure */
322		SET_NSCFG(drvdata->base, mid, 3);
323	}
324
325	clk_disable(drvdata->clk);
 
326	clk_disable(drvdata->pclk);
327
328	dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
329	return 0;
330fail:
331	kfree(ctx_drvdata);
332	return ret;
333}
334
335static int msm_iommu_ctx_remove(struct platform_device *pdev)
336{
337	struct msm_iommu_ctx_drvdata *drv = NULL;
338	drv = platform_get_drvdata(pdev);
339	if (drv) {
340		memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
341		kfree(drv);
342	}
343	return 0;
344}
345
346static struct platform_driver msm_iommu_driver = {
347	.driver = {
348		.name	= "msm_iommu",
349	},
350	.probe		= msm_iommu_probe,
351	.remove		= msm_iommu_remove,
352};
353
354static struct platform_driver msm_iommu_ctx_driver = {
355	.driver = {
356		.name	= "msm_iommu_ctx",
357	},
358	.probe		= msm_iommu_ctx_probe,
359	.remove		= msm_iommu_ctx_remove,
360};
361
362static struct platform_driver * const drivers[] = {
363	&msm_iommu_driver,
364	&msm_iommu_ctx_driver,
365};
366
367static int __init msm_iommu_driver_init(void)
368{
369	return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370}
371
372static void __exit msm_iommu_driver_exit(void)
373{
374	platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
 
375}
376
377subsys_initcall(msm_iommu_driver_init);
378module_exit(msm_iommu_driver_exit);
379
380MODULE_LICENSE("GPL v2");
381MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
v3.15
  1/* 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 * You should have received a copy of the GNU General Public License
 13 * along with this program; if not, write to the Free Software
 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 15 * 02110-1301, USA.
 16 */
 17
 18#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 19
 20#include <linux/kernel.h>
 21#include <linux/module.h>
 22#include <linux/platform_device.h>
 23#include <linux/io.h>
 24#include <linux/clk.h>
 25#include <linux/iommu.h>
 26#include <linux/interrupt.h>
 27#include <linux/err.h>
 28#include <linux/slab.h>
 29
 30#include "msm_iommu_hw-8xxx.h"
 31#include "msm_iommu.h"
 32
 33struct iommu_ctx_iter_data {
 34	/* input */
 35	const char *name;
 36
 37	/* output */
 38	struct device *dev;
 39};
 40
 41static struct platform_device *msm_iommu_root_dev;
 42
 43static int each_iommu_ctx(struct device *dev, void *data)
 44{
 45	struct iommu_ctx_iter_data *res = data;
 46	struct msm_iommu_ctx_dev *c = dev->platform_data;
 47
 48	if (!res || !c || !c->name || !res->name)
 49		return -EINVAL;
 50
 51	if (!strcmp(res->name, c->name)) {
 52		res->dev = dev;
 53		return 1;
 54	}
 55	return 0;
 56}
 57
 58static int each_iommu(struct device *dev, void *data)
 59{
 60	return device_for_each_child(dev, data, each_iommu_ctx);
 61}
 62
 63struct device *msm_iommu_get_ctx(const char *ctx_name)
 64{
 65	struct iommu_ctx_iter_data r;
 66	int found;
 67
 68	if (!msm_iommu_root_dev) {
 69		pr_err("No root IOMMU device.\n");
 70		goto fail;
 71	}
 72
 73	r.name = ctx_name;
 74	found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
 75
 76	if (!found) {
 77		pr_err("Could not find context <%s>\n", ctx_name);
 78		goto fail;
 79	}
 80
 81	return r.dev;
 82fail:
 83	return NULL;
 84}
 85EXPORT_SYMBOL(msm_iommu_get_ctx);
 86
 87static void msm_iommu_reset(void __iomem *base, int ncb)
 88{
 89	int ctx;
 90
 91	SET_RPUE(base, 0);
 92	SET_RPUEIE(base, 0);
 93	SET_ESRRESTORE(base, 0);
 94	SET_TBE(base, 0);
 95	SET_CR(base, 0);
 96	SET_SPDMBE(base, 0);
 97	SET_TESTBUSCR(base, 0);
 98	SET_TLBRSW(base, 0);
 99	SET_GLOBAL_TLBIALL(base, 0);
100	SET_RPU_ACR(base, 0);
101	SET_TLBLKCRWE(base, 1);
102
103	for (ctx = 0; ctx < ncb; ctx++) {
104		SET_BPRCOSH(base, ctx, 0);
105		SET_BPRCISH(base, ctx, 0);
106		SET_BPRCNSH(base, ctx, 0);
107		SET_BPSHCFG(base, ctx, 0);
108		SET_BPMTCFG(base, ctx, 0);
109		SET_ACTLR(base, ctx, 0);
110		SET_SCTLR(base, ctx, 0);
111		SET_FSRRESTORE(base, ctx, 0);
112		SET_TTBR0(base, ctx, 0);
113		SET_TTBR1(base, ctx, 0);
114		SET_TTBCR(base, ctx, 0);
115		SET_BFBCR(base, ctx, 0);
116		SET_PAR(base, ctx, 0);
117		SET_FAR(base, ctx, 0);
118		SET_CTX_TLBIALL(base, ctx, 0);
119		SET_TLBFLPTER(base, ctx, 0);
120		SET_TLBSLPTER(base, ctx, 0);
121		SET_TLBLKCR(base, ctx, 0);
122		SET_PRRR(base, ctx, 0);
123		SET_NMRR(base, ctx, 0);
124		SET_CONTEXTIDR(base, ctx, 0);
125	}
126}
127
128static int msm_iommu_probe(struct platform_device *pdev)
129{
130	struct resource *r, *r2;
131	struct clk *iommu_clk;
132	struct clk *iommu_pclk;
133	struct msm_iommu_drvdata *drvdata;
134	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
135	void __iomem *regs_base;
136	resource_size_t	len;
137	int ret, irq, par;
138
139	if (pdev->id == -1) {
140		msm_iommu_root_dev = pdev;
141		return 0;
142	}
143
144	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
145
146	if (!drvdata) {
147		ret = -ENOMEM;
148		goto fail;
149	}
150
151	if (!iommu_dev) {
152		ret = -ENODEV;
153		goto fail;
154	}
155
156	iommu_pclk = clk_get(NULL, "smmu_pclk");
157	if (IS_ERR(iommu_pclk)) {
158		ret = -ENODEV;
159		goto fail;
160	}
161
162	ret = clk_prepare_enable(iommu_pclk);
163	if (ret)
164		goto fail_enable;
165
166	iommu_clk = clk_get(&pdev->dev, "iommu_clk");
167
168	if (!IS_ERR(iommu_clk))	{
169		if (clk_get_rate(iommu_clk) == 0)
170			clk_set_rate(iommu_clk, 1);
171
172		ret = clk_prepare_enable(iommu_clk);
173		if (ret) {
174			clk_put(iommu_clk);
175			goto fail_pclk;
176		}
177	} else
178		iommu_clk = NULL;
179
180	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
181
182	if (!r) {
183		ret = -ENODEV;
184		goto fail_clk;
185	}
186
187	len = resource_size(r);
188
189	r2 = request_mem_region(r->start, len, r->name);
190	if (!r2) {
191		pr_err("Could not request memory region: start=%p, len=%d\n",
192							(void *) r->start, len);
193		ret = -EBUSY;
194		goto fail_clk;
195	}
196
197	regs_base = ioremap(r2->start, len);
198
199	if (!regs_base) {
200		pr_err("Could not ioremap: start=%p, len=%d\n",
201			 (void *) r2->start, len);
202		ret = -EBUSY;
203		goto fail_mem;
204	}
205
206	irq = platform_get_irq_byname(pdev, "secure_irq");
207	if (irq < 0) {
208		ret = -ENODEV;
209		goto fail_io;
210	}
211
212	msm_iommu_reset(regs_base, iommu_dev->ncb);
213
214	SET_M(regs_base, 0, 1);
215	SET_PAR(regs_base, 0, 0);
216	SET_V2PCFG(regs_base, 0, 1);
217	SET_V2PPR(regs_base, 0, 0);
218	par = GET_PAR(regs_base, 0);
219	SET_V2PCFG(regs_base, 0, 0);
220	SET_M(regs_base, 0, 0);
221
222	if (!par) {
223		pr_err("%s: Invalid PAR value detected\n", iommu_dev->name);
224		ret = -ENODEV;
225		goto fail_io;
226	}
227
228	ret = request_irq(irq, msm_iommu_fault_handler, 0,
229			"msm_iommu_secure_irpt_handler", drvdata);
230	if (ret) {
231		pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
232		goto fail_io;
233	}
234
235
236	drvdata->pclk = iommu_pclk;
237	drvdata->clk = iommu_clk;
238	drvdata->base = regs_base;
239	drvdata->irq = irq;
240	drvdata->ncb = iommu_dev->ncb;
241
242	pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
243		iommu_dev->name, regs_base, irq, iommu_dev->ncb);
244
245	platform_set_drvdata(pdev, drvdata);
246
247	if (iommu_clk)
248		clk_disable(iommu_clk);
249
250	clk_disable(iommu_pclk);
251
252	return 0;
253fail_io:
254	iounmap(regs_base);
255fail_mem:
256	release_mem_region(r->start, len);
257fail_clk:
258	if (iommu_clk) {
259		clk_disable(iommu_clk);
260		clk_put(iommu_clk);
261	}
262fail_pclk:
263	clk_disable_unprepare(iommu_pclk);
264fail_enable:
265	clk_put(iommu_pclk);
266fail:
267	kfree(drvdata);
268	return ret;
269}
270
271static int msm_iommu_remove(struct platform_device *pdev)
272{
273	struct msm_iommu_drvdata *drv = NULL;
274
275	drv = platform_get_drvdata(pdev);
276	if (drv) {
277		if (drv->clk) {
278			clk_unprepare(drv->clk);
279			clk_put(drv->clk);
280		}
281		clk_unprepare(drv->pclk);
282		clk_put(drv->pclk);
283		memset(drv, 0, sizeof(*drv));
284		kfree(drv);
285	}
286	return 0;
287}
288
289static int msm_iommu_ctx_probe(struct platform_device *pdev)
290{
291	struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
292	struct msm_iommu_drvdata *drvdata;
293	struct msm_iommu_ctx_drvdata *ctx_drvdata;
294	int i, ret;
295
296	if (!c || !pdev->dev.parent)
297		return -EINVAL;
298
299	drvdata = dev_get_drvdata(pdev->dev.parent);
300	if (!drvdata)
301		return -ENODEV;
302
303	ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
304	if (!ctx_drvdata)
305		return -ENOMEM;
306
307	ctx_drvdata->num = c->num;
308	ctx_drvdata->pdev = pdev;
309
310	INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
311	platform_set_drvdata(pdev, ctx_drvdata);
312
313	ret = clk_prepare_enable(drvdata->pclk);
314	if (ret)
315		goto fail;
316
317	if (drvdata->clk) {
318		ret = clk_prepare_enable(drvdata->clk);
319		if (ret) {
320			clk_disable_unprepare(drvdata->pclk);
321			goto fail;
322		}
323	}
324
325	/* Program the M2V tables for this context */
326	for (i = 0; i < MAX_NUM_MIDS; i++) {
327		int mid = c->mids[i];
328		if (mid == -1)
329			break;
330
331		SET_M2VCBR_N(drvdata->base, mid, 0);
332		SET_CBACR_N(drvdata->base, c->num, 0);
333
334		/* Set VMID = 0 */
335		SET_VMID(drvdata->base, mid, 0);
336
337		/* Set the context number for that MID to this context */
338		SET_CBNDX(drvdata->base, mid, c->num);
339
340		/* Set MID associated with this context bank to 0*/
341		SET_CBVMID(drvdata->base, c->num, 0);
342
343		/* Set the ASID for TLB tagging for this context */
344		SET_CONTEXTIDR_ASID(drvdata->base, c->num, c->num);
345
346		/* Set security bit override to be Non-secure */
347		SET_NSCFG(drvdata->base, mid, 3);
348	}
349
350	if (drvdata->clk)
351		clk_disable(drvdata->clk);
352	clk_disable(drvdata->pclk);
353
354	dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
355	return 0;
356fail:
357	kfree(ctx_drvdata);
358	return ret;
359}
360
361static int msm_iommu_ctx_remove(struct platform_device *pdev)
362{
363	struct msm_iommu_ctx_drvdata *drv = NULL;
364	drv = platform_get_drvdata(pdev);
365	if (drv) {
366		memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
367		kfree(drv);
368	}
369	return 0;
370}
371
372static struct platform_driver msm_iommu_driver = {
373	.driver = {
374		.name	= "msm_iommu",
375	},
376	.probe		= msm_iommu_probe,
377	.remove		= msm_iommu_remove,
378};
379
380static struct platform_driver msm_iommu_ctx_driver = {
381	.driver = {
382		.name	= "msm_iommu_ctx",
383	},
384	.probe		= msm_iommu_ctx_probe,
385	.remove		= msm_iommu_ctx_remove,
386};
387
 
 
 
 
 
388static int __init msm_iommu_driver_init(void)
389{
390	int ret;
391	ret = platform_driver_register(&msm_iommu_driver);
392	if (ret != 0) {
393		pr_err("Failed to register IOMMU driver\n");
394		goto error;
395	}
396
397	ret = platform_driver_register(&msm_iommu_ctx_driver);
398	if (ret != 0) {
399		platform_driver_unregister(&msm_iommu_driver);
400		pr_err("Failed to register IOMMU context driver\n");
401		goto error;
402	}
403
404error:
405	return ret;
406}
407
408static void __exit msm_iommu_driver_exit(void)
409{
410	platform_driver_unregister(&msm_iommu_ctx_driver);
411	platform_driver_unregister(&msm_iommu_driver);
412}
413
414subsys_initcall(msm_iommu_driver_init);
415module_exit(msm_iommu_driver_exit);
416
417MODULE_LICENSE("GPL v2");
418MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");