aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorHiroshi Doyu <hdoyu@nvidia.com>2012-06-25 07:23:55 -0400
committerJoerg Roedel <joerg.roedel@amd.com>2012-06-25 07:50:43 -0400
commit0760e8faa960f8ee991fa4acb802db4e20661281 (patch)
tree87fd7b7127f4758d71480809c650fdde252b9076 /drivers/iommu
parent4e0ee78f2af96676c9dca898c13250f62c513058 (diff)
iommu/tegra: smmu: Add device tree support for SMMU
The necessary info is expected to pass from DT. For more precise resource reservation, there shouldn't be any overlapping of register range between SMMU and MC. SMMU register offset needs to be calculated correctly, based on its register bank. Signed-off-by: Hiroshi DOYU <hdoyu@nvidia.com> Acked-by: Stephen Warren <swarren@wwwdotorg.org> Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/Kconfig2
-rw-r--r--drivers/iommu/tegra-smmu.c149
2 files changed, 96 insertions, 55 deletions
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 4826af62a9d..9f69b561f5d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -158,7 +158,7 @@ config TEGRA_IOMMU_GART
158 158
159config TEGRA_IOMMU_SMMU 159config TEGRA_IOMMU_SMMU
160 bool "Tegra SMMU IOMMU Support" 160 bool "Tegra SMMU IOMMU Support"
161 depends on ARCH_TEGRA_3x_SOC 161 depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB
162 select IOMMU_API 162 select IOMMU_API
163 help 163 help
164 Enables support for remapping discontiguous physical memory 164 Enables support for remapping discontiguous physical memory
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index ecd679043d7..2c92b8c3514 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -30,12 +30,15 @@
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/iommu.h> 31#include <linux/iommu.h>
32#include <linux/io.h> 32#include <linux/io.h>
33#include <linux/of.h>
34#include <linux/of_iommu.h>
33 35
34#include <asm/page.h> 36#include <asm/page.h>
35#include <asm/cacheflush.h> 37#include <asm/cacheflush.h>
36 38
37#include <mach/iomap.h> 39#include <mach/iomap.h>
38#include <mach/smmu.h> 40#include <mach/smmu.h>
41#include <mach/tegra-ahb.h>
39 42
40/* bitmap of the page sizes currently supported */ 43/* bitmap of the page sizes currently supported */
41#define SMMU_IOMMU_PGSIZES (SZ_4K) 44#define SMMU_IOMMU_PGSIZES (SZ_4K)
@@ -111,12 +114,6 @@
111 114
112#define SMMU_PDE_NEXT_SHIFT 28 115#define SMMU_PDE_NEXT_SHIFT 28
113 116
114/* AHB Arbiter Registers */
115#define AHB_XBAR_CTRL 0xe0
116#define AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE 1
117#define AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT 17
118
119#define SMMU_NUM_ASIDS 4
120#define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000 117#define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000
121#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */ 118#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */
122#define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000 119#define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000
@@ -136,6 +133,7 @@
136 133
137#define SMMU_PAGE_SHIFT 12 134#define SMMU_PAGE_SHIFT 12
138#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) 135#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
136#define SMMU_PAGE_MASK ((1 << SMMU_PAGE_SHIFT) - 1)
139 137
140#define SMMU_PDIR_COUNT 1024 138#define SMMU_PDIR_COUNT 1024
141#define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT) 139#define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT)
@@ -177,6 +175,8 @@
177#define SMMU_ASID_DISABLE 0 175#define SMMU_ASID_DISABLE 0
178#define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0)) 176#define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0))
179 177
178#define NUM_SMMU_REG_BANKS 3
179
180#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1) 180#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
181#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0) 181#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0)
182#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1) 182#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
@@ -235,7 +235,7 @@ struct smmu_as {
235 * Per SMMU device - IOMMU device 235 * Per SMMU device - IOMMU device
236 */ 236 */
237struct smmu_device { 237struct smmu_device {
238 void __iomem *regs, *regs_ahbarb; 238 void __iomem *regs[NUM_SMMU_REG_BANKS];
239 unsigned long iovmm_base; /* remappable base address */ 239 unsigned long iovmm_base; /* remappable base address */
240 unsigned long page_count; /* total remappable size */ 240 unsigned long page_count; /* total remappable size */
241 spinlock_t lock; 241 spinlock_t lock;
@@ -252,29 +252,47 @@ struct smmu_device {
252 unsigned long translation_enable_1; 252 unsigned long translation_enable_1;
253 unsigned long translation_enable_2; 253 unsigned long translation_enable_2;
254 unsigned long asid_security; 254 unsigned long asid_security;
255
256 struct device_node *ahb;
255}; 257};
256 258
257static struct smmu_device *smmu_handle; /* unique for a system */ 259static struct smmu_device *smmu_handle; /* unique for a system */
258 260
259/* 261/*
260 * SMMU/AHB register accessors 262 * SMMU register accessors
261 */ 263 */
262static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) 264static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
263{ 265{
264 return readl(smmu->regs + offs); 266 BUG_ON(offs < 0x10);
265} 267 if (offs < 0x3c)
266static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) 268 return readl(smmu->regs[0] + offs - 0x10);
267{ 269 BUG_ON(offs < 0x1f0);
268 writel(val, smmu->regs + offs); 270 if (offs < 0x200)
271 return readl(smmu->regs[1] + offs - 0x1f0);
272 BUG_ON(offs < 0x228);
273 if (offs < 0x284)
274 return readl(smmu->regs[2] + offs - 0x228);
275 BUG();
269} 276}
270 277
271static inline u32 ahb_read(struct smmu_device *smmu, size_t offs) 278static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
272{
273 return readl(smmu->regs_ahbarb + offs);
274}
275static inline void ahb_write(struct smmu_device *smmu, u32 val, size_t offs)
276{ 279{
277 writel(val, smmu->regs_ahbarb + offs); 280 BUG_ON(offs < 0x10);
281 if (offs < 0x3c) {
282 writel(val, smmu->regs[0] + offs - 0x10);
283 return;
284 }
285 BUG_ON(offs < 0x1f0);
286 if (offs < 0x200) {
287 writel(val, smmu->regs[1] + offs - 0x1f0);
288 return;
289 }
290 BUG_ON(offs < 0x228);
291 if (offs < 0x284) {
292 writel(val, smmu->regs[2] + offs - 0x228);
293 return;
294 }
295 BUG();
278} 296}
279 297
280#define VA_PAGE_TO_PA(va, page) \ 298#define VA_PAGE_TO_PA(va, page) \
@@ -370,7 +388,7 @@ static void smmu_flush_regs(struct smmu_device *smmu, int enable)
370 FLUSH_SMMU_REGS(smmu); 388 FLUSH_SMMU_REGS(smmu);
371} 389}
372 390
373static void smmu_setup_regs(struct smmu_device *smmu) 391static int smmu_setup_regs(struct smmu_device *smmu)
374{ 392{
375 int i; 393 int i;
376 u32 val; 394 u32 val;
@@ -398,10 +416,7 @@ static void smmu_setup_regs(struct smmu_device *smmu)
398 416
399 smmu_flush_regs(smmu, 1); 417 smmu_flush_regs(smmu, 1);
400 418
401 val = ahb_read(smmu, AHB_XBAR_CTRL); 419 return tegra_ahb_enable_smmu(smmu->ahb);
402 val |= AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE <<
403 AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT;
404 ahb_write(smmu, val, AHB_XBAR_CTRL);
405} 420}
406 421
407static void flush_ptc_and_tlb(struct smmu_device *smmu, 422static void flush_ptc_and_tlb(struct smmu_device *smmu,
@@ -873,52 +888,72 @@ static int tegra_smmu_resume(struct device *dev)
873{ 888{
874 struct smmu_device *smmu = dev_get_drvdata(dev); 889 struct smmu_device *smmu = dev_get_drvdata(dev);
875 unsigned long flags; 890 unsigned long flags;
891 int err;
876 892
877 spin_lock_irqsave(&smmu->lock, flags); 893 spin_lock_irqsave(&smmu->lock, flags);
878 smmu_setup_regs(smmu); 894 err = smmu_setup_regs(smmu);
879 spin_unlock_irqrestore(&smmu->lock, flags); 895 spin_unlock_irqrestore(&smmu->lock, flags);
880 return 0; 896 return err;
881} 897}
882 898
883static int tegra_smmu_probe(struct platform_device *pdev) 899static int tegra_smmu_probe(struct platform_device *pdev)
884{ 900{
885 struct smmu_device *smmu; 901 struct smmu_device *smmu;
886 struct resource *regs, *regs2, *window;
887 struct device *dev = &pdev->dev; 902 struct device *dev = &pdev->dev;
888 int i, err = 0; 903 int i, asids, err = 0;
904 dma_addr_t base;
905 size_t size;
906 const void *prop;
889 907
890 if (smmu_handle) 908 if (smmu_handle)
891 return -EIO; 909 return -EIO;
892 910
893 BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT); 911 BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
894 912
895 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
896 regs2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
897 window = platform_get_resource(pdev, IORESOURCE_MEM, 2);
898 if (!regs || !regs2 || !window) {
899 dev_err(dev, "No SMMU resources\n");
900 return -ENODEV;
901 }
902
903 smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); 913 smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
904 if (!smmu) { 914 if (!smmu) {
905 dev_err(dev, "failed to allocate smmu_device\n"); 915 dev_err(dev, "failed to allocate smmu_device\n");
906 return -ENOMEM; 916 return -ENOMEM;
907 } 917 }
908 918
909 smmu->dev = dev; 919 for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) {
910 smmu->num_as = SMMU_NUM_ASIDS; 920 struct resource *res;
911 smmu->iovmm_base = (unsigned long)window->start; 921
912 smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT; 922 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
913 smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs)); 923 if (!res)
914 smmu->regs_ahbarb = devm_ioremap(dev, regs2->start, 924 return -ENODEV;
915 resource_size(regs2)); 925 smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
916 if (!smmu->regs || !smmu->regs_ahbarb) { 926 if (!smmu->regs[i])
917 dev_err(dev, "failed to remap SMMU registers\n"); 927 return -EBUSY;
918 err = -ENXIO;
919 goto fail;
920 } 928 }
921 929
930 err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
931 if (err)
932 return -ENODEV;
933
934 if (size & SMMU_PAGE_MASK)
935 return -EINVAL;
936
937 size >>= SMMU_PAGE_SHIFT;
938 if (!size)
939 return -EINVAL;
940
941 prop = of_get_property(dev->of_node, "nvidia,#asids", NULL);
942 if (!prop)
943 return -ENODEV;
944 asids = be32_to_cpup(prop);
945 if (!asids)
946 return -ENODEV;
947
948 smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0);
949 if (!smmu->ahb)
950 return -ENODEV;
951
952 smmu->dev = dev;
953 smmu->num_as = asids;
954 smmu->iovmm_base = base;
955 smmu->page_count = size;
956
922 smmu->translation_enable_0 = ~0; 957 smmu->translation_enable_0 = ~0;
923 smmu->translation_enable_1 = ~0; 958 smmu->translation_enable_1 = ~0;
924 smmu->translation_enable_2 = ~0; 959 smmu->translation_enable_2 = ~0;
@@ -945,7 +980,9 @@ static int tegra_smmu_probe(struct platform_device *pdev)
945 INIT_LIST_HEAD(&as->client); 980 INIT_LIST_HEAD(&as->client);
946 } 981 }
947 spin_lock_init(&smmu->lock); 982 spin_lock_init(&smmu->lock);
948 smmu_setup_regs(smmu); 983 err = smmu_setup_regs(smmu);
984 if (err)
985 goto fail;
949 platform_set_drvdata(pdev, smmu); 986 platform_set_drvdata(pdev, smmu);
950 987
951 smmu->avp_vector_page = alloc_page(GFP_KERNEL); 988 smmu->avp_vector_page = alloc_page(GFP_KERNEL);
@@ -958,10 +995,6 @@ static int tegra_smmu_probe(struct platform_device *pdev)
958fail: 995fail:
959 if (smmu->avp_vector_page) 996 if (smmu->avp_vector_page)
960 __free_page(smmu->avp_vector_page); 997 __free_page(smmu->avp_vector_page);
961 if (smmu->regs)
962 devm_iounmap(dev, smmu->regs);
963 if (smmu->regs_ahbarb)
964 devm_iounmap(dev, smmu->regs_ahbarb);
965 if (smmu && smmu->as) { 998 if (smmu && smmu->as) {
966 for (i = 0; i < smmu->num_as; i++) { 999 for (i = 0; i < smmu->num_as; i++) {
967 if (smmu->as[i].pdir_page) { 1000 if (smmu->as[i].pdir_page) {
@@ -993,8 +1026,6 @@ static int tegra_smmu_remove(struct platform_device *pdev)
993 __free_page(smmu->avp_vector_page); 1026 __free_page(smmu->avp_vector_page);
994 if (smmu->regs) 1027 if (smmu->regs)
995 devm_iounmap(dev, smmu->regs); 1028 devm_iounmap(dev, smmu->regs);
996 if (smmu->regs_ahbarb)
997 devm_iounmap(dev, smmu->regs_ahbarb);
998 devm_kfree(dev, smmu); 1029 devm_kfree(dev, smmu);
999 smmu_handle = NULL; 1030 smmu_handle = NULL;
1000 return 0; 1031 return 0;
@@ -1005,6 +1036,14 @@ const struct dev_pm_ops tegra_smmu_pm_ops = {
1005 .resume = tegra_smmu_resume, 1036 .resume = tegra_smmu_resume,
1006}; 1037};
1007 1038
1039#ifdef CONFIG_OF
1040static struct of_device_id tegra_smmu_of_match[] __devinitdata = {
1041 { .compatible = "nvidia,tegra30-smmu", },
1042 { },
1043};
1044MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
1045#endif
1046
1008static struct platform_driver tegra_smmu_driver = { 1047static struct platform_driver tegra_smmu_driver = {
1009 .probe = tegra_smmu_probe, 1048 .probe = tegra_smmu_probe,
1010 .remove = tegra_smmu_remove, 1049 .remove = tegra_smmu_remove,
@@ -1012,6 +1051,7 @@ static struct platform_driver tegra_smmu_driver = {
1012 .owner = THIS_MODULE, 1051 .owner = THIS_MODULE,
1013 .name = "tegra-smmu", 1052 .name = "tegra-smmu",
1014 .pm = &tegra_smmu_pm_ops, 1053 .pm = &tegra_smmu_pm_ops,
1054 .of_match_table = of_match_ptr(tegra_smmu_of_match),
1015 }, 1055 },
1016}; 1056};
1017 1057
@@ -1031,4 +1071,5 @@ module_exit(tegra_smmu_exit);
1031 1071
1032MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30"); 1072MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
1033MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); 1073MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
1074MODULE_ALIAS("platform:tegra-smmu");
1034MODULE_LICENSE("GPL v2"); 1075MODULE_LICENSE("GPL v2");