blob: 61e2c6b1305d96ede892cdd1d2dece57b06fa223 [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
Olav Haugancaa12d32013-06-05 16:05:47 -0700120#ifdef CONFIG_IOMMU_NON_SECURE
121static inline void get_secure_id(struct device_node *node,
122 struct msm_iommu_drvdata *drvdata)
123{
124}
125
126static inline void get_secure_ctx(struct device_node *node,
127 struct msm_iommu_ctx_drvdata *ctx_drvdata)
128{
129 ctx_drvdata->secure_context = 0;
130}
131#else
132static void get_secure_id(struct device_node *node,
133 struct msm_iommu_drvdata *drvdata)
134{
135 of_property_read_u32(node, "qcom,iommu-secure-id", &drvdata->sec_id);
136}
137
138static void get_secure_ctx(struct device_node *node,
139 struct msm_iommu_ctx_drvdata *ctx_drvdata)
140{
141 ctx_drvdata->secure_context =
142 of_property_read_bool(node, "qcom,secure-context");
143}
144#endif
145
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800146static int msm_iommu_parse_dt(struct platform_device *pdev,
147 struct msm_iommu_drvdata *drvdata)
148{
149 struct device_node *child;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700150 int ret = 0;
Olav Haugan3c7fb382013-01-02 17:32:25 -0800151 struct resource *r;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800152
Stephen Boyd55742b72012-08-08 11:40:26 -0700153 drvdata->dev = &pdev->dev;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800154
Olav Haugan236970a2013-05-14 17:00:02 -0700155 ret = __get_bus_vote_client(pdev, drvdata);
156
157 if (ret)
158 goto fail;
159
Stepan Moskovchenko880a3182012-10-01 12:35:24 -0700160 ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
161 if (ret)
162 goto fail;
163
Olav Haugan336bf412013-05-10 16:22:21 -0700164 for_each_child_of_node(pdev->dev.of_node, child)
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800165 drvdata->ncb++;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800166
Olav Haugan4e315c42013-03-06 10:14:28 -0800167 drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
168 GFP_KERNEL);
169
170 if (!drvdata->asid) {
171 pr_err("Unable to get memory for asid array\n");
172 ret = -ENOMEM;
173 goto fail;
174 }
175
Olav Haugane6c00c32013-01-08 14:11:55 -0800176 ret = of_property_read_string(pdev->dev.of_node, "label",
177 &drvdata->name);
178 if (ret)
179 goto fail;
180
Laura Abbott0d135652012-10-04 12:59:03 -0700181 drvdata->sec_id = -1;
Olav Haugancaa12d32013-06-05 16:05:47 -0700182 get_secure_id(pdev->dev.of_node, drvdata);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800183
184 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
185 if (r) {
186 drvdata->clk_reg_virt = devm_ioremap(&pdev->dev, r->start,
187 resource_size(r));
188 if (!drvdata->clk_reg_virt) {
Stepan Moskovchenko61fa3db2012-08-10 17:51:18 +0100189 pr_err("Failed to map resource for iommu clk: %pr\n",
190 r);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800191 ret = -ENOMEM;
192 goto fail;
193 }
194 }
195
Olav Haugancd932192013-01-31 18:30:15 -0800196 drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
197 "qcom,iommu-enable-halt");
198
Olav Haugan336bf412013-05-10 16:22:21 -0700199 ret = of_platform_populate(pdev->dev.of_node,
200 msm_iommu_v1_ctx_match_table,
201 NULL, &pdev->dev);
202 if (ret)
203 pr_err("Failed to create iommu context device\n");
204
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700205 msm_iommu_add_drv(drvdata);
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700206fail:
Olav Haugan236970a2013-05-14 17:00:02 -0700207 __put_bus_vote_client(drvdata);
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700208 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800209}
210
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800211static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
Olav Haugan0c2d9322013-01-31 18:35:30 -0800212 struct iommu_pmon *pmon_info)
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800213{
214 int ret = 0;
215 int irq = platform_get_irq(pdev, 0);
Olav Haugan0c2d9322013-01-31 18:35:30 -0800216 unsigned int cls_prop_size;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800217
218 if (irq > 0) {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800219 pmon_info->iommu.evt_irq = platform_get_irq(pdev, 0);
220
221 ret = of_property_read_u32(pdev->dev.of_node,
222 "qcom,iommu-pmu-ngroups",
223 &pmon_info->num_groups);
224 if (ret) {
225 pr_err("Error reading qcom,iommu-pmu-ngroups\n");
226 goto fail;
227 }
228 ret = of_property_read_u32(pdev->dev.of_node,
229 "qcom,iommu-pmu-ncounters",
230 &pmon_info->num_counters);
231 if (ret) {
232 pr_err("Error reading qcom,iommu-pmu-ncounters\n");
233 goto fail;
234 }
235
236 if (!of_get_property(pdev->dev.of_node,
237 "qcom,iommu-pmu-event-classes",
238 &cls_prop_size)) {
239 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
240 return -EINVAL;
241 }
242
243 pmon_info->event_cls_supported =
244 devm_kzalloc(&pdev->dev, cls_prop_size, GFP_KERNEL);
245
246 if (!pmon_info->event_cls_supported) {
247 pr_err("Unable to get memory for event class array\n");
248 return -ENOMEM;
249 }
250
251 pmon_info->nevent_cls_supported = cls_prop_size / sizeof(u32);
252
253 ret = of_property_read_u32_array(pdev->dev.of_node,
254 "qcom,iommu-pmu-event-classes",
255 pmon_info->event_cls_supported,
256 pmon_info->nevent_cls_supported);
257 if (ret) {
258 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
259 return ret;
260 }
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800261 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800262 pmon_info->iommu.evt_irq = -1;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800263 ret = irq;
264 }
Olav Haugan0c2d9322013-01-31 18:35:30 -0800265
266fail:
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800267 return ret;
268}
269
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800270static int __devinit msm_iommu_probe(struct platform_device *pdev)
271{
Olav Haugan0c2d9322013-01-31 18:35:30 -0800272 struct iommu_pmon *pmon_info;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800273 struct msm_iommu_drvdata *drvdata;
274 struct resource *r;
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700275 int ret, needs_alt_core_clk;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800276
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800277 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
278 if (!drvdata)
279 return -ENOMEM;
280
Olav Haugan3c7fb382013-01-02 17:32:25 -0800281 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iommu_base");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800282 if (!r)
283 return -EINVAL;
284
285 drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
286 if (!drvdata->base)
287 return -ENOMEM;
288
Olav Haugan95d24162012-12-05 14:47:47 -0800289 drvdata->glb_base = drvdata->base;
290
Olav Haugan00082d92013-05-21 09:21:10 -0700291 if (of_get_property(pdev->dev.of_node, "vdd-supply", NULL)) {
Stepan Moskovchenko6751acc2012-06-21 17:36:47 -0700292
Olav Haugan00082d92013-05-21 09:21:10 -0700293 drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
294 if (IS_ERR(drvdata->gdsc))
295 return PTR_ERR(drvdata->gdsc);
296
297 drvdata->alt_gdsc = devm_regulator_get(&pdev->dev,
298 "qcom,alt-vdd");
299 if (IS_ERR(drvdata->alt_gdsc))
300 drvdata->alt_gdsc = NULL;
301 } else {
302 pr_debug("Warning: No regulator specified for IOMMU\n");
303 }
Olav Haugan2648d972013-01-07 17:32:31 -0800304
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700305 drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800306 if (IS_ERR(drvdata->pclk))
307 return PTR_ERR(drvdata->pclk);
308
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700309 drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
310 if (IS_ERR(drvdata->clk))
311 return PTR_ERR(drvdata->clk);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800312
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700313 needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
314 "qcom,needs-alt-core-clk");
315 if (needs_alt_core_clk) {
316 drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
317 if (IS_ERR(drvdata->aclk))
318 return PTR_ERR(drvdata->aclk);
319 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800320
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700321 if (clk_get_rate(drvdata->clk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800322 ret = clk_round_rate(drvdata->clk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700323 clk_set_rate(drvdata->clk, ret);
324 }
325
326 if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800327 ret = clk_round_rate(drvdata->aclk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700328 clk_set_rate(drvdata->aclk, ret);
329 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800330
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800331 ret = msm_iommu_parse_dt(pdev, drvdata);
332 if (ret)
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700333 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800334
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800335 dev_info(&pdev->dev, "device %s mapped at %p, with %d ctx banks\n",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800336 drvdata->name, drvdata->base, drvdata->ncb);
337
338 platform_set_drvdata(pdev, drvdata);
339
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800340 pmon_info = msm_iommu_pm_alloc(&pdev->dev);
341 if (pmon_info != NULL) {
342 ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
343 if (ret) {
344 msm_iommu_pm_free(&pdev->dev);
345 pr_info("%s: pmon not available.\n", drvdata->name);
346 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800347 pmon_info->iommu.base = drvdata->base;
Olav Haugan0858ae02013-06-04 16:51:50 -0700348 pmon_info->iommu.ops = msm_get_iommu_access_ops();
Olav Hauganef69e892013-02-04 13:47:08 -0800349 pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
Olav Haugan0c2d9322013-01-31 18:35:30 -0800350 pmon_info->iommu.iommu_name = drvdata->name;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800351 ret = msm_iommu_pm_iommu_register(pmon_info);
352 if (ret) {
353 pr_err("%s iommu register fail\n",
354 drvdata->name);
355 msm_iommu_pm_free(&pdev->dev);
356 } else {
357 pr_debug("%s iommu registered for pmon\n",
Olav Haugan0c2d9322013-01-31 18:35:30 -0800358 pmon_info->iommu.iommu_name);
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800359 }
360 }
361 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800362 return 0;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800363}
364
365static int __devexit msm_iommu_remove(struct platform_device *pdev)
366{
367 struct msm_iommu_drvdata *drv = NULL;
368
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800369 msm_iommu_pm_iommu_unregister(&pdev->dev);
370 msm_iommu_pm_free(&pdev->dev);
371
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800372 drv = platform_get_drvdata(pdev);
373 if (drv) {
Olav Haugan236970a2013-05-14 17:00:02 -0700374 __put_bus_vote_client(drv);
Stephen Boyd55742b72012-08-08 11:40:26 -0700375 msm_iommu_remove_drv(drv);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800376 platform_set_drvdata(pdev, NULL);
377 }
378 return 0;
379}
380
381static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800382 struct msm_iommu_ctx_drvdata *ctx_drvdata)
383{
384 struct resource *r, rp;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700385 int irq = 0, ret = 0;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700386 u32 nsid;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800387
Olav Haugancaa12d32013-06-05 16:05:47 -0700388 get_secure_ctx(pdev->dev.of_node, ctx_drvdata);
Olav Hauganddd379d2013-01-28 09:07:51 -0800389
Mitchel Humpherysf3b50912013-05-21 17:46:04 -0700390 if (ctx_drvdata->secure_context) {
391 irq = platform_get_irq(pdev, 1);
392 if (irq > 0) {
393 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
394 msm_iommu_secure_fault_handler_v2,
395 IRQF_ONESHOT | IRQF_SHARED,
396 "msm_iommu_secure_irq", pdev);
397 if (ret) {
398 pr_err("Request IRQ %d failed with ret=%d\n",
399 irq, ret);
400 return ret;
401 }
402 }
403 } else {
Olav Hauganddd379d2013-01-28 09:07:51 -0800404 irq = platform_get_irq(pdev, 0);
405 if (irq > 0) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700406 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
Olav Hauganddd379d2013-01-28 09:07:51 -0800407 msm_iommu_fault_handler_v2,
408 IRQF_ONESHOT | IRQF_SHARED,
409 "msm_iommu_nonsecure_irq", pdev);
410 if (ret) {
411 pr_err("Request IRQ %d failed with ret=%d\n",
412 irq, ret);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700413 goto out;
Olav Hauganddd379d2013-01-28 09:07:51 -0800414 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800415 }
416 }
417
418 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700419 if (!r) {
420 ret = -EINVAL;
421 goto out;
422 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800423
424 ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
425 if (ret)
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700426 goto out;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800427
428 /* Calculate the context bank number using the base addresses. The
429 * first 8 pages belong to the global address space which is followed
430 * by the context banks, hence subtract by 8 to get the context bank
431 * number.
432 */
433 ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
434
Stepan Moskovchenkoce78fc22012-07-11 17:20:27 -0700435 if (of_property_read_string(pdev->dev.of_node, "label",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800436 &ctx_drvdata->name))
437 ctx_drvdata->name = dev_name(&pdev->dev);
438
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700439 if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
440 ret = -EINVAL;
441 goto out;
442 }
443 if (nsid >= sizeof(ctx_drvdata->sids)) {
444 ret = -EINVAL;
445 goto out;
446 }
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700447
448 if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
449 ctx_drvdata->sids,
450 nsid / sizeof(*ctx_drvdata->sids))) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700451 ret = -EINVAL;
452 goto out;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700453 }
454 ctx_drvdata->nsid = nsid;
455
Olav Haugan26ddd432012-12-07 11:39:21 -0800456 ctx_drvdata->asid = -1;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700457out:
458 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800459}
460
461static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
462{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800463 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
464 int ret;
465
466 if (!pdev->dev.parent)
467 return -EINVAL;
468
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800469 ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
470 GFP_KERNEL);
471 if (!ctx_drvdata)
472 return -ENOMEM;
473
474 ctx_drvdata->pdev = pdev;
475 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800476
Sathish Ambleycf045e62012-06-07 12:56:50 -0700477 ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700478 if (!ret) {
479 platform_set_drvdata(pdev, ctx_drvdata);
480
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800481 dev_info(&pdev->dev, "context %s using bank %d\n",
Stepan Moskovchenkoe14ca5c2012-07-11 12:40:51 -0700482 ctx_drvdata->name, ctx_drvdata->num);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700483 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800484
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800485 return ret;
486}
487
488static int __devexit msm_iommu_ctx_remove(struct platform_device *pdev)
489{
490 platform_set_drvdata(pdev, NULL);
491 return 0;
492}
493
494static struct of_device_id msm_iommu_match_table[] = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800495 { .compatible = "qcom,msm-smmu-v1", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800496 {}
497};
498
499static struct platform_driver msm_iommu_driver = {
500 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800501 .name = "msm_iommu_v1",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800502 .of_match_table = msm_iommu_match_table,
503 },
504 .probe = msm_iommu_probe,
505 .remove = __devexit_p(msm_iommu_remove),
506};
507
Olav Haugan336bf412013-05-10 16:22:21 -0700508static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
509 { .compatible = "qcom,msm-smmu-v1-ctx", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800510 {}
511};
512
513static struct platform_driver msm_iommu_ctx_driver = {
514 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800515 .name = "msm_iommu_ctx_v1",
Olav Haugan336bf412013-05-10 16:22:21 -0700516 .of_match_table = msm_iommu_v1_ctx_match_table,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800517 },
518 .probe = msm_iommu_ctx_probe,
519 .remove = __devexit_p(msm_iommu_ctx_remove),
520};
521
522static int __init msm_iommu_driver_init(void)
523{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800524 int ret;
525
Olav Haugan0858ae02013-06-04 16:51:50 -0700526 if (!msm_soc_version_supports_iommu_v0()) {
527 msm_set_iommu_access_ops(&iommu_access_ops_v1);
528 msm_iommu_sec_set_access_ops(&iommu_access_ops_v1);
529 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800530 ret = platform_driver_register(&msm_iommu_driver);
531 if (ret != 0) {
532 pr_err("Failed to register IOMMU driver\n");
533 goto error;
534 }
535
536 ret = platform_driver_register(&msm_iommu_ctx_driver);
537 if (ret != 0) {
538 pr_err("Failed to register IOMMU context driver\n");
539 goto error;
540 }
541
542error:
543 return ret;
544}
545
546static void __exit msm_iommu_driver_exit(void)
547{
548 platform_driver_unregister(&msm_iommu_ctx_driver);
549 platform_driver_unregister(&msm_iommu_driver);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800550}
551
552subsys_initcall(msm_iommu_driver_init);
553module_exit(msm_iommu_driver_exit);
554
555MODULE_LICENSE("GPL v2");