Merge tag 'tegra-for-4.2-memory' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into next/drivers

Merge "ARM: tegra: Memory controller updates for v4.2-rc1" from Thierry Reding:

Adds support for Tegra132 (which is mostly the same as for Tegra124,
except for cache maintenance). debugfs support is also introduced for
the SMMU part of the memory controller, which allows users to inspect
the translation state for SWGROUPs and memory clients.

* tag 'tegra-for-4.2-memory' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  memory: tegra: Disable ARBITRATION_EMEM interrupt
  memory: tegra: Add Tegra132 support
  iommu/tegra-smmu: Add debugfs support
  memory: tegra: Add SWGROUP names
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 1ae4e54..73f918d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -219,7 +219,7 @@
 	select IOMMU_API
 	help
 	  This driver supports the IOMMU hardware (SMMU) found on NVIDIA Tegra
-	  SoCs (Tegra30 up to Tegra124).
+	  SoCs (Tegra30 up to Tegra132).
 
 config EXYNOS_IOMMU
 	bool "Exynos IOMMU Support"
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index c845d99..c1f2e52 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
 #include <linux/err.h>
 #include <linux/iommu.h>
 #include <linux/kernel.h>
@@ -31,6 +32,8 @@
 	struct mutex lock;
 
 	struct list_head list;
+
+	struct dentry *debugfs;
 };
 
 struct tegra_smmu_as {
@@ -673,6 +676,103 @@
 	}
 }
 
+static int tegra_smmu_swgroups_show(struct seq_file *s, void *data)
+{
+	struct tegra_smmu *smmu = s->private;
+	unsigned int i;
+	u32 value;
+
+	seq_printf(s, "swgroup    enabled  ASID\n");
+	seq_printf(s, "------------------------\n");
+
+	for (i = 0; i < smmu->soc->num_swgroups; i++) {
+		const struct tegra_smmu_swgroup *group = &smmu->soc->swgroups[i];
+		const char *status;
+		unsigned int asid;
+
+		value = smmu_readl(smmu, group->reg);
+
+		if (value & SMMU_ASID_ENABLE)
+			status = "yes";
+		else
+			status = "no";
+
+		asid = value & SMMU_ASID_MASK;
+
+		seq_printf(s, "%-9s  %-7s  %#04x\n", group->name, status,
+			   asid);
+	}
+
+	return 0;
+}
+
+static int tegra_smmu_swgroups_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tegra_smmu_swgroups_show, inode->i_private);
+}
+
+static const struct file_operations tegra_smmu_swgroups_fops = {
+	.open = tegra_smmu_swgroups_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int tegra_smmu_clients_show(struct seq_file *s, void *data)
+{
+	struct tegra_smmu *smmu = s->private;
+	unsigned int i;
+	u32 value;
+
+	seq_printf(s, "client       enabled\n");
+	seq_printf(s, "--------------------\n");
+
+	for (i = 0; i < smmu->soc->num_clients; i++) {
+		const struct tegra_mc_client *client = &smmu->soc->clients[i];
+		const char *status;
+
+		value = smmu_readl(smmu, client->smmu.reg);
+
+		if (value & BIT(client->smmu.bit))
+			status = "yes";
+		else
+			status = "no";
+
+		seq_printf(s, "%-12s %s\n", client->name, status);
+	}
+
+	return 0;
+}
+
+static int tegra_smmu_clients_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, tegra_smmu_clients_show, inode->i_private);
+}
+
+static const struct file_operations tegra_smmu_clients_fops = {
+	.open = tegra_smmu_clients_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void tegra_smmu_debugfs_init(struct tegra_smmu *smmu)
+{
+	smmu->debugfs = debugfs_create_dir("smmu", NULL);
+	if (!smmu->debugfs)
+		return;
+
+	debugfs_create_file("swgroups", S_IRUGO, smmu->debugfs, smmu,
+			    &tegra_smmu_swgroups_fops);
+	debugfs_create_file("clients", S_IRUGO, smmu->debugfs, smmu,
+			    &tegra_smmu_clients_fops);
+}
+
+static void tegra_smmu_debugfs_exit(struct tegra_smmu *smmu)
+{
+	debugfs_remove_recursive(smmu->debugfs);
+}
+
 struct tegra_smmu *tegra_smmu_probe(struct device *dev,
 				    const struct tegra_smmu_soc *soc,
 				    struct tegra_mc *mc)
@@ -743,5 +843,14 @@
 	if (err < 0)
 		return ERR_PTR(err);
 
+	if (IS_ENABLED(CONFIG_DEBUG_FS))
+		tegra_smmu_debugfs_init(smmu);
+
 	return smmu;
 }
+
+void tegra_smmu_remove(struct tegra_smmu *smmu)
+{
+	if (IS_ENABLED(CONFIG_DEBUG_FS))
+		tegra_smmu_debugfs_exit(smmu);
+}
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
index 0d9f497..9d4f431 100644
--- a/drivers/memory/tegra/Makefile
+++ b/drivers/memory/tegra/Makefile
@@ -3,5 +3,6 @@
 tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC)  += tegra30.o
 tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
 tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
+tegra-mc-$(CONFIG_ARCH_TEGRA_132_SOC) += tegra124.o
 
 obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
index fe3c44e..9182364 100644
--- a/drivers/memory/tegra/mc.c
+++ b/drivers/memory/tegra/mc.c
@@ -58,6 +58,9 @@
 #ifdef CONFIG_ARCH_TEGRA_124_SOC
 	{ .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc },
 #endif
+#ifdef CONFIG_ARCH_TEGRA_132_SOC
+	{ .compatible = "nvidia,tegra132-mc", .data = &tegra132_mc_soc },
+#endif
 	{ }
 };
 MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
@@ -273,8 +276,8 @@
 
 	value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
 		MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
-		MC_INT_ARBITRATION_EMEM | MC_INT_SECURITY_VIOLATION |
-		MC_INT_DECERR_EMEM;
+		MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM;
+
 	mc_writel(mc, value, MC_INTMASK);
 
 	return 0;
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
index d5d2114..b7361b0 100644
--- a/drivers/memory/tegra/mc.h
+++ b/drivers/memory/tegra/mc.h
@@ -37,4 +37,8 @@
 extern const struct tegra_mc_soc tegra124_mc_soc;
 #endif
 
+#ifdef CONFIG_ARCH_TEGRA_132_SOC
+extern const struct tegra_mc_soc tegra132_mc_soc;
+#endif
+
 #endif /* MEMORY_TEGRA_MC_H */
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
index 511e9a2..9f57958 100644
--- a/drivers/memory/tegra/tegra114.c
+++ b/drivers/memory/tegra/tegra114.c
@@ -896,22 +896,22 @@
 };
 
 static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
-	{ .swgroup = TEGRA_SWGROUP_DC,        .reg = 0x240 },
-	{ .swgroup = TEGRA_SWGROUP_DCB,       .reg = 0x244 },
-	{ .swgroup = TEGRA_SWGROUP_EPP,       .reg = 0x248 },
-	{ .swgroup = TEGRA_SWGROUP_G2,        .reg = 0x24c },
-	{ .swgroup = TEGRA_SWGROUP_AVPC,      .reg = 0x23c },
-	{ .swgroup = TEGRA_SWGROUP_NV,        .reg = 0x268 },
-	{ .swgroup = TEGRA_SWGROUP_HDA,       .reg = 0x254 },
-	{ .swgroup = TEGRA_SWGROUP_HC,        .reg = 0x250 },
-	{ .swgroup = TEGRA_SWGROUP_MSENC,     .reg = 0x264 },
-	{ .swgroup = TEGRA_SWGROUP_PPCS,      .reg = 0x270 },
-	{ .swgroup = TEGRA_SWGROUP_VDE,       .reg = 0x27c },
-	{ .swgroup = TEGRA_SWGROUP_VI,        .reg = 0x280 },
-	{ .swgroup = TEGRA_SWGROUP_ISP,       .reg = 0x258 },
-	{ .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
-	{ .swgroup = TEGRA_SWGROUP_XUSB_DEV,  .reg = 0x28c },
-	{ .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
+	{ .name = "dc",        .swgroup = TEGRA_SWGROUP_DC,        .reg = 0x240 },
+	{ .name = "dcb",       .swgroup = TEGRA_SWGROUP_DCB,       .reg = 0x244 },
+	{ .name = "epp",       .swgroup = TEGRA_SWGROUP_EPP,       .reg = 0x248 },
+	{ .name = "g2",        .swgroup = TEGRA_SWGROUP_G2,        .reg = 0x24c },
+	{ .name = "avpc",      .swgroup = TEGRA_SWGROUP_AVPC,      .reg = 0x23c },
+	{ .name = "nv",        .swgroup = TEGRA_SWGROUP_NV,        .reg = 0x268 },
+	{ .name = "hda",       .swgroup = TEGRA_SWGROUP_HDA,       .reg = 0x254 },
+	{ .name = "hc",        .swgroup = TEGRA_SWGROUP_HC,        .reg = 0x250 },
+	{ .name = "msenc",     .swgroup = TEGRA_SWGROUP_MSENC,     .reg = 0x264 },
+	{ .name = "ppcs",      .swgroup = TEGRA_SWGROUP_PPCS,      .reg = 0x270 },
+	{ .name = "vde",       .swgroup = TEGRA_SWGROUP_VDE,       .reg = 0x27c },
+	{ .name = "vi",        .swgroup = TEGRA_SWGROUP_VI,        .reg = 0x280 },
+	{ .name = "isp",       .swgroup = TEGRA_SWGROUP_ISP,       .reg = 0x258 },
+	{ .name = "xusb_host", .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
+	{ .name = "xusb_dev",  .swgroup = TEGRA_SWGROUP_XUSB_DEV,  .reg = 0x28c },
+	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
 };
 
 static void tegra114_flush_dcache(struct page *page, unsigned long offset,
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
index 278d40b..b996dfb 100644
--- a/drivers/memory/tegra/tegra124.c
+++ b/drivers/memory/tegra/tegra124.c
@@ -934,29 +934,29 @@
 };
 
 static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
-	{ .swgroup = TEGRA_SWGROUP_DC,        .reg = 0x240 },
-	{ .swgroup = TEGRA_SWGROUP_DCB,       .reg = 0x244 },
-	{ .swgroup = TEGRA_SWGROUP_AFI,       .reg = 0x238 },
-	{ .swgroup = TEGRA_SWGROUP_AVPC,      .reg = 0x23c },
-	{ .swgroup = TEGRA_SWGROUP_HDA,       .reg = 0x254 },
-	{ .swgroup = TEGRA_SWGROUP_HC,        .reg = 0x250 },
-	{ .swgroup = TEGRA_SWGROUP_MSENC,     .reg = 0x264 },
-	{ .swgroup = TEGRA_SWGROUP_PPCS,      .reg = 0x270 },
-	{ .swgroup = TEGRA_SWGROUP_SATA,      .reg = 0x274 },
-	{ .swgroup = TEGRA_SWGROUP_VDE,       .reg = 0x27c },
-	{ .swgroup = TEGRA_SWGROUP_ISP2,      .reg = 0x258 },
-	{ .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
-	{ .swgroup = TEGRA_SWGROUP_XUSB_DEV,  .reg = 0x28c },
-	{ .swgroup = TEGRA_SWGROUP_ISP2B,     .reg = 0xaa4 },
-	{ .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
-	{ .swgroup = TEGRA_SWGROUP_A9AVP,     .reg = 0x290 },
-	{ .swgroup = TEGRA_SWGROUP_GPU,       .reg = 0xaac },
-	{ .swgroup = TEGRA_SWGROUP_SDMMC1A,   .reg = 0xa94 },
-	{ .swgroup = TEGRA_SWGROUP_SDMMC2A,   .reg = 0xa98 },
-	{ .swgroup = TEGRA_SWGROUP_SDMMC3A,   .reg = 0xa9c },
-	{ .swgroup = TEGRA_SWGROUP_SDMMC4A,   .reg = 0xaa0 },
-	{ .swgroup = TEGRA_SWGROUP_VIC,       .reg = 0x284 },
-	{ .swgroup = TEGRA_SWGROUP_VI,        .reg = 0x280 },
+	{ .name = "dc",        .swgroup = TEGRA_SWGROUP_DC,        .reg = 0x240 },
+	{ .name = "dcb",       .swgroup = TEGRA_SWGROUP_DCB,       .reg = 0x244 },
+	{ .name = "afi",       .swgroup = TEGRA_SWGROUP_AFI,       .reg = 0x238 },
+	{ .name = "avpc",      .swgroup = TEGRA_SWGROUP_AVPC,      .reg = 0x23c },
+	{ .name = "hda",       .swgroup = TEGRA_SWGROUP_HDA,       .reg = 0x254 },
+	{ .name = "hc",        .swgroup = TEGRA_SWGROUP_HC,        .reg = 0x250 },
+	{ .name = "msenc",     .swgroup = TEGRA_SWGROUP_MSENC,     .reg = 0x264 },
+	{ .name = "ppcs",      .swgroup = TEGRA_SWGROUP_PPCS,      .reg = 0x270 },
+	{ .name = "sata",      .swgroup = TEGRA_SWGROUP_SATA,      .reg = 0x274 },
+	{ .name = "vde",       .swgroup = TEGRA_SWGROUP_VDE,       .reg = 0x27c },
+	{ .name = "isp2",      .swgroup = TEGRA_SWGROUP_ISP2,      .reg = 0x258 },
+	{ .name = "xusb_host", .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
+	{ .name = "xusb_dev",  .swgroup = TEGRA_SWGROUP_XUSB_DEV,  .reg = 0x28c },
+	{ .name = "isp2b",     .swgroup = TEGRA_SWGROUP_ISP2B,     .reg = 0xaa4 },
+	{ .name = "tsec",      .swgroup = TEGRA_SWGROUP_TSEC,      .reg = 0x294 },
+	{ .name = "a9avp",     .swgroup = TEGRA_SWGROUP_A9AVP,     .reg = 0x290 },
+	{ .name = "gpu",       .swgroup = TEGRA_SWGROUP_GPU,       .reg = 0xaac },
+	{ .name = "sdmmc1a",   .swgroup = TEGRA_SWGROUP_SDMMC1A,   .reg = 0xa94 },
+	{ .name = "sdmmc2a",   .swgroup = TEGRA_SWGROUP_SDMMC2A,   .reg = 0xa98 },
+	{ .name = "sdmmc3a",   .swgroup = TEGRA_SWGROUP_SDMMC3A,   .reg = 0xa9c },
+	{ .name = "sdmmc4a",   .swgroup = TEGRA_SWGROUP_SDMMC4A,   .reg = 0xaa0 },
+	{ .name = "vic",       .swgroup = TEGRA_SWGROUP_VIC,       .reg = 0x284 },
+	{ .name = "vi",        .swgroup = TEGRA_SWGROUP_VI,        .reg = 0x280 },
 };
 
 #ifdef CONFIG_ARCH_TEGRA_124_SOC
@@ -993,3 +993,36 @@
 	.smmu = &tegra124_smmu_soc,
 };
 #endif /* CONFIG_ARCH_TEGRA_124_SOC */
+
+#ifdef CONFIG_ARCH_TEGRA_132_SOC
+static void tegra132_flush_dcache(struct page *page, unsigned long offset,
+				  size_t size)
+{
+	void *virt = page_address(page) + offset;
+
+	__flush_dcache_area(virt, size);
+}
+
+static const struct tegra_smmu_ops tegra132_smmu_ops = {
+	.flush_dcache = tegra132_flush_dcache,
+};
+
+static const struct tegra_smmu_soc tegra132_smmu_soc = {
+	.clients = tegra124_mc_clients,
+	.num_clients = ARRAY_SIZE(tegra124_mc_clients),
+	.swgroups = tegra124_swgroups,
+	.num_swgroups = ARRAY_SIZE(tegra124_swgroups),
+	.supports_round_robin_arbitration = true,
+	.supports_request_limit = true,
+	.num_asids = 128,
+	.ops = &tegra132_smmu_ops,
+};
+
+const struct tegra_mc_soc tegra132_mc_soc = {
+	.clients = tegra124_mc_clients,
+	.num_clients = ARRAY_SIZE(tegra124_mc_clients),
+	.num_address_bits = 34,
+	.atom_size = 32,
+	.smmu = &tegra132_smmu_soc,
+};
+#endif /* CONFIG_ARCH_TEGRA_132_SOC */
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
index 71fe937..1abcd8f 100644
--- a/drivers/memory/tegra/tegra30.c
+++ b/drivers/memory/tegra/tegra30.c
@@ -918,22 +918,22 @@
 };
 
 static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
-	{ .swgroup = TEGRA_SWGROUP_DC,   .reg = 0x240 },
-	{ .swgroup = TEGRA_SWGROUP_DCB,  .reg = 0x244 },
-	{ .swgroup = TEGRA_SWGROUP_EPP,  .reg = 0x248 },
-	{ .swgroup = TEGRA_SWGROUP_G2,   .reg = 0x24c },
-	{ .swgroup = TEGRA_SWGROUP_MPE,  .reg = 0x264 },
-	{ .swgroup = TEGRA_SWGROUP_VI,   .reg = 0x280 },
-	{ .swgroup = TEGRA_SWGROUP_AFI,  .reg = 0x238 },
-	{ .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
-	{ .swgroup = TEGRA_SWGROUP_NV,   .reg = 0x268 },
-	{ .swgroup = TEGRA_SWGROUP_NV2,  .reg = 0x26c },
-	{ .swgroup = TEGRA_SWGROUP_HDA,  .reg = 0x254 },
-	{ .swgroup = TEGRA_SWGROUP_HC,   .reg = 0x250 },
-	{ .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
-	{ .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 },
-	{ .swgroup = TEGRA_SWGROUP_VDE,  .reg = 0x27c },
-	{ .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
+	{ .name = "dc",   .swgroup = TEGRA_SWGROUP_DC,   .reg = 0x240 },
+	{ .name = "dcb",  .swgroup = TEGRA_SWGROUP_DCB,  .reg = 0x244 },
+	{ .name = "epp",  .swgroup = TEGRA_SWGROUP_EPP,  .reg = 0x248 },
+	{ .name = "g2",   .swgroup = TEGRA_SWGROUP_G2,   .reg = 0x24c },
+	{ .name = "mpe",  .swgroup = TEGRA_SWGROUP_MPE,  .reg = 0x264 },
+	{ .name = "vi",   .swgroup = TEGRA_SWGROUP_VI,   .reg = 0x280 },
+	{ .name = "afi",  .swgroup = TEGRA_SWGROUP_AFI,  .reg = 0x238 },
+	{ .name = "avpc", .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
+	{ .name = "nv",   .swgroup = TEGRA_SWGROUP_NV,   .reg = 0x268 },
+	{ .name = "nv2",  .swgroup = TEGRA_SWGROUP_NV2,  .reg = 0x26c },
+	{ .name = "hda",  .swgroup = TEGRA_SWGROUP_HDA,  .reg = 0x254 },
+	{ .name = "hc",   .swgroup = TEGRA_SWGROUP_HC,   .reg = 0x250 },
+	{ .name = "ppcs", .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
+	{ .name = "sata", .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 },
+	{ .name = "vde",  .swgroup = TEGRA_SWGROUP_VDE,  .reg = 0x27c },
+	{ .name = "isp",  .swgroup = TEGRA_SWGROUP_ISP,  .reg = 0x258 },
 };
 
 static void tegra30_flush_dcache(struct page *page, unsigned long offset,
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
index 63deb8d..e5ba518 100644
--- a/include/soc/tegra/mc.h
+++ b/include/soc/tegra/mc.h
@@ -40,6 +40,7 @@
 };
 
 struct tegra_smmu_swgroup {
+	const char *name;
 	unsigned int swgroup;
 	unsigned int reg;
 };
@@ -71,6 +72,7 @@
 struct tegra_smmu *tegra_smmu_probe(struct device *dev,
 				    const struct tegra_smmu_soc *soc,
 				    struct tegra_mc *mc);
+void tegra_smmu_remove(struct tegra_smmu *smmu);
 #else
 static inline struct tegra_smmu *
 tegra_smmu_probe(struct device *dev, const struct tegra_smmu_soc *soc,
@@ -78,6 +80,10 @@
 {
 	return NULL;
 }
+
+static inline void tegra_smmu_remove(struct tegra_smmu *smmu)
+{
+}
 #endif
 
 struct tegra_mc_soc {