diff options
| author | Dmitry Osipenko <digetx@gmail.com> | 2018-12-12 15:38:56 -0500 |
|---|---|---|
| committer | Joerg Roedel <jroedel@suse.de> | 2019-01-16 07:54:12 -0500 |
| commit | ce2785a75dbca27375f3723f4e697a2a8dc096ee (patch) | |
| tree | 89451c3cdcc2103f759587db69e6eb9355423459 | |
| parent | 45594c683ef780f20f11b1e0018b933b6ff5d9a1 (diff) | |
iommu/tegra: gart: Integrate with Memory Controller driver
The device-tree binding has been changed. There is no separate GART device
anymore, it is squashed into the Memory Controller. Integrate GART module
with the MC in a way it is done for the SMMU on Tegra30+.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
| -rw-r--r-- | drivers/iommu/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/iommu/tegra-gart.c | 71 | ||||
| -rw-r--r-- | drivers/memory/tegra/mc.c | 43 | ||||
| -rw-r--r-- | include/soc/tegra/mc.h | 25 |
4 files changed, 87 insertions, 53 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index d9a25715650e..83c099bb7288 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig | |||
| @@ -282,6 +282,7 @@ config ROCKCHIP_IOMMU | |||
| 282 | config TEGRA_IOMMU_GART | 282 | config TEGRA_IOMMU_GART |
| 283 | bool "Tegra GART IOMMU Support" | 283 | bool "Tegra GART IOMMU Support" |
| 284 | depends on ARCH_TEGRA_2x_SOC | 284 | depends on ARCH_TEGRA_2x_SOC |
| 285 | depends on TEGRA_MC | ||
| 285 | select IOMMU_API | 286 | select IOMMU_API |
| 286 | help | 287 | help |
| 287 | Enables support for remapping discontiguous physical memory | 288 | Enables support for remapping discontiguous physical memory |
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index 835fea461c59..b35ffa312a83 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c | |||
| @@ -19,16 +19,17 @@ | |||
| 19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/io.h> | 22 | #include <linux/io.h> |
| 24 | #include <linux/iommu.h> | 23 | #include <linux/iommu.h> |
| 25 | #include <linux/list.h> | 24 | #include <linux/list.h> |
| 26 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
| 27 | #include <linux/of_device.h> | 26 | #include <linux/platform_device.h> |
| 28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 29 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
| 30 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
| 31 | 30 | ||
| 31 | #include <soc/tegra/mc.h> | ||
| 32 | |||
| 32 | /* bitmap of the page sizes currently supported */ | 33 | /* bitmap of the page sizes currently supported */ |
| 33 | #define GART_IOMMU_PGSIZES (SZ_4K) | 34 | #define GART_IOMMU_PGSIZES (SZ_4K) |
| 34 | 35 | ||
| @@ -397,9 +398,8 @@ static const struct iommu_ops gart_iommu_ops = { | |||
| 397 | .iotlb_sync = gart_iommu_sync, | 398 | .iotlb_sync = gart_iommu_sync, |
| 398 | }; | 399 | }; |
| 399 | 400 | ||
| 400 | static int tegra_gart_suspend(struct device *dev) | 401 | int tegra_gart_suspend(struct gart_device *gart) |
| 401 | { | 402 | { |
| 402 | struct gart_device *gart = dev_get_drvdata(dev); | ||
| 403 | unsigned long iova; | 403 | unsigned long iova; |
| 404 | u32 *data = gart->savedata; | 404 | u32 *data = gart->savedata; |
| 405 | unsigned long flags; | 405 | unsigned long flags; |
| @@ -411,9 +411,8 @@ static int tegra_gart_suspend(struct device *dev) | |||
| 411 | return 0; | 411 | return 0; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | static int tegra_gart_resume(struct device *dev) | 414 | int tegra_gart_resume(struct gart_device *gart) |
| 415 | { | 415 | { |
| 416 | struct gart_device *gart = dev_get_drvdata(dev); | ||
| 417 | unsigned long flags; | 416 | unsigned long flags; |
| 418 | 417 | ||
| 419 | spin_lock_irqsave(&gart->pte_lock, flags); | 418 | spin_lock_irqsave(&gart->pte_lock, flags); |
| @@ -422,41 +421,33 @@ static int tegra_gart_resume(struct device *dev) | |||
| 422 | return 0; | 421 | return 0; |
| 423 | } | 422 | } |
| 424 | 423 | ||
| 425 | static int tegra_gart_probe(struct platform_device *pdev) | 424 | struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc) |
| 426 | { | 425 | { |
| 427 | struct gart_device *gart; | 426 | struct gart_device *gart; |
| 428 | struct resource *res, *res_remap; | 427 | struct resource *res_remap; |
| 429 | void __iomem *gart_regs; | 428 | void __iomem *gart_regs; |
| 430 | struct device *dev = &pdev->dev; | ||
| 431 | int ret; | 429 | int ret; |
| 432 | 430 | ||
| 433 | BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); | 431 | BUILD_BUG_ON(PAGE_SHIFT != GART_PAGE_SHIFT); |
| 434 | 432 | ||
| 435 | /* the GART memory aperture is required */ | 433 | /* the GART memory aperture is required */ |
| 436 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 434 | res_remap = platform_get_resource(to_platform_device(dev), |
| 437 | res_remap = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 435 | IORESOURCE_MEM, 1); |
| 438 | if (!res || !res_remap) { | 436 | if (!res_remap) { |
| 439 | dev_err(dev, "GART memory aperture expected\n"); | 437 | dev_err(dev, "GART memory aperture expected\n"); |
| 440 | return -ENXIO; | 438 | return ERR_PTR(-ENXIO); |
| 441 | } | 439 | } |
| 442 | 440 | ||
| 443 | gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL); | 441 | gart = devm_kzalloc(dev, sizeof(*gart), GFP_KERNEL); |
| 444 | if (!gart) { | 442 | if (!gart) { |
| 445 | dev_err(dev, "failed to allocate gart_device\n"); | 443 | dev_err(dev, "failed to allocate gart_device\n"); |
| 446 | return -ENOMEM; | 444 | return ERR_PTR(-ENOMEM); |
| 447 | } | ||
| 448 | |||
| 449 | gart_regs = devm_ioremap(dev, res->start, resource_size(res)); | ||
| 450 | if (!gart_regs) { | ||
| 451 | dev_err(dev, "failed to remap GART registers\n"); | ||
| 452 | return -ENXIO; | ||
| 453 | } | 445 | } |
| 454 | 446 | ||
| 455 | ret = iommu_device_sysfs_add(&gart->iommu, &pdev->dev, NULL, | 447 | ret = iommu_device_sysfs_add(&gart->iommu, dev, NULL, "gart"); |
| 456 | dev_name(&pdev->dev)); | ||
| 457 | if (ret) { | 448 | if (ret) { |
| 458 | dev_err(dev, "Failed to register IOMMU in sysfs\n"); | 449 | dev_err(dev, "Failed to register IOMMU in sysfs\n"); |
| 459 | return ret; | 450 | return ERR_PTR(ret); |
| 460 | } | 451 | } |
| 461 | 452 | ||
| 462 | iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); | 453 | iommu_device_set_ops(&gart->iommu, &gart_iommu_ops); |
| @@ -468,7 +459,8 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 468 | goto remove_sysfs; | 459 | goto remove_sysfs; |
| 469 | } | 460 | } |
| 470 | 461 | ||
| 471 | gart->dev = &pdev->dev; | 462 | gart->dev = dev; |
| 463 | gart_regs = mc->regs + GART_REG_BASE; | ||
| 472 | spin_lock_init(&gart->pte_lock); | 464 | spin_lock_init(&gart->pte_lock); |
| 473 | spin_lock_init(&gart->client_lock); | 465 | spin_lock_init(&gart->client_lock); |
| 474 | INIT_LIST_HEAD(&gart->client); | 466 | INIT_LIST_HEAD(&gart->client); |
| @@ -483,46 +475,19 @@ static int tegra_gart_probe(struct platform_device *pdev) | |||
| 483 | goto unregister_iommu; | 475 | goto unregister_iommu; |
| 484 | } | 476 | } |
| 485 | 477 | ||
| 486 | platform_set_drvdata(pdev, gart); | ||
| 487 | do_gart_setup(gart, NULL); | 478 | do_gart_setup(gart, NULL); |
| 488 | 479 | ||
| 489 | gart_handle = gart; | 480 | gart_handle = gart; |
| 490 | 481 | ||
| 491 | return 0; | 482 | return gart; |
| 492 | 483 | ||
| 493 | unregister_iommu: | 484 | unregister_iommu: |
| 494 | iommu_device_unregister(&gart->iommu); | 485 | iommu_device_unregister(&gart->iommu); |
| 495 | remove_sysfs: | 486 | remove_sysfs: |
| 496 | iommu_device_sysfs_remove(&gart->iommu); | 487 | iommu_device_sysfs_remove(&gart->iommu); |
| 497 | 488 | ||
| 498 | return ret; | 489 | return ERR_PTR(ret); |
| 499 | } | ||
| 500 | |||
| 501 | static const struct dev_pm_ops tegra_gart_pm_ops = { | ||
| 502 | .suspend = tegra_gart_suspend, | ||
| 503 | .resume = tegra_gart_resume, | ||
| 504 | }; | ||
| 505 | |||
| 506 | static const struct of_device_id tegra_gart_of_match[] = { | ||
| 507 | { .compatible = "nvidia,tegra20-gart", }, | ||
| 508 | { }, | ||
| 509 | }; | ||
| 510 | |||
| 511 | static struct platform_driver tegra_gart_driver = { | ||
| 512 | .probe = tegra_gart_probe, | ||
| 513 | .driver = { | ||
| 514 | .name = "tegra-gart", | ||
| 515 | .pm = &tegra_gart_pm_ops, | ||
| 516 | .of_match_table = tegra_gart_of_match, | ||
| 517 | .suppress_bind_attrs = true, | ||
| 518 | }, | ||
| 519 | }; | ||
| 520 | |||
| 521 | static int __init tegra_gart_init(void) | ||
| 522 | { | ||
| 523 | return platform_driver_register(&tegra_gart_driver); | ||
| 524 | } | 490 | } |
| 525 | subsys_initcall(tegra_gart_init); | ||
| 526 | 491 | ||
| 527 | module_param(gart_debug, bool, 0644); | 492 | module_param(gart_debug, bool, 0644); |
| 528 | MODULE_PARM_DESC(gart_debug, "Enable GART debugging"); | 493 | MODULE_PARM_DESC(gart_debug, "Enable GART debugging"); |
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 55ecfb2d8cfd..e684e234361a 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c | |||
| @@ -702,13 +702,56 @@ static int tegra_mc_probe(struct platform_device *pdev) | |||
| 702 | PTR_ERR(mc->smmu)); | 702 | PTR_ERR(mc->smmu)); |
| 703 | } | 703 | } |
| 704 | 704 | ||
| 705 | if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { | ||
| 706 | mc->gart = tegra_gart_probe(&pdev->dev, mc); | ||
| 707 | if (IS_ERR(mc->gart)) { | ||
| 708 | dev_err(&pdev->dev, "failed to probe GART: %ld\n", | ||
| 709 | PTR_ERR(mc->gart)); | ||
| 710 | mc->gart = NULL; | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | return 0; | ||
| 715 | } | ||
| 716 | |||
| 717 | static int tegra_mc_suspend(struct device *dev) | ||
| 718 | { | ||
| 719 | struct tegra_mc *mc = dev_get_drvdata(dev); | ||
| 720 | int err; | ||
| 721 | |||
| 722 | if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { | ||
| 723 | err = tegra_gart_suspend(mc->gart); | ||
| 724 | if (err) | ||
| 725 | return err; | ||
| 726 | } | ||
| 727 | |||
| 705 | return 0; | 728 | return 0; |
| 706 | } | 729 | } |
| 707 | 730 | ||
| 731 | static int tegra_mc_resume(struct device *dev) | ||
| 732 | { | ||
| 733 | struct tegra_mc *mc = dev_get_drvdata(dev); | ||
| 734 | int err; | ||
| 735 | |||
| 736 | if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { | ||
| 737 | err = tegra_gart_resume(mc->gart); | ||
| 738 | if (err) | ||
| 739 | return err; | ||
| 740 | } | ||
| 741 | |||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | |||
| 745 | static const struct dev_pm_ops tegra_mc_pm_ops = { | ||
| 746 | .suspend = tegra_mc_suspend, | ||
| 747 | .resume = tegra_mc_resume, | ||
| 748 | }; | ||
| 749 | |||
| 708 | static struct platform_driver tegra_mc_driver = { | 750 | static struct platform_driver tegra_mc_driver = { |
| 709 | .driver = { | 751 | .driver = { |
| 710 | .name = "tegra-mc", | 752 | .name = "tegra-mc", |
| 711 | .of_match_table = tegra_mc_of_match, | 753 | .of_match_table = tegra_mc_of_match, |
| 754 | .pm = &tegra_mc_pm_ops, | ||
| 712 | .suppress_bind_attrs = true, | 755 | .suppress_bind_attrs = true, |
| 713 | }, | 756 | }, |
| 714 | .prevent_deferred_probe = true, | 757 | .prevent_deferred_probe = true, |
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index db5bfdf589b4..e489a028ec9f 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #ifndef __SOC_TEGRA_MC_H__ | 9 | #ifndef __SOC_TEGRA_MC_H__ |
| 10 | #define __SOC_TEGRA_MC_H__ | 10 | #define __SOC_TEGRA_MC_H__ |
| 11 | 11 | ||
| 12 | #include <linux/err.h> | ||
| 12 | #include <linux/reset-controller.h> | 13 | #include <linux/reset-controller.h> |
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 14 | 15 | ||
| @@ -77,6 +78,7 @@ struct tegra_smmu_soc { | |||
| 77 | 78 | ||
| 78 | struct tegra_mc; | 79 | struct tegra_mc; |
| 79 | struct tegra_smmu; | 80 | struct tegra_smmu; |
| 81 | struct gart_device; | ||
| 80 | 82 | ||
| 81 | #ifdef CONFIG_TEGRA_IOMMU_SMMU | 83 | #ifdef CONFIG_TEGRA_IOMMU_SMMU |
| 82 | struct tegra_smmu *tegra_smmu_probe(struct device *dev, | 84 | struct tegra_smmu *tegra_smmu_probe(struct device *dev, |
| @@ -96,6 +98,28 @@ static inline void tegra_smmu_remove(struct tegra_smmu *smmu) | |||
| 96 | } | 98 | } |
| 97 | #endif | 99 | #endif |
| 98 | 100 | ||
| 101 | #ifdef CONFIG_TEGRA_IOMMU_GART | ||
| 102 | struct gart_device *tegra_gart_probe(struct device *dev, struct tegra_mc *mc); | ||
| 103 | int tegra_gart_suspend(struct gart_device *gart); | ||
| 104 | int tegra_gart_resume(struct gart_device *gart); | ||
| 105 | #else | ||
| 106 | static inline struct gart_device * | ||
| 107 | tegra_gart_probe(struct device *dev, struct tegra_mc *mc) | ||
| 108 | { | ||
| 109 | return ERR_PTR(-ENODEV); | ||
| 110 | } | ||
| 111 | |||
| 112 | static inline int tegra_gart_suspend(struct gart_device *gart) | ||
| 113 | { | ||
| 114 | return -ENODEV; | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline int tegra_gart_resume(struct gart_device *gart) | ||
| 118 | { | ||
| 119 | return -ENODEV; | ||
| 120 | } | ||
| 121 | #endif | ||
| 122 | |||
| 99 | struct tegra_mc_reset { | 123 | struct tegra_mc_reset { |
| 100 | const char *name; | 124 | const char *name; |
| 101 | unsigned long id; | 125 | unsigned long id; |
| @@ -144,6 +168,7 @@ struct tegra_mc_soc { | |||
| 144 | struct tegra_mc { | 168 | struct tegra_mc { |
| 145 | struct device *dev; | 169 | struct device *dev; |
| 146 | struct tegra_smmu *smmu; | 170 | struct tegra_smmu *smmu; |
| 171 | struct gart_device *gart; | ||
| 147 | void __iomem *regs; | 172 | void __iomem *regs; |
| 148 | struct clk *clk; | 173 | struct clk *clk; |
| 149 | int irq; | 174 | int irq; |
