Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hiroshi Doyu and committed by
Joerg Roedel
0760e8fa 4e0ee78f

+117 -55
+21
Documentation/devicetree/bindings/iommu/nvidia,tegra30-smmu.txt
··· 1 + NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit) 2 + 3 + Required properties: 4 + - compatible : "nvidia,tegra30-smmu" 5 + - reg : Should contain 3 register banks(address and length) for each 6 + of the SMMU register blocks. 7 + - interrupts : Should contain MC General interrupt. 8 + - nvidia,#asids : # of ASIDs 9 + - dma-window : IOVA start address and length. 10 + - nvidia,ahb : phandle to the ahb bus connected to SMMU. 11 + 12 + Example: 13 + smmu { 14 + compatible = "nvidia,tegra30-smmu"; 15 + reg = <0x7000f010 0x02c 16 + 0x7000f1f0 0x010 17 + 0x7000f228 0x05c>; 18 + nvidia,#asids = <4>; /* # of ASIDs */ 19 + dma-window = <0 0x40000000>; /* IOVA start & length */ 20 + nvidia,ahb = <&ahb>; 21 + };
+1 -1
drivers/iommu/Kconfig
··· 158 158 159 159 config TEGRA_IOMMU_SMMU 160 160 bool "Tegra SMMU IOMMU Support" 161 - depends on ARCH_TEGRA_3x_SOC 161 + depends on ARCH_TEGRA_3x_SOC && TEGRA_AHB 162 162 select IOMMU_API 163 163 help 164 164 Enables support for remapping discontiguous physical memory
+95 -54
drivers/iommu/tegra-smmu.c
··· 30 30 #include <linux/sched.h> 31 31 #include <linux/iommu.h> 32 32 #include <linux/io.h> 33 + #include <linux/of.h> 34 + #include <linux/of_iommu.h> 33 35 34 36 #include <asm/page.h> 35 37 #include <asm/cacheflush.h> 36 38 37 39 #include <mach/iomap.h> 38 40 #include <mach/smmu.h> 41 + #include <mach/tegra-ahb.h> 39 42 40 43 /* bitmap of the page sizes currently supported */ 41 44 #define SMMU_IOMMU_PGSIZES (SZ_4K) ··· 114 111 115 112 #define SMMU_PDE_NEXT_SHIFT 28 116 113 117 - /* AHB Arbiter Registers */ 118 - #define AHB_XBAR_CTRL 0xe0 119 - #define AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE 1 120 - #define AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT 17 121 - 122 - #define SMMU_NUM_ASIDS 4 123 114 #define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000 124 115 #define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */ 125 116 #define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000 ··· 133 136 134 137 #define SMMU_PAGE_SHIFT 12 135 138 #define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT) 139 + #define SMMU_PAGE_MASK ((1 << SMMU_PAGE_SHIFT) - 1) 136 140 137 141 #define SMMU_PDIR_COUNT 1024 138 142 #define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT) ··· 174 176 #define SMMU_ASID_ENABLE(asid) ((asid) | (1 << 31)) 175 177 #define SMMU_ASID_DISABLE 0 176 178 #define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0)) 179 + 180 + #define NUM_SMMU_REG_BANKS 3 177 181 178 182 #define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1) 179 183 #define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0) ··· 235 235 * Per SMMU device - IOMMU device 236 236 */ 237 237 struct smmu_device { 238 - void __iomem *regs, *regs_ahbarb; 238 + void __iomem *regs[NUM_SMMU_REG_BANKS]; 239 239 unsigned long iovmm_base; /* remappable base address */ 240 240 unsigned long page_count; /* total remappable size */ 241 241 spinlock_t lock; ··· 252 252 unsigned long translation_enable_1; 253 253 unsigned long translation_enable_2; 254 254 unsigned long asid_security; 255 + 256 + struct device_node *ahb; 255 257 }; 256 258 257 259 static struct smmu_device *smmu_handle; /* unique for a system */ 258 260 259 261 /* 260 - * SMMU/AHB register accessors 262 + * SMMU register accessors 261 263 */ 262 264 static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) 263 265 { 264 - return readl(smmu->regs + offs); 265 - } 266 - static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) 267 - { 268 - writel(val, smmu->regs + offs); 266 + BUG_ON(offs < 0x10); 267 + if (offs < 0x3c) 268 + return readl(smmu->regs[0] + offs - 0x10); 269 + BUG_ON(offs < 0x1f0); 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 271 - static inline u32 ahb_read(struct smmu_device *smmu, size_t offs) 278 + static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) 272 279 { 273 - return readl(smmu->regs_ahbarb + offs); 274 - } 275 - static inline void ahb_write(struct smmu_device *smmu, u32 val, size_t offs) 276 - { 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 298 #define VA_PAGE_TO_PA(va, page) \ ··· 388 370 FLUSH_SMMU_REGS(smmu); 389 371 } 390 372 391 - static void smmu_setup_regs(struct smmu_device *smmu) 373 + static int smmu_setup_regs(struct smmu_device *smmu) 392 374 { 393 375 int i; 394 376 u32 val; ··· 416 398 417 399 smmu_flush_regs(smmu, 1); 418 400 419 - val = ahb_read(smmu, AHB_XBAR_CTRL); 420 - val |= AHB_XBAR_CTRL_SMMU_INIT_DONE_DONE << 421 - AHB_XBAR_CTRL_SMMU_INIT_DONE_SHIFT; 422 - ahb_write(smmu, val, AHB_XBAR_CTRL); 401 + return tegra_ahb_enable_smmu(smmu->ahb); 423 402 } 424 403 425 404 static void flush_ptc_and_tlb(struct smmu_device *smmu, ··· 888 873 { 889 874 struct smmu_device *smmu = dev_get_drvdata(dev); 890 875 unsigned long flags; 876 + int err; 891 877 892 878 spin_lock_irqsave(&smmu->lock, flags); 893 - smmu_setup_regs(smmu); 879 + err = smmu_setup_regs(smmu); 894 880 spin_unlock_irqrestore(&smmu->lock, flags); 895 - return 0; 881 + return err; 896 882 } 897 883 898 884 static int tegra_smmu_probe(struct platform_device *pdev) 899 885 { 900 886 struct smmu_device *smmu; 901 - struct resource *regs, *regs2, *window; 902 887 struct device *dev = &pdev->dev; 903 - int i, err = 0; 888 + int i, asids, err = 0; 889 + dma_addr_t base; 890 + size_t size; 891 + const void *prop; 904 892 905 893 if (smmu_handle) 906 894 return -EIO; 907 895 908 896 BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT); 909 - 910 - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 911 - regs2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); 912 - window = platform_get_resource(pdev, IORESOURCE_MEM, 2); 913 - if (!regs || !regs2 || !window) { 914 - dev_err(dev, "No SMMU resources\n"); 915 - return -ENODEV; 916 - } 917 897 918 898 smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); 919 899 if (!smmu) { ··· 916 906 return -ENOMEM; 917 907 } 918 908 919 - smmu->dev = dev; 920 - smmu->num_as = SMMU_NUM_ASIDS; 921 - smmu->iovmm_base = (unsigned long)window->start; 922 - smmu->page_count = resource_size(window) >> SMMU_PAGE_SHIFT; 923 - smmu->regs = devm_ioremap(dev, regs->start, resource_size(regs)); 924 - smmu->regs_ahbarb = devm_ioremap(dev, regs2->start, 925 - resource_size(regs2)); 926 - if (!smmu->regs || !smmu->regs_ahbarb) { 927 - dev_err(dev, "failed to remap SMMU registers\n"); 928 - err = -ENXIO; 929 - goto fail; 909 + for (i = 0; i < ARRAY_SIZE(smmu->regs); i++) { 910 + struct resource *res; 911 + 912 + res = platform_get_resource(pdev, IORESOURCE_MEM, i); 913 + if (!res) 914 + return -ENODEV; 915 + smmu->regs[i] = devm_request_and_ioremap(&pdev->dev, res); 916 + if (!smmu->regs[i]) 917 + return -EBUSY; 930 918 } 919 + 920 + err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); 921 + if (err) 922 + return -ENODEV; 923 + 924 + if (size & SMMU_PAGE_MASK) 925 + return -EINVAL; 926 + 927 + size >>= SMMU_PAGE_SHIFT; 928 + if (!size) 929 + return -EINVAL; 930 + 931 + prop = of_get_property(dev->of_node, "nvidia,#asids", NULL); 932 + if (!prop) 933 + return -ENODEV; 934 + asids = be32_to_cpup(prop); 935 + if (!asids) 936 + return -ENODEV; 937 + 938 + smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0); 939 + if (!smmu->ahb) 940 + return -ENODEV; 941 + 942 + smmu->dev = dev; 943 + smmu->num_as = asids; 944 + smmu->iovmm_base = base; 945 + smmu->page_count = size; 931 946 932 947 smmu->translation_enable_0 = ~0; 933 948 smmu->translation_enable_1 = ~0; ··· 980 945 INIT_LIST_HEAD(&as->client); 981 946 } 982 947 spin_lock_init(&smmu->lock); 983 - smmu_setup_regs(smmu); 948 + err = smmu_setup_regs(smmu); 949 + if (err) 950 + goto fail; 984 951 platform_set_drvdata(pdev, smmu); 985 952 986 953 smmu->avp_vector_page = alloc_page(GFP_KERNEL); ··· 995 958 fail: 996 959 if (smmu->avp_vector_page) 997 960 __free_page(smmu->avp_vector_page); 998 - if (smmu->regs) 999 - devm_iounmap(dev, smmu->regs); 1000 - if (smmu->regs_ahbarb) 1001 - devm_iounmap(dev, smmu->regs_ahbarb); 1002 961 if (smmu && smmu->as) { 1003 962 for (i = 0; i < smmu->num_as; i++) { 1004 963 if (smmu->as[i].pdir_page) { ··· 1026 993 __free_page(smmu->avp_vector_page); 1027 994 if (smmu->regs) 1028 995 devm_iounmap(dev, smmu->regs); 1029 - if (smmu->regs_ahbarb) 1030 - devm_iounmap(dev, smmu->regs_ahbarb); 1031 996 devm_kfree(dev, smmu); 1032 997 smmu_handle = NULL; 1033 998 return 0; ··· 1036 1005 .resume = tegra_smmu_resume, 1037 1006 }; 1038 1007 1008 + #ifdef CONFIG_OF 1009 + static struct of_device_id tegra_smmu_of_match[] __devinitdata = { 1010 + { .compatible = "nvidia,tegra30-smmu", }, 1011 + { }, 1012 + }; 1013 + MODULE_DEVICE_TABLE(of, tegra_smmu_of_match); 1014 + #endif 1015 + 1039 1016 static struct platform_driver tegra_smmu_driver = { 1040 1017 .probe = tegra_smmu_probe, 1041 1018 .remove = tegra_smmu_remove, ··· 1051 1012 .owner = THIS_MODULE, 1052 1013 .name = "tegra-smmu", 1053 1014 .pm = &tegra_smmu_pm_ops, 1015 + .of_match_table = of_match_ptr(tegra_smmu_of_match), 1054 1016 }, 1055 1017 }; 1056 1018 ··· 1071 1031 1072 1032 MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30"); 1073 1033 MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); 1034 + MODULE_ALIAS("platform:tegra-smmu"); 1074 1035 MODULE_LICENSE("GPL v2");