blob: 7fbcff435d56299f388c92fdd5258b9303311b93 [file] [log] [blame]
Dhaval Patel14d46ce2017-01-17 16:28:12 -08001/*
2 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -07005 *
Dhaval Patel14d46ce2017-01-17 16:28:12 -08006 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -07009 *
Dhaval Patel14d46ce2017-01-17 16:28:12 -080010 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program. If not, see <http://www.gnu.org/licenses/>.
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070017 */
18
19#include <linux/module.h>
20#include <linux/of_platform.h>
21#include <linux/pm_runtime.h>
22#include <linux/msm_dma_iommu_mapping.h>
23
24#include <asm/dma-iommu.h>
25#include <soc/qcom/secure_buffer.h>
26
27#include "msm_drv.h"
Clarence Ip24b7c362017-05-14 17:03:50 -040028#include "msm_gem.h"
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070029#include "msm_mmu.h"
Alan Kwongc16e0922017-05-11 14:50:46 -070030#include "sde_dbg.h"
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070031
Alan Kwong112a84f2016-05-24 20:49:21 -040032#ifndef SZ_4G
33#define SZ_4G (((size_t) SZ_1G) * 4)
34#endif
35
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070036struct msm_smmu_client {
37 struct device *dev;
38 struct dma_iommu_mapping *mmu_mapping;
39 bool domain_attached;
40};
41
42struct msm_smmu {
43 struct msm_mmu base;
44 struct device *client_dev;
Alan Kwong112a84f2016-05-24 20:49:21 -040045 struct msm_smmu_client *client;
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070046};
47
48struct msm_smmu_domain {
49 const char *label;
50 size_t va_start;
51 size_t va_size;
52 bool secure;
53};
54
55#define to_msm_smmu(x) container_of(x, struct msm_smmu, base)
Alan Kwong112a84f2016-05-24 20:49:21 -040056#define msm_smmu_to_client(smmu) (smmu->client)
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070057
58static int _msm_smmu_create_mapping(struct msm_smmu_client *client,
59 const struct msm_smmu_domain *domain);
60
Dhaval Patel04c7e8e2016-09-26 20:14:31 -070061static int msm_smmu_attach(struct msm_mmu *mmu, const char * const *names,
62 int cnt)
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070063{
64 struct msm_smmu *smmu = to_msm_smmu(mmu);
65 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
66 int rc = 0;
67
Alan Kwong112a84f2016-05-24 20:49:21 -040068 if (!client) {
69 pr_err("undefined smmu client\n");
70 return -EINVAL;
71 }
72
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070073 /* domain attach only once */
74 if (client->domain_attached)
75 return 0;
76
77 rc = arm_iommu_attach_device(client->dev,
78 client->mmu_mapping);
79 if (rc) {
80 dev_err(client->dev, "iommu attach dev failed (%d)\n",
81 rc);
82 return rc;
83 }
84
85 client->domain_attached = true;
86
87 dev_dbg(client->dev, "iommu domain attached\n");
88
89 return 0;
90}
91
Dhaval Patel04c7e8e2016-09-26 20:14:31 -070092static void msm_smmu_detach(struct msm_mmu *mmu, const char * const *names,
93 int cnt)
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -070094{
Lloyd Atkinson479690d2016-10-04 09:51:22 -040095 struct msm_smmu *smmu = to_msm_smmu(mmu);
96 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
97
98 if (!client) {
99 pr_err("undefined smmu client\n");
100 return;
101 }
102
103 if (!client->domain_attached)
104 return;
105
106 arm_iommu_detach_device(client->dev);
107 client->domain_attached = false;
108 dev_dbg(client->dev, "iommu domain detached\n");
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700109}
110
111static int msm_smmu_map(struct msm_mmu *mmu, uint32_t iova,
112 struct sg_table *sgt, unsigned int len, int prot)
113{
114 struct msm_smmu *smmu = to_msm_smmu(mmu);
115 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
116 struct iommu_domain *domain;
117 struct scatterlist *sg;
118 unsigned int da = iova;
119 unsigned int i, j;
120 int ret;
121
122 if (!client)
123 return -ENODEV;
124
125 domain = client->mmu_mapping->domain;
126 if (!domain || !sgt)
127 return -EINVAL;
128
129 for_each_sg(sgt->sgl, sg, sgt->nents, i) {
130 u32 pa = sg_phys(sg) - sg->offset;
131 size_t bytes = sg->length + sg->offset;
132
133 VERB("map[%d]: %08x %08x(%zx)", i, iova, pa, bytes);
134
135 ret = iommu_map(domain, da, pa, bytes, prot);
136 if (ret)
137 goto fail;
138
139 da += bytes;
140 }
141
142 return 0;
143
144fail:
145 da = iova;
146
147 for_each_sg(sgt->sgl, sg, i, j) {
148 size_t bytes = sg->length + sg->offset;
149
150 iommu_unmap(domain, da, bytes);
151 da += bytes;
152 }
153 return ret;
154}
155
156static int msm_smmu_map_sg(struct msm_mmu *mmu, struct sg_table *sgt,
157 enum dma_data_direction dir)
158{
159 struct msm_smmu *smmu = to_msm_smmu(mmu);
160 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
161 int ret;
162
163 ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents, dir);
164 if (ret != sgt->nents)
165 return -ENOMEM;
166
167 return 0;
168}
169
170static void msm_smmu_unmap_sg(struct msm_mmu *mmu, struct sg_table *sgt,
171 enum dma_data_direction dir)
172{
173 struct msm_smmu *smmu = to_msm_smmu(mmu);
174 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
175
176 dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir);
177}
178
179static int msm_smmu_unmap(struct msm_mmu *mmu, uint32_t iova,
180 struct sg_table *sgt, unsigned int len)
181{
182 struct msm_smmu *smmu = to_msm_smmu(mmu);
183 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
184 struct iommu_domain *domain;
185 struct scatterlist *sg;
186 unsigned int da = iova;
187 int i;
188
189 if (!client)
190 return -ENODEV;
191
192 domain = client->mmu_mapping->domain;
193 if (!domain || !sgt)
194 return -EINVAL;
195
196 for_each_sg(sgt->sgl, sg, sgt->nents, i) {
197 size_t bytes = sg->length + sg->offset;
198 size_t unmapped;
199
200 unmapped = iommu_unmap(domain, da, bytes);
201 if (unmapped < bytes)
202 return unmapped;
203
204 VERB("unmap[%d]: %08x(%zx)", i, iova, bytes);
205
206 WARN_ON(!PAGE_ALIGNED(bytes));
207
208 da += bytes;
209 }
210
211 return 0;
212}
213
214static void msm_smmu_destroy(struct msm_mmu *mmu)
215{
216 struct msm_smmu *smmu = to_msm_smmu(mmu);
217 struct platform_device *pdev = to_platform_device(smmu->client_dev);
218
Lloyd Atkinson479690d2016-10-04 09:51:22 -0400219 if (smmu->client_dev)
220 platform_device_unregister(pdev);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700221 kfree(smmu);
222}
223
224static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
Clarence Ip24b7c362017-05-14 17:03:50 -0400225 struct dma_buf *dma_buf, int dir, u32 flags)
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700226{
227 struct msm_smmu *smmu = to_msm_smmu(mmu);
228 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
Clarence Ip24b7c362017-05-14 17:03:50 -0400229 unsigned long attrs = 0x0;
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700230 int ret;
231
Clarence Ip24b7c362017-05-14 17:03:50 -0400232 if (flags & MSM_BO_KEEPATTRS)
233 attrs |= DMA_ATTR_IOMMU_USE_UPSTREAM_HINT;
234
235 ret = msm_dma_map_sg_attrs(client->dev, sgt->sgl, sgt->nents, dir,
236 dma_buf, attrs);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700237 if (ret != sgt->nents) {
238 DRM_ERROR("dma map sg failed\n");
239 return -ENOMEM;
240 }
241
Alan Kwongc16e0922017-05-11 14:50:46 -0700242 if (sgt && sgt->sgl) {
243 DRM_DEBUG("%pad/0x%x/0x%x/0x%lx\n", &sgt->sgl->dma_address,
244 sgt->sgl->dma_length, dir, attrs);
245 SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length,
246 dir, attrs);
247 }
248
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700249 return 0;
250}
251
252
253static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
254 struct dma_buf *dma_buf, int dir)
255{
256 struct msm_smmu *smmu = to_msm_smmu(mmu);
257 struct msm_smmu_client *client = msm_smmu_to_client(smmu);
258
Alan Kwongc16e0922017-05-11 14:50:46 -0700259 if (sgt && sgt->sgl) {
260 DRM_DEBUG("%pad/0x%x/0x%x\n", &sgt->sgl->dma_address,
261 sgt->sgl->dma_length, dir);
262 SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, dir);
263 }
264
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700265 msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir, dma_buf);
266}
267
268static const struct msm_mmu_funcs funcs = {
269 .attach = msm_smmu_attach,
270 .detach = msm_smmu_detach,
271 .map = msm_smmu_map,
272 .map_sg = msm_smmu_map_sg,
273 .unmap_sg = msm_smmu_unmap_sg,
274 .unmap = msm_smmu_unmap,
275 .map_dma_buf = msm_smmu_map_dma_buf,
276 .unmap_dma_buf = msm_smmu_unmap_dma_buf,
277 .destroy = msm_smmu_destroy,
278};
279
280static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = {
281 [MSM_SMMU_DOMAIN_UNSECURE] = {
282 .label = "mdp_ns",
Alan Kwong112a84f2016-05-24 20:49:21 -0400283 .va_start = SZ_128K,
284 .va_size = SZ_4G - SZ_128K,
285 .secure = false,
286 },
287 [MSM_SMMU_DOMAIN_SECURE] = {
288 .label = "mdp_s",
289 .va_start = 0,
290 .va_size = SZ_4G,
291 .secure = true,
292 },
293 [MSM_SMMU_DOMAIN_NRT_UNSECURE] = {
294 .label = "rot_ns",
295 .va_start = SZ_128K,
296 .va_size = SZ_4G - SZ_128K,
297 .secure = false,
298 },
299 [MSM_SMMU_DOMAIN_NRT_SECURE] = {
300 .label = "rot_s",
301 .va_start = 0,
302 .va_size = SZ_4G,
303 .secure = true,
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700304 },
305};
306
307static const struct of_device_id msm_smmu_dt_match[] = {
Alan Kwong112a84f2016-05-24 20:49:21 -0400308 { .compatible = "qcom,smmu-mdp-unsec",
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700309 .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_UNSECURE] },
Alan Kwong112a84f2016-05-24 20:49:21 -0400310 { .compatible = "qcom,smmu-mdp-sec",
311 .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_SECURE] },
312 { .compatible = "qcom,smmu-rot-unsec",
313 .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_NRT_UNSECURE] },
314 { .compatible = "qcom,smmu-rot-sec",
315 .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_NRT_SECURE] },
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700316 {}
317};
318MODULE_DEVICE_TABLE(of, msm_smmu_dt_match);
319
320static struct device *msm_smmu_device_create(struct device *dev,
321 enum msm_mmu_domain_type domain,
322 struct msm_smmu *smmu)
323{
324 struct device_node *child;
325 struct platform_device *pdev;
326 int i;
327 const char *compat = NULL;
328
329 for (i = 0; i < ARRAY_SIZE(msm_smmu_dt_match); i++) {
330 if (msm_smmu_dt_match[i].data == &msm_smmu_domains[domain]) {
331 compat = msm_smmu_dt_match[i].compatible;
332 break;
333 }
334 }
335
336 if (!compat) {
Dhaval Patel5473cd22017-03-19 21:38:08 -0700337 DRM_DEBUG("unable to find matching domain for %d\n", domain);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700338 return ERR_PTR(-ENOENT);
339 }
Dhaval Patel5473cd22017-03-19 21:38:08 -0700340 DRM_DEBUG("found domain %d compat: %s\n", domain, compat);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700341
342 if (domain == MSM_SMMU_DOMAIN_UNSECURE) {
343 int rc;
344
Alan Kwong112a84f2016-05-24 20:49:21 -0400345 smmu->client = devm_kzalloc(dev,
346 sizeof(struct msm_smmu_client), GFP_KERNEL);
347 if (!smmu->client)
348 return ERR_PTR(-ENOMEM);
349
350 smmu->client->dev = dev;
351
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700352 rc = _msm_smmu_create_mapping(msm_smmu_to_client(smmu),
353 msm_smmu_dt_match[i].data);
Alan Kwong112a84f2016-05-24 20:49:21 -0400354 if (rc) {
355 devm_kfree(dev, smmu->client);
356 smmu->client = NULL;
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700357 return ERR_PTR(rc);
Alan Kwong112a84f2016-05-24 20:49:21 -0400358 }
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700359
360 return NULL;
361 }
362
363 child = of_find_compatible_node(dev->of_node, NULL, compat);
364 if (!child) {
Dhaval Patel5473cd22017-03-19 21:38:08 -0700365 DRM_DEBUG("unable to find compatible node for %s\n", compat);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700366 return ERR_PTR(-ENODEV);
367 }
368
369 pdev = of_platform_device_create(child, NULL, dev);
370 if (!pdev) {
371 DRM_ERROR("unable to create smmu platform dev for domain %d\n",
372 domain);
373 return ERR_PTR(-ENODEV);
374 }
375
Alan Kwong112a84f2016-05-24 20:49:21 -0400376 smmu->client = platform_get_drvdata(pdev);
377
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700378 return &pdev->dev;
379}
380
381struct msm_mmu *msm_smmu_new(struct device *dev,
382 enum msm_mmu_domain_type domain)
383{
384 struct msm_smmu *smmu;
385 struct device *client_dev;
386
387 smmu = kzalloc(sizeof(*smmu), GFP_KERNEL);
388 if (!smmu)
389 return ERR_PTR(-ENOMEM);
390
391 client_dev = msm_smmu_device_create(dev, domain, smmu);
Alan Kwong112a84f2016-05-24 20:49:21 -0400392 if (IS_ERR(client_dev)) {
393 kfree(smmu);
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700394 return (void *)client_dev ? : ERR_PTR(-ENODEV);
Alan Kwong112a84f2016-05-24 20:49:21 -0400395 }
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700396
397 smmu->client_dev = client_dev;
398 msm_mmu_init(&smmu->base, dev, &funcs);
399
400 return &smmu->base;
401}
402
Alan Kwongc16e0922017-05-11 14:50:46 -0700403static int msm_smmu_fault_handler(struct iommu_domain *domain,
404 struct device *dev, unsigned long iova,
405 int flags, void *token)
406{
407 struct msm_smmu_client *client;
408 int rc = -EINVAL;
409
410 if (!token) {
411 DRM_ERROR("Error: token is NULL\n");
412 return -EINVAL;
413 }
414
415 client = (struct msm_smmu_client *)token;
416
417 /* see iommu.h for fault flags definition */
418 SDE_EVT32(iova, flags);
419 DRM_ERROR("trigger dump, iova=0x%08lx, flags=0x%x\n", iova, flags);
420 DRM_ERROR("SMMU device:%s", client->dev ? client->dev->kobj.name : "");
421
422 /* generate dump, but no panic */
423 SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
424 "dsi1_phy", "vbif", "dbg_bus",
425 "vbif_dbg_bus");
426
427 /*
428 * return -ENOSYS to allow smmu driver to dump out useful
429 * debug info.
430 */
431 return rc;
432}
433
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700434static int _msm_smmu_create_mapping(struct msm_smmu_client *client,
435 const struct msm_smmu_domain *domain)
436{
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700437 int rc;
438
439 client->mmu_mapping = arm_iommu_create_mapping(&platform_bus_type,
440 domain->va_start, domain->va_size);
441 if (IS_ERR(client->mmu_mapping)) {
442 dev_err(client->dev,
443 "iommu create mapping failed for domain=%s\n",
444 domain->label);
445 return PTR_ERR(client->mmu_mapping);
446 }
447
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700448 if (domain->secure) {
449 int secure_vmid = VMID_CP_PIXEL;
450
451 rc = iommu_domain_set_attr(client->mmu_mapping->domain,
452 DOMAIN_ATTR_SECURE_VMID, &secure_vmid);
453 if (rc) {
454 dev_err(client->dev, "couldn't set secure pix vmid\n");
455 goto error;
456 }
457 }
458
Alan Kwongc16e0922017-05-11 14:50:46 -0700459 iommu_set_fault_handler(client->mmu_mapping->domain,
460 msm_smmu_fault_handler, (void *)client);
461
Alan Kwong112a84f2016-05-24 20:49:21 -0400462 DRM_INFO("Created domain %s [%zx,%zx] secure=%d\n",
463 domain->label, domain->va_start, domain->va_size,
464 domain->secure);
465
Adrian Salido-Moreno48ebb792015-10-02 15:54:46 -0700466 return 0;
467
468error:
469 arm_iommu_release_mapping(client->mmu_mapping);
470 return rc;
471}
472
473/**
474 * msm_smmu_probe()
475 * @pdev: platform device
476 *
477 * Each smmu context acts as a separate device and the context banks are
478 * configured with a VA range.
479 * Registers the clks as each context bank has its own clks, for which voting
480 * has to be done everytime before using that context bank.
481 */
482static int msm_smmu_probe(struct platform_device *pdev)
483{
484 const struct of_device_id *match;
485 struct msm_smmu_client *client;
486 const struct msm_smmu_domain *domain;
487 int rc;
488
489 match = of_match_device(msm_smmu_dt_match, &pdev->dev);
490 if (!match || !match->data) {
491 dev_err(&pdev->dev, "probe failed as match data is invalid\n");
492 return -EINVAL;
493 }
494
495 domain = match->data;
496 if (!domain) {
497 dev_err(&pdev->dev, "no matching device found\n");
498 return -EINVAL;
499 }
500
501 DRM_INFO("probing device %s\n", match->compatible);
502
503 client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
504 if (!client)
505 return -ENOMEM;
506
507 client->dev = &pdev->dev;
508
509 rc = _msm_smmu_create_mapping(client, domain);
510 platform_set_drvdata(pdev, client);
511
512 return rc;
513}
514
515static int msm_smmu_remove(struct platform_device *pdev)
516{
517 struct msm_smmu_client *client;
518
519 client = platform_get_drvdata(pdev);
520 if (client->domain_attached) {
521 arm_iommu_detach_device(client->dev);
522 client->domain_attached = false;
523 }
524 arm_iommu_release_mapping(client->mmu_mapping);
525
526 return 0;
527}
528
529static struct platform_driver msm_smmu_driver = {
530 .probe = msm_smmu_probe,
531 .remove = msm_smmu_remove,
532 .driver = {
533 .name = "msmdrm_smmu",
534 .of_match_table = msm_smmu_dt_match,
535 },
536};
537
538static int __init msm_smmu_driver_init(void)
539{
540 int ret;
541
542 ret = platform_driver_register(&msm_smmu_driver);
543 if (ret)
544 pr_err("mdss_smmu_register_driver() failed!\n");
545
546 return ret;
547}
548module_init(msm_smmu_driver_init);
549
550static void __exit msm_smmu_driver_cleanup(void)
551{
552 platform_driver_unregister(&msm_smmu_driver);
553}
554module_exit(msm_smmu_driver_cleanup);
555
556MODULE_LICENSE("GPL v2");
557MODULE_DESCRIPTION("MSM SMMU driver");