blob: a9d164e37e918a014345a1485f7500c0c8f574e7 [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
Olav Haugan19307692013-06-20 09:04:25 -070035#ifdef CONFIG_IOMMU_LPAE
36static const char *BFB_REG_NODE_NAME = "qcom,iommu-lpae-bfb-regs";
37static const char *BFB_DATA_NODE_NAME = "qcom,iommu-lpae-bfb-data";
38#else
39static const char *BFB_REG_NODE_NAME = "qcom,iommu-bfb-regs";
40static const char *BFB_DATA_NODE_NAME = "qcom,iommu-bfb-data";
41#endif
42
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070043static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
44 struct msm_iommu_drvdata *drvdata)
45{
46 struct msm_iommu_bfb_settings *bfb_settings;
47 u32 nreg, nval;
Mitchel Humpherysa1830b32013-02-25 18:29:54 -080048 int ret;
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070049
50 /*
Olav Haugan19307692013-06-20 09:04:25 -070051 * It is not valid for a device to have the BFB_REG_NODE_NAME
52 * property but not the BFB_DATA_NODE_NAME property, and vice versa.
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070053 */
Olav Haugan19307692013-06-20 09:04:25 -070054 if (!of_get_property(pdev->dev.of_node, BFB_REG_NODE_NAME, &nreg)) {
55 if (of_get_property(pdev->dev.of_node, BFB_DATA_NODE_NAME,
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070056 &nval))
57 return -EINVAL;
58 return 0;
59 }
60
Olav Haugan19307692013-06-20 09:04:25 -070061 if (!of_get_property(pdev->dev.of_node, BFB_DATA_NODE_NAME, &nval))
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070062 return -EINVAL;
63
64 if (nreg >= sizeof(bfb_settings->regs))
65 return -EINVAL;
66
67 if (nval >= sizeof(bfb_settings->data))
68 return -EINVAL;
69
70 if (nval != nreg)
71 return -EINVAL;
72
73 bfb_settings = devm_kzalloc(&pdev->dev, sizeof(*bfb_settings),
74 GFP_KERNEL);
75 if (!bfb_settings)
76 return -ENOMEM;
77
78 ret = of_property_read_u32_array(pdev->dev.of_node,
Olav Haugan19307692013-06-20 09:04:25 -070079 BFB_REG_NODE_NAME,
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070080 bfb_settings->regs,
81 nreg / sizeof(*bfb_settings->regs));
82 if (ret)
83 return ret;
84
85 ret = of_property_read_u32_array(pdev->dev.of_node,
Olav Haugan19307692013-06-20 09:04:25 -070086 BFB_DATA_NODE_NAME,
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070087 bfb_settings->data,
88 nval / sizeof(*bfb_settings->data));
89 if (ret)
90 return ret;
91
92 bfb_settings->length = nreg / sizeof(*bfb_settings->regs);
93
Stepan Moskovchenko880a3182012-10-01 12:35:24 -070094 drvdata->bfb_settings = bfb_settings;
95 return 0;
96}
97
Olav Haugan236970a2013-05-14 17:00:02 -070098static int __get_bus_vote_client(struct platform_device *pdev,
99 struct msm_iommu_drvdata *drvdata)
100{
101 int ret = 0;
102 struct msm_bus_scale_pdata *bs_table;
103 const char *dummy;
104
105 /* Check whether bus scaling has been specified for this node */
106 ret = of_property_read_string(pdev->dev.of_node, "qcom,msm-bus,name",
107 &dummy);
108 if (ret)
109 return 0;
110
111 bs_table = msm_bus_cl_get_pdata(pdev);
112
113 if (bs_table) {
114 drvdata->bus_client = msm_bus_scale_register_client(bs_table);
115 if (IS_ERR(&drvdata->bus_client)) {
116 pr_err("%s(): Bus client register failed.\n", __func__);
117 ret = -EINVAL;
118 }
119 }
120 return ret;
121}
122
123static void __put_bus_vote_client(struct msm_iommu_drvdata *drvdata)
124{
125 msm_bus_scale_unregister_client(drvdata->bus_client);
Mitchel Humpherys64d70872013-06-05 11:59:12 -0700126 drvdata->bus_client = 0;
Olav Haugan236970a2013-05-14 17:00:02 -0700127}
128
Olav Haugancaa12d32013-06-05 16:05:47 -0700129#ifdef CONFIG_IOMMU_NON_SECURE
130static inline void get_secure_id(struct device_node *node,
131 struct msm_iommu_drvdata *drvdata)
132{
133}
134
135static inline void get_secure_ctx(struct device_node *node,
136 struct msm_iommu_ctx_drvdata *ctx_drvdata)
137{
138 ctx_drvdata->secure_context = 0;
139}
140#else
141static void get_secure_id(struct device_node *node,
142 struct msm_iommu_drvdata *drvdata)
143{
144 of_property_read_u32(node, "qcom,iommu-secure-id", &drvdata->sec_id);
145}
146
147static void get_secure_ctx(struct device_node *node,
148 struct msm_iommu_ctx_drvdata *ctx_drvdata)
149{
150 ctx_drvdata->secure_context =
151 of_property_read_bool(node, "qcom,secure-context");
152}
153#endif
154
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800155static int msm_iommu_parse_dt(struct platform_device *pdev,
156 struct msm_iommu_drvdata *drvdata)
157{
158 struct device_node *child;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700159 int ret = 0;
Olav Haugan3c7fb382013-01-02 17:32:25 -0800160 struct resource *r;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800161
Stephen Boyd55742b72012-08-08 11:40:26 -0700162 drvdata->dev = &pdev->dev;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800163
Olav Haugan236970a2013-05-14 17:00:02 -0700164 ret = __get_bus_vote_client(pdev, drvdata);
165
166 if (ret)
167 goto fail;
168
Stepan Moskovchenko880a3182012-10-01 12:35:24 -0700169 ret = msm_iommu_parse_bfb_settings(pdev, drvdata);
170 if (ret)
171 goto fail;
172
Olav Haugan336bf412013-05-10 16:22:21 -0700173 for_each_child_of_node(pdev->dev.of_node, child)
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800174 drvdata->ncb++;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800175
Olav Haugan4e315c42013-03-06 10:14:28 -0800176 drvdata->asid = devm_kzalloc(&pdev->dev, drvdata->ncb * sizeof(int),
177 GFP_KERNEL);
178
179 if (!drvdata->asid) {
180 pr_err("Unable to get memory for asid array\n");
181 ret = -ENOMEM;
182 goto fail;
183 }
184
Olav Haugane6c00c32013-01-08 14:11:55 -0800185 ret = of_property_read_string(pdev->dev.of_node, "label",
186 &drvdata->name);
187 if (ret)
188 goto fail;
189
Laura Abbott0d135652012-10-04 12:59:03 -0700190 drvdata->sec_id = -1;
Olav Haugancaa12d32013-06-05 16:05:47 -0700191 get_secure_id(pdev->dev.of_node, drvdata);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800192
193 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clk_base");
194 if (r) {
195 drvdata->clk_reg_virt = devm_ioremap(&pdev->dev, r->start,
196 resource_size(r));
197 if (!drvdata->clk_reg_virt) {
Stepan Moskovchenko61fa3db2012-08-10 17:51:18 +0100198 pr_err("Failed to map resource for iommu clk: %pr\n",
199 r);
Olav Haugan3c7fb382013-01-02 17:32:25 -0800200 ret = -ENOMEM;
201 goto fail;
202 }
203 }
204
Olav Haugancd932192013-01-31 18:30:15 -0800205 drvdata->halt_enabled = of_property_read_bool(pdev->dev.of_node,
206 "qcom,iommu-enable-halt");
207
Olav Haugan336bf412013-05-10 16:22:21 -0700208 ret = of_platform_populate(pdev->dev.of_node,
209 msm_iommu_v1_ctx_match_table,
210 NULL, &pdev->dev);
Laura Abbott4a666eb2013-09-23 13:24:06 -0700211 if (ret) {
Olav Haugan336bf412013-05-10 16:22:21 -0700212 pr_err("Failed to create iommu context device\n");
Laura Abbott4a666eb2013-09-23 13:24:06 -0700213 goto fail;
214 }
Olav Haugan336bf412013-05-10 16:22:21 -0700215
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700216 msm_iommu_add_drv(drvdata);
Laura Abbott4a666eb2013-09-23 13:24:06 -0700217 return 0;
218
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700219fail:
Olav Haugan236970a2013-05-14 17:00:02 -0700220 __put_bus_vote_client(drvdata);
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700221 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800222}
223
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800224static int msm_iommu_pmon_parse_dt(struct platform_device *pdev,
Olav Haugan0c2d9322013-01-31 18:35:30 -0800225 struct iommu_pmon *pmon_info)
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800226{
227 int ret = 0;
228 int irq = platform_get_irq(pdev, 0);
Olav Haugan0c2d9322013-01-31 18:35:30 -0800229 unsigned int cls_prop_size;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800230
231 if (irq > 0) {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800232 pmon_info->iommu.evt_irq = platform_get_irq(pdev, 0);
233
234 ret = of_property_read_u32(pdev->dev.of_node,
235 "qcom,iommu-pmu-ngroups",
236 &pmon_info->num_groups);
237 if (ret) {
238 pr_err("Error reading qcom,iommu-pmu-ngroups\n");
239 goto fail;
240 }
241 ret = of_property_read_u32(pdev->dev.of_node,
242 "qcom,iommu-pmu-ncounters",
243 &pmon_info->num_counters);
244 if (ret) {
245 pr_err("Error reading qcom,iommu-pmu-ncounters\n");
246 goto fail;
247 }
248
249 if (!of_get_property(pdev->dev.of_node,
250 "qcom,iommu-pmu-event-classes",
251 &cls_prop_size)) {
252 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
253 return -EINVAL;
254 }
255
256 pmon_info->event_cls_supported =
257 devm_kzalloc(&pdev->dev, cls_prop_size, GFP_KERNEL);
258
259 if (!pmon_info->event_cls_supported) {
260 pr_err("Unable to get memory for event class array\n");
261 return -ENOMEM;
262 }
263
264 pmon_info->nevent_cls_supported = cls_prop_size / sizeof(u32);
265
266 ret = of_property_read_u32_array(pdev->dev.of_node,
267 "qcom,iommu-pmu-event-classes",
268 pmon_info->event_cls_supported,
269 pmon_info->nevent_cls_supported);
270 if (ret) {
271 pr_err("Error reading qcom,iommu-pmu-event-classes\n");
272 return ret;
273 }
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800274 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800275 pmon_info->iommu.evt_irq = -1;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800276 ret = irq;
277 }
Olav Haugan0c2d9322013-01-31 18:35:30 -0800278
279fail:
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800280 return ret;
281}
282
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800283static int __devinit msm_iommu_probe(struct platform_device *pdev)
284{
Olav Haugan0c2d9322013-01-31 18:35:30 -0800285 struct iommu_pmon *pmon_info;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800286 struct msm_iommu_drvdata *drvdata;
287 struct resource *r;
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700288 int ret, needs_alt_core_clk;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800289
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800290 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
291 if (!drvdata)
292 return -ENOMEM;
293
Olav Haugan3c7fb382013-01-02 17:32:25 -0800294 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iommu_base");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800295 if (!r)
296 return -EINVAL;
297
298 drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
299 if (!drvdata->base)
300 return -ENOMEM;
301
Olav Haugan95d24162012-12-05 14:47:47 -0800302 drvdata->glb_base = drvdata->base;
303
Olav Haugan00082d92013-05-21 09:21:10 -0700304 if (of_get_property(pdev->dev.of_node, "vdd-supply", NULL)) {
Stepan Moskovchenko6751acc2012-06-21 17:36:47 -0700305
Olav Haugan00082d92013-05-21 09:21:10 -0700306 drvdata->gdsc = devm_regulator_get(&pdev->dev, "vdd");
307 if (IS_ERR(drvdata->gdsc))
308 return PTR_ERR(drvdata->gdsc);
309
310 drvdata->alt_gdsc = devm_regulator_get(&pdev->dev,
311 "qcom,alt-vdd");
312 if (IS_ERR(drvdata->alt_gdsc))
313 drvdata->alt_gdsc = NULL;
314 } else {
315 pr_debug("Warning: No regulator specified for IOMMU\n");
316 }
Olav Haugan2648d972013-01-07 17:32:31 -0800317
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700318 drvdata->pclk = devm_clk_get(&pdev->dev, "iface_clk");
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800319 if (IS_ERR(drvdata->pclk))
320 return PTR_ERR(drvdata->pclk);
321
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700322 drvdata->clk = devm_clk_get(&pdev->dev, "core_clk");
323 if (IS_ERR(drvdata->clk))
324 return PTR_ERR(drvdata->clk);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800325
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700326 needs_alt_core_clk = of_property_read_bool(pdev->dev.of_node,
327 "qcom,needs-alt-core-clk");
328 if (needs_alt_core_clk) {
329 drvdata->aclk = devm_clk_get(&pdev->dev, "alt_core_clk");
330 if (IS_ERR(drvdata->aclk))
331 return PTR_ERR(drvdata->aclk);
332 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800333
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700334 if (clk_get_rate(drvdata->clk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800335 ret = clk_round_rate(drvdata->clk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700336 clk_set_rate(drvdata->clk, ret);
337 }
338
339 if (drvdata->aclk && clk_get_rate(drvdata->aclk) == 0) {
Olav Haugan8d9dfdd2013-02-12 15:00:13 -0800340 ret = clk_round_rate(drvdata->aclk, 1000);
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700341 clk_set_rate(drvdata->aclk, ret);
342 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800343
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800344 ret = msm_iommu_parse_dt(pdev, drvdata);
345 if (ret)
Stepan Moskovchenko17ae71e2012-07-24 19:24:14 -0700346 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800347
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800348 dev_info(&pdev->dev, "device %s mapped at %p, with %d ctx banks\n",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800349 drvdata->name, drvdata->base, drvdata->ncb);
350
351 platform_set_drvdata(pdev, drvdata);
352
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800353 pmon_info = msm_iommu_pm_alloc(&pdev->dev);
354 if (pmon_info != NULL) {
355 ret = msm_iommu_pmon_parse_dt(pdev, pmon_info);
356 if (ret) {
357 msm_iommu_pm_free(&pdev->dev);
358 pr_info("%s: pmon not available.\n", drvdata->name);
359 } else {
Olav Haugan0c2d9322013-01-31 18:35:30 -0800360 pmon_info->iommu.base = drvdata->base;
Olav Haugan0858ae02013-06-04 16:51:50 -0700361 pmon_info->iommu.ops = msm_get_iommu_access_ops();
Olav Hauganef69e892013-02-04 13:47:08 -0800362 pmon_info->iommu.hw_ops = iommu_pm_get_hw_ops_v1();
Olav Haugan0c2d9322013-01-31 18:35:30 -0800363 pmon_info->iommu.iommu_name = drvdata->name;
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800364 ret = msm_iommu_pm_iommu_register(pmon_info);
365 if (ret) {
366 pr_err("%s iommu register fail\n",
367 drvdata->name);
368 msm_iommu_pm_free(&pdev->dev);
369 } else {
370 pr_debug("%s iommu registered for pmon\n",
Olav Haugan0c2d9322013-01-31 18:35:30 -0800371 pmon_info->iommu.iommu_name);
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800372 }
373 }
374 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800375 return 0;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800376}
377
378static int __devexit msm_iommu_remove(struct platform_device *pdev)
379{
380 struct msm_iommu_drvdata *drv = NULL;
381
Olav Haugan5ebfbc62013-01-07 17:49:10 -0800382 msm_iommu_pm_iommu_unregister(&pdev->dev);
383 msm_iommu_pm_free(&pdev->dev);
384
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800385 drv = platform_get_drvdata(pdev);
386 if (drv) {
Olav Haugan236970a2013-05-14 17:00:02 -0700387 __put_bus_vote_client(drv);
Stephen Boyd55742b72012-08-08 11:40:26 -0700388 msm_iommu_remove_drv(drv);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800389 platform_set_drvdata(pdev, NULL);
390 }
391 return 0;
392}
393
394static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800395 struct msm_iommu_ctx_drvdata *ctx_drvdata)
396{
397 struct resource *r, rp;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700398 int irq = 0, ret = 0;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700399 u32 nsid;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800400
Olav Haugancaa12d32013-06-05 16:05:47 -0700401 get_secure_ctx(pdev->dev.of_node, ctx_drvdata);
Olav Hauganddd379d2013-01-28 09:07:51 -0800402
Mitchel Humpherysf3b50912013-05-21 17:46:04 -0700403 if (ctx_drvdata->secure_context) {
404 irq = platform_get_irq(pdev, 1);
405 if (irq > 0) {
406 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
407 msm_iommu_secure_fault_handler_v2,
408 IRQF_ONESHOT | IRQF_SHARED,
409 "msm_iommu_secure_irq", pdev);
410 if (ret) {
411 pr_err("Request IRQ %d failed with ret=%d\n",
412 irq, ret);
413 return ret;
414 }
415 }
416 } else {
Olav Hauganddd379d2013-01-28 09:07:51 -0800417 irq = platform_get_irq(pdev, 0);
418 if (irq > 0) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700419 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
Olav Hauganddd379d2013-01-28 09:07:51 -0800420 msm_iommu_fault_handler_v2,
421 IRQF_ONESHOT | IRQF_SHARED,
422 "msm_iommu_nonsecure_irq", pdev);
423 if (ret) {
424 pr_err("Request IRQ %d failed with ret=%d\n",
425 irq, ret);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700426 goto out;
Olav Hauganddd379d2013-01-28 09:07:51 -0800427 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800428 }
429 }
430
431 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700432 if (!r) {
433 ret = -EINVAL;
434 goto out;
435 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800436
437 ret = of_address_to_resource(pdev->dev.parent->of_node, 0, &rp);
438 if (ret)
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700439 goto out;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800440
441 /* Calculate the context bank number using the base addresses. The
442 * first 8 pages belong to the global address space which is followed
443 * by the context banks, hence subtract by 8 to get the context bank
444 * number.
445 */
446 ctx_drvdata->num = ((r->start - rp.start) >> CTX_SHIFT) - 8;
447
Stepan Moskovchenkoce78fc22012-07-11 17:20:27 -0700448 if (of_property_read_string(pdev->dev.of_node, "label",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800449 &ctx_drvdata->name))
450 ctx_drvdata->name = dev_name(&pdev->dev);
451
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700452 if (!of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &nsid)) {
453 ret = -EINVAL;
454 goto out;
455 }
456 if (nsid >= sizeof(ctx_drvdata->sids)) {
457 ret = -EINVAL;
458 goto out;
459 }
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700460
461 if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
462 ctx_drvdata->sids,
463 nsid / sizeof(*ctx_drvdata->sids))) {
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700464 ret = -EINVAL;
465 goto out;
Stepan Moskovchenko4575bdd2012-06-28 14:59:00 -0700466 }
467 ctx_drvdata->nsid = nsid;
468
Olav Haugan26ddd432012-12-07 11:39:21 -0800469 ctx_drvdata->asid = -1;
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700470out:
471 return ret;
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800472}
473
474static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
475{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800476 struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
477 int ret;
478
479 if (!pdev->dev.parent)
480 return -EINVAL;
481
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800482 ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
483 GFP_KERNEL);
484 if (!ctx_drvdata)
485 return -ENOMEM;
486
487 ctx_drvdata->pdev = pdev;
488 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800489
Sathish Ambleycf045e62012-06-07 12:56:50 -0700490 ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700491 if (!ret) {
492 platform_set_drvdata(pdev, ctx_drvdata);
493
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800494 dev_info(&pdev->dev, "context %s using bank %d\n",
Stepan Moskovchenkoe14ca5c2012-07-11 12:40:51 -0700495 ctx_drvdata->name, ctx_drvdata->num);
Olav Haugan08fb8ac2013-05-15 15:30:07 -0700496 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800497
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800498 return ret;
499}
500
501static int __devexit msm_iommu_ctx_remove(struct platform_device *pdev)
502{
503 platform_set_drvdata(pdev, NULL);
504 return 0;
505}
506
507static struct of_device_id msm_iommu_match_table[] = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800508 { .compatible = "qcom,msm-smmu-v1", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800509 {}
510};
511
512static struct platform_driver msm_iommu_driver = {
513 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800514 .name = "msm_iommu_v1",
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800515 .of_match_table = msm_iommu_match_table,
516 },
517 .probe = msm_iommu_probe,
518 .remove = __devexit_p(msm_iommu_remove),
519};
520
Olav Haugan336bf412013-05-10 16:22:21 -0700521static struct of_device_id msm_iommu_v1_ctx_match_table[] = {
522 { .compatible = "qcom,msm-smmu-v1-ctx", },
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800523 {}
524};
525
526static struct platform_driver msm_iommu_ctx_driver = {
527 .driver = {
Olav Haugan0e22c482013-01-28 17:39:36 -0800528 .name = "msm_iommu_ctx_v1",
Olav Haugan336bf412013-05-10 16:22:21 -0700529 .of_match_table = msm_iommu_v1_ctx_match_table,
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800530 },
531 .probe = msm_iommu_ctx_probe,
532 .remove = __devexit_p(msm_iommu_ctx_remove),
533};
534
535static int __init msm_iommu_driver_init(void)
536{
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800537 int ret;
538
Olav Haugan0858ae02013-06-04 16:51:50 -0700539 if (!msm_soc_version_supports_iommu_v0()) {
540 msm_set_iommu_access_ops(&iommu_access_ops_v1);
541 msm_iommu_sec_set_access_ops(&iommu_access_ops_v1);
542 }
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800543 ret = platform_driver_register(&msm_iommu_driver);
544 if (ret != 0) {
545 pr_err("Failed to register IOMMU driver\n");
546 goto error;
547 }
548
549 ret = platform_driver_register(&msm_iommu_ctx_driver);
550 if (ret != 0) {
551 pr_err("Failed to register IOMMU context driver\n");
552 goto error;
553 }
554
555error:
556 return ret;
557}
558
559static void __exit msm_iommu_driver_exit(void)
560{
561 platform_driver_unregister(&msm_iommu_ctx_driver);
562 platform_driver_unregister(&msm_iommu_driver);
Sathish Ambleyd1b89ed2012-02-07 21:47:47 -0800563}
564
565subsys_initcall(msm_iommu_driver_init);
566module_exit(msm_iommu_driver_exit);
567
568MODULE_LICENSE("GPL v2");