blob: 958b7b11eb88cf6565c9a261979281dd2001cd83 [file] [log] [blame]
Olav Haugan3c7fb382013-01-02 17:32:25 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -08002 *
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/io.h>
19#include <linux/clk.h>
20#include <linux/iommu.h>
21#include <linux/interrupt.h>
22#include <linux/err.h>
23#include <linux/slab.h>
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -080024#include <linux/of.h>
25#include <linux/of_address.h>
26#include <linux/of_device.h>
27
Olav Haugane6d01ef2013-01-25 16:55:44 -080028#include <mach/iommu_hw-v1.h>
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -080029#include <mach/iommu.h>
Olav Haugan5ebfbc62013-01-07 17:49:10 -080030#include <mach/iommu_perfmon.h>
Olav Haugan236970a2013-05-14 17:00:02 -070031#include <mach/msm_bus.h>
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -080032
Olav Haugan336bf412013-05-10 16:22:21 -070033static struct of_device_id msm_iommu_v1_ctx_match_table[];
34
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070035static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
36 struct msm_iommu_drvdata *drvdata)
37{
38 struct msm_iommu_bfb_settings *bfb_settings;
39 u32 nreg, nval;
Mitchel Humpherysa1830b32013-02-25 18:29:54 -080040 int ret;
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070041
42 /*
43 * It is not valid for a device to have the qcom,iommu-bfb-regs
44 * property but not the qcom,iommu-bfb-data property, and vice versa.
45 */
46 if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-regs", &nreg)) {
47 if (of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data",
48 &nval))
49 return -EINVAL;
50 return 0;
51 }
52
53 if (!of_get_property(pdev->dev.of_node, "qcom,iommu-bfb-data", &nval))
54 return -EINVAL;
55
56 if (nreg >= sizeof(bfb_settings->regs))
57 return -EINVAL;
58
59 if (nval >= sizeof(bfb_settings->data))
60 return -EINVAL;
61
62 if (nval != nreg)
63 return -EINVAL;
64
65 bfb_settings = devm_kzalloc(&pdev->dev, sizeof(*bfb_settings),
66 GFP_KERNEL);
67 if (!bfb_settings)
68 return -ENOMEM;
69
70 ret = of_property_read_u32_array(pdev->dev.of_node,
71 "qcom,iommu-bfb-regs",
72 bfb_settings->regs,
73 nreg / sizeof(*bfb_settings->regs));
74 if (ret)
75 return ret;
76
77 ret = of_property_read_u32_array(pdev->dev.of_node,
78 "qcom,iommu-bfb-data",
79 bfb_settings->data,
80 nval / sizeof(*bfb_settings->data));
81 if (ret)
82 return ret;
83
84 bfb_settings->length = nreg / sizeof(*bfb_settings->regs);
85
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070086 drvdata->bfb_settings = bfb_settings;
87 return 0;
88}
89
Olav Haugan236970a2013-05-14 17:00:02 -070090static int __get_bus_vote_client(struct platform_device *pdev,
91 struct msm_iommu_drvdata *drvdata)
92{
93 int ret = 0;
94 struct msm_bus_scale_pdata *bs_table;
95 const char *dummy;
96
97 /* Check whether bus scaling has been specified for this node */
98 ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
99 &dummy);
100 if (ret)
101 return 0;
102
103 bs_table = msm_bus_cl_get_pdata(pdev);
104
105 if (bs_table) {
106 drvdata->bus_client = msm_bus_scale_register_client(bs_table);
107 if (IS_ERR(&drvdata->bus_client)) {
108 pr_err("%s(): Bus client register failed.\n", __func__);
109 ret = -EINVAL;
110 }
111 }
112 return ret;
113}
114
115static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
116{
117 msm_bus_scale_unregister_client(drvdata->bus_client);
118}
119
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800120static int msm_iommu_parse_dt(struct platform_device *pdev,
121 struct msm_iommu_drvdata *drvdata)
122{
123 struct device_node *child;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700124 int ret = 0;
Olav Haugan3c7fb382013-01-02 17:32:25 -0800125 struct resource *r;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800126
Stephen Boyd55742b72012-08-08 11:40:26 -0700127 drvdata->dev = &pdev->dev;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800128
Olav Haugan236970a2013-05-14 17:00:02 -0700129 ret = __get_bus_vote_client(pdev, drvdata);
130
131 if (ret)
132 goto fail;
133
Stepan Moskovchenko880a3182012-10-01 12:35:24 -0700134 ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
135 if (ret)
136 goto fail;
137
Olav Haugan336bf412013-05-10 16:22:21 -0700138 for_each_child_of_node(pdev->dev.of_node, child)
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800139 drvdata->ncb++;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800140
Olav Haugan4e315c42013-03-06 10:14:28 -0800141 drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
142 GFP_KERNEL);
143
144 if (!drvdata->asid) {
145 pr_err("Unable to get memory for asid array\n");
146 ret = -ENOMEM;
147 goto fail;
148 }
149
Olav Haugane6c00c32013-01-08 14:11:55 -0800150 ret = of_property_read_string(pdev->dev.of_node, "label",
151 &drvdata->name);
152 if (ret)
153 goto fail;
154
Laura Abbott0d135652012-10-04 12:59:03 -0700155 drvdata->sec_id = -1;
156 of_property_read_u32(pdev->dev.of_node, "qcom,iommu-secure-id",
157 &drvdata->sec_id);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800158
159 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
160 if (r) {
161 drvdata->clk_reg_virt = devm_ioremap(&pdev->dev, r->start,
162 resource_size(r));
163 if (!drvdata->clk_reg_virt) {
Stepan Moskovchenko61fa3db2012-08-10 17:51:18 +0100164 pr_err("Failed to map resource for iommu clk: %pr\n",
165 r);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800166 ret = -ENOMEM;
167 goto fail;
168 }
169 }
170
Olav Haugancd932192013-01-31 18:30:15 -0800171 drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
172 "qcom,iommu-enable-halt");
173
Olav Haugan336bf412013-05-10 16:22:21 -0700174 ret = of_platform_populate(pdev->dev.of_node,
175 msm_iommu_v1_ctx_match_table,
176 NULL, &pdev->dev);
177 if (ret)
178 pr_err("Failed to create iommu context device\n");
179
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700180 msm_iommu_add_drv(drvdata);
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700181fail:
Olav Haugan236970a2013-05-14 17:00:02 -0700182 __put_bus_vote_client(drvdata);
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700183 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800184}
185
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800186static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
Olav Haugan0c2d9322013-01-31 18:35:30 -0800187 struct iommu_pmon *pmon_info)
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800188{
189 int ret = 0;
190 int irq = platform_get_irq(pdev, 0);
Olav Haugan0c2d9322013-01-31 18:35:30 -0800191 unsigned int cls_prop_size;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800192
193 if (irq > 0) {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800194 pmon_info->iommu.evt_irq = platform_get_irq(pdev, 0);
195
196 ret = of_property_read_u32(pdev->dev.of_node,
197 "qcom,iommu-pmu-ngroups",
198 &pmon_info->num_groups);
199 if (ret) {
200 pr_err("Error reading qcom,iommu-pmu-ngroups\n");
201 goto fail;
202 }
203 ret = of_property_read_u32(pdev->dev.of_node,
204 "qcom,iommu-pmu-ncounters",
205 &pmon_info->num_counters);
206 if (ret) {
207 pr_err("Error reading qcom,iommu-pmu-ncounters\n");
208 goto fail;
209 }
210
211 if (!of_get_property(pdev->dev.of_node,
212 "qcom,iommu-pmu-event-classes",
213 &cls_prop_size)) {
214 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
215 return -EINVAL;
216 }
217
218 pmon_info->event_cls_supported =
219 devm_kzalloc(&pdev->dev, cls_prop_size, GFP_KERNEL);
220
221 if (!pmon_info->event_cls_supported) {
222 pr_err("Unable to get memory for event class array\n");
223 return -ENOMEM;
224 }
225
226 pmon_info->nevent_cls_supported = cls_prop_size / sizeof(u32);
227
228 ret = of_property_read_u32_array(pdev->dev.of_node,
229 "qcom,iommu-pmu-event-classes",
230 pmon_info->event_cls_supported,
231 pmon_info->nevent_cls_supported);
232 if (ret) {
233 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
234 return ret;
235 }
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800236 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800237 pmon_info->iommu.evt_irq = -1;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800238 ret = irq;
239 }
Olav Haugan0c2d9322013-01-31 18:35:30 -0800240
241fail:
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800242 return ret;
243}
244
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800245static int __devinit msm_iommu_probe(struct platform_device *pdev)
246{
Olav Haugan0c2d9322013-01-31 18:35:30 -0800247 struct iommu_pmon *pmon_info;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800248 struct msm_iommu_drvdata *drvdata;
249 struct resource *r;
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700250 int ret, needs_alt_core_clk;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800251
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800252 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
253 if (!drvdata)
254 return -ENOMEM;
255
Olav Haugan3c7fb382013-01-02 17:32:25 -0800256 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iommu_base");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800257 if (!r)
258 return -EINVAL;
259
260 drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
261 if (!drvdata->base)
262 return -ENOMEM;
263
Olav Haugan95d24162012-12-05 14:47:47 -0800264 drvdata->glb_base = drvdata->base;
265
Stepan Moskovchenko6751acc2012-06-21 17:36:47 -0700266 drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
267 if (IS_ERR(drvdata->gdsc))
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700268 return PTR_ERR(drvdata->gdsc);
Stepan Moskovchenko6751acc2012-06-21 17:36:47 -0700269
Olav Haugan2648d972013-01-07 17:32:31 -0800270 drvdata->alt_gdsc = devm_regulator_get(&pdev->dev, "qcom,alt-vdd");
271 if (IS_ERR(drvdata->alt_gdsc))
272 drvdata->alt_gdsc = NULL;
273
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700274 drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800275 if (IS_ERR(drvdata->pclk))
276 return PTR_ERR(drvdata->pclk);
277
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700278 drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
279 if (IS_ERR(drvdata->clk))
280 return PTR_ERR(drvdata->clk);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800281
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700282 needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
283 "qcom,needs-alt-core-clk");
284 if (needs_alt_core_clk) {
285 drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
286 if (IS_ERR(drvdata->aclk))
287 return PTR_ERR(drvdata->aclk);
288 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800289
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700290 if (clk_get_rate(drvdata->clk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800291 ret = clk_round_rate(drvdata->clk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700292 clk_set_rate(drvdata->clk, ret);
293 }
294
295 if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800296 ret = clk_round_rate(drvdata->aclk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700297 clk_set_rate(drvdata->aclk, ret);
298 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800299
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800300 ret = msm_iommu_parse_dt(pdev, drvdata);
301 if (ret)
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700302 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800303
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800304 dev_info(&pdev->dev, "device %s mapped at %p, with %d ctx banks\n",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800305 drvdata->name, drvdata->base, drvdata->ncb);
306
307 platform_set_drvdata(pdev, drvdata);
308
Olav Hauganeece7e52013-04-02 10:22:21 -0700309 msm_iommu_sec_set_access_ops(&iommu_access_ops_v1);
310
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800311 pmon_info = msm_iommu_pm_alloc(&pdev->dev);
312 if (pmon_info != NULL) {
313 ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
314 if (ret) {
315 msm_iommu_pm_free(&pdev->dev);
316 pr_info("%s: pmon not available.\n", drvdata->name);
317 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800318 pmon_info->iommu.base = drvdata->base;
Olav Hauganef69e892013-02-04 13:47:08 -0800319 pmon_info->iommu.ops = &iommu_access_ops_v1;
320 pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
Olav Haugan0c2d9322013-01-31 18:35:30 -0800321 pmon_info->iommu.iommu_name = drvdata->name;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800322 ret = msm_iommu_pm_iommu_register(pmon_info);
323 if (ret) {
324 pr_err("%s iommu register fail\n",
325 drvdata->name);
326 msm_iommu_pm_free(&pdev->dev);
327 } else {
328 pr_debug("%s iommu registered for pmon\n",
Olav Haugan0c2d9322013-01-31 18:35:30 -0800329 pmon_info->iommu.iommu_name);
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800330 }
331 }
332 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800333 return 0;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800334}
335
336static int __devexit msm_iommu_remove(struct platform_device *pdev)
337{
338 struct msm_iommu_drvdata *drv = NULL;
339
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800340 msm_iommu_pm_iommu_unregister(&pdev->dev);
341 msm_iommu_pm_free(&pdev->dev);
342
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800343 drv = platform_get_drvdata(pdev);
344 if (drv) {
Olav Haugan236970a2013-05-14 17:00:02 -0700345 __put_bus_vote_client(drv);
Stephen Boyd55742b72012-08-08 11:40:26 -0700346 msm_iommu_remove_drv(drv);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800347 platform_set_drvdata(pdev, NULL);
348 }
349 return 0;
350}
351
352static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800353 struct msm_iommu_ctx_drvdata *ctx_drvdata)
354{
355 struct resource *r, rp;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700356 int irq = 0, ret = 0;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700357 u32 nsid;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800358
Olav Hauganddd379d2013-01-28 09:07:51 -0800359 ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
360 "qcom,secure-context");
361
Mitchel Humpherysf3b50912013-05-21 17:46:04 -0700362 if (ctx_drvdata->secure_context) {
363 irq = platform_get_irq(pdev, 1);
364 if (irq > 0) {
365 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
366 msm_iommu_secure_fault_handler_v2,
367 IRQF_ONESHOT | IRQF_SHARED,
368 "msm_iommu_secure_irq", pdev);
369 if (ret) {
370 pr_err("Request IRQ %d failed with ret=%d\n",
371 irq, ret);
372 return ret;
373 }
374 }
375 } else {
Olav Hauganddd379d2013-01-28 09:07:51 -0800376 irq = platform_get_irq(pdev, 0);
377 if (irq > 0) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700378 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
Olav Hauganddd379d2013-01-28 09:07:51 -0800379 msm_iommu_fault_handler_v2,
380 IRQF_ONESHOT | IRQF_SHARED,
381 "msm_iommu_nonsecure_irq", pdev);
382 if (ret) {
383 pr_err("Request IRQ %d failed with ret=%d\n",
384 irq, ret);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700385 goto out;
Olav Hauganddd379d2013-01-28 09:07:51 -0800386 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800387 }
388 }
389
390 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700391 if (!r) {
392 ret = -EINVAL;
393 goto out;
394 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800395
396 ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
397 if (ret)
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700398 goto out;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800399
400 /* Calculate the context bank number using the base addresses. The
401 * first 8 pages belong to the global address space which is followed
402 * by the context banks, hence subtract by 8 to get the context bank
403 * number.
404 */
405 ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
406
Stepan Moskovchenkoce78fc22012-07-11 17:20:27 -0700407 if (of_property_read_string(pdev->dev.of_node, "label",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800408 &ctx_drvdata->name))
409 ctx_drvdata->name = dev_name(&pdev->dev);
410
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700411 if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
412 ret = -EINVAL;
413 goto out;
414 }
415 if (nsid >= sizeof(ctx_drvdata->sids)) {
416 ret = -EINVAL;
417 goto out;
418 }
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700419
420 if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
421 ctx_drvdata->sids,
422 nsid / sizeof(*ctx_drvdata->sids))) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700423 ret = -EINVAL;
424 goto out;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700425 }
426 ctx_drvdata->nsid = nsid;
427
Olav Haugan26ddd432012-12-07 11:39:21 -0800428 ctx_drvdata->asid = -1;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700429out:
430 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800431}
432
433static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
434{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800435 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
436 int ret;
437
438 if (!pdev->dev.parent)
439 return -EINVAL;
440
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800441 ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
442 GFP_KERNEL);
443 if (!ctx_drvdata)
444 return -ENOMEM;
445
446 ctx_drvdata->pdev = pdev;
447 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800448
Sathish Ambleycf045e62012-06-07 12:56:50 -0700449 ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700450 if (!ret) {
451 platform_set_drvdata(pdev, ctx_drvdata);
452
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800453 dev_info(&pdev->dev, "context %s using bank %d\n",
Stepan Moskovchenkoe14ca5c2012-07-11 12:40:51 -0700454 ctx_drvdata->name, ctx_drvdata->num);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700455 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800456
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800457 return ret;
458}
459
460static int __devexit msm_iommu_ctx_remove(struct platform_device *pdev)
461{
462 platform_set_drvdata(pdev, NULL);
463 return 0;
464}
465
466static struct of_device_id msm_iommu_match_table[] = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800467 { .compatible = "qcom,msm-smmu-v1", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800468 {}
469};
470
471static struct platform_driver msm_iommu_driver = {
472 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800473 .name = "msm_iommu_v1",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800474 .of_match_table = msm_iommu_match_table,
475 },
476 .probe = msm_iommu_probe,
477 .remove = __devexit_p(msm_iommu_remove),
478};
479
Olav Haugan336bf412013-05-10 16:22:21 -0700480static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
481 { .compatible = "qcom,msm-smmu-v1-ctx", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800482 {}
483};
484
485static struct platform_driver msm_iommu_ctx_driver = {
486 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800487 .name = "msm_iommu_ctx_v1",
Olav Haugan336bf412013-05-10 16:22:21 -0700488 .of_match_table = msm_iommu_v1_ctx_match_table,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800489 },
490 .probe = msm_iommu_ctx_probe,
491 .remove = __devexit_p(msm_iommu_ctx_remove),
492};
493
494static int __init msm_iommu_driver_init(void)
495{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800496 int ret;
497
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800498 ret = platform_driver_register(&msm_iommu_driver);
499 if (ret != 0) {
500 pr_err("Failed to register IOMMU driver\n");
501 goto error;
502 }
503
504 ret = platform_driver_register(&msm_iommu_ctx_driver);
505 if (ret != 0) {
506 pr_err("Failed to register IOMMU context driver\n");
507 goto error;
508 }
509
510error:
511 return ret;
512}
513
514static void __exit msm_iommu_driver_exit(void)
515{
516 platform_driver_unregister(&msm_iommu_ctx_driver);
517 platform_driver_unregister(&msm_iommu_driver);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800518}
519
520subsys_initcall(msm_iommu_driver_init);
521module_exit(msm_iommu_driver_exit);
522
523MODULE_LICENSE("GPL v2");