From: Simon <xxm@rock-chips.com>
Date: Mon, 23 Nov 2015 12:21:14 +0000 (+0800)
Subject: iommu/rk: support kernel version 4.4
X-Git-Tag: firefly_0821_release~3586
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=59d4ed13c7e29022cf1ea993ad4882158f6c8028;p=firefly-linux-kernel-4.4.55.git

iommu/rk: support kernel version 4.4

Change-Id: I430577668f50284c1b318636ea5e1009b5e90ca5
Signed-off-by: Simon <xxm@rock-chips.com>
---

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index b9094e9da537..8d5dde499aa3 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -221,6 +221,35 @@ config ROCKCHIP_IOMMU
 	  Say Y here if you are using a Rockchip SoC that includes an IOMMU
 	  device.
 
+config RK_IOMMU
+	bool "RK IOMMU Support"
+	depends on ARCH_ROCKCHIP || COMPILE_TEST
+	select IOMMU_API
+	help
+	  Support for IOMMUs found on Rockchip rk32xx,rk313x,rk33xx SOCs.
+	  These IOMMUs allow virtualization of the address space used by most
+	  cores within the multimedia subsystem.
+	  Say Y here if you are using a Rockchip SoC that includes an IOMMU
+	  device.
+
+config RK_IOVMM
+	bool "IO Virtual Memory Manager for RK IOMMUs"
+	select GENERIC_ALLOCATOR
+	depends on RK_IOMMU
+	help
+	  Supporting the users of Rockchip IOMMU for allocating and mapping
+	  an IO virtual memory region with a physical memory region
+	  and managing the allocated virtual memory regions.
+
+config RK_IOMMU_DEBUG
+	bool "Debugging log for RK IOMMU"
+	depends on RK_IOMMU
+	help
+	  Select this to see the detailed log message that shows what
+	  happens in the IOMMU driver
+
+	  Say N unless you need kernel log message for IOMMU debugging
+
 config TEGRA_IOMMU_GART
 	bool "Tegra GART IOMMU Support"
 	depends on ARCH_TEGRA_2x_SOC
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 68faca02225d..99c659d7c6d9 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -19,6 +19,8 @@ obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
+obj-$(CONFIG_RK_IOMMU) += rk-iommu.o
+obj-$(CONFIG_RK_IOVMM) += rk-iovmm.o
 obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
 obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
diff --git a/drivers/iommu/rk-iommu.c b/drivers/iommu/rk-iommu.c
index db5a66d11a38..b3bb9f38b313 100644
--- a/drivers/iommu/rk-iommu.c
+++ b/drivers/iommu/rk-iommu.c
@@ -27,7 +27,7 @@
 #include <linux/rockchip/cpu.h>
 #include <linux/rockchip/iomap.h>
 #include <linux/device.h>
-#include "rockchip-iommu.h"
+#include "rk-iommu.h"
 
 /* We does not consider super section mapping (16MB) */
 #define SPAGE_ORDER 12
@@ -187,8 +187,14 @@ struct rk_iommu_domain {
 	short *lv2entcnt; /* free lv2 entry counter for each section */
 	spinlock_t lock; /* lock for this structure */
 	spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
+	struct iommu_domain domain;
 };
 
+static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
+{
+	return container_of(dom, struct rk_iommu_domain, domain);
+}
+
 static bool rockchip_set_iommu_active(struct iommu_drvdata *data)
 {
 	/* return true if the IOMMU was not active previously
@@ -594,7 +600,7 @@ static irqreturn_t rockchip_iommu_irq(int irq, void *dev_id)
 				report_iommu_fault(data->domain, data->iommu,
 						   fault_address, flags);
 			if (data->fault_handler)
-				data->fault_handler(data->iommu, IOMMU_PAGEFAULT, dte, fault_address, 1);
+				data->fault_handler(data->master, IOMMU_PAGEFAULT, dte, fault_address, 1);
 
 			rockchip_iommu_page_fault_done(data->res_bases[i],
 					               data->dbgname);
@@ -821,7 +827,7 @@ int rockchip_iommu_tlb_invalidate(struct device *dev)
 static phys_addr_t rockchip_iommu_iova_to_phys(struct iommu_domain *domain,
 					       dma_addr_t iova)
 {
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	unsigned int *entry;
 	unsigned long flags;
 	phys_addr_t phys = 0;
@@ -872,7 +878,7 @@ static unsigned int *rockchip_alloc_lv2entry(unsigned int *sent,
 static size_t rockchip_iommu_unmap(struct iommu_domain *domain,
 				   unsigned long iova, size_t size)
 {
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	unsigned long flags;
 	unsigned int *ent;
 
@@ -913,7 +919,7 @@ done:
 static int rockchip_iommu_map(struct iommu_domain *domain, unsigned long iova,
 			      phys_addr_t paddr, size_t size, int prot)
 {
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	unsigned int *entry;
 	unsigned long flags;
 	int ret = -ENOMEM;
@@ -945,7 +951,7 @@ static int rockchip_iommu_map(struct iommu_domain *domain, unsigned long iova,
 static void rockchip_iommu_detach_device(struct iommu_domain *domain, struct device *dev)
 {
 	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	struct list_head *pos;
 	unsigned long flags;
 	bool found = false;
@@ -981,7 +987,7 @@ static void rockchip_iommu_detach_device(struct iommu_domain *domain, struct dev
 static int rockchip_iommu_attach_device(struct iommu_domain *domain, struct device *dev)
 {
 	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	unsigned long flags;
 	int ret;
 
@@ -994,6 +1000,7 @@ static int rockchip_iommu_attach_device(struct iommu_domain *domain, struct devi
 		BUG_ON(!list_empty(&data->node));
 		list_add_tail(&data->node, &priv->clients);
 		data->domain = domain;
+		data->master = dev;
 	}
 
 	spin_unlock_irqrestore(&priv->lock, flags);
@@ -1005,7 +1012,9 @@ static int rockchip_iommu_attach_device(struct iommu_domain *domain, struct devi
 		dev_dbg(dev->archdata.iommu,"%s: IOMMU with pgtable 0x%x already attached\n",
 			__func__, (unsigned int)virt_to_phys(priv->pgtable));
 	} else {
-		if (!(strstr(data->dbgname, "vpu") || strstr(data->dbgname, "hevc")))
+		if (!(strstr(data->dbgname, "vpu") ||
+		      strstr(data->dbgname, "hevc") ||
+		      strstr(data->dbgname, "vdec")))
 			dev_info(dev->archdata.iommu,"%s: Attached new IOMMU with pgtable 0x%x\n",
 				__func__, (unsigned int)virt_to_phys(priv->pgtable));
 	}
@@ -1013,9 +1022,9 @@ static int rockchip_iommu_attach_device(struct iommu_domain *domain, struct devi
 	return ret;
 }
 
-static void rockchip_iommu_domain_destroy(struct iommu_domain *domain)
+static void rockchip_iommu_domain_free(struct iommu_domain *domain)
 {
-	struct rk_iommu_domain *priv = domain->priv;
+	struct rk_iommu_domain *priv = to_rk_domain(domain);
 	int i;
 
 	WARN_ON(!list_empty(&priv->clients));
@@ -1027,17 +1036,19 @@ static void rockchip_iommu_domain_destroy(struct iommu_domain *domain)
 
 	free_pages((unsigned long)priv->pgtable, 0);
 	free_pages((unsigned long)priv->lv2entcnt, 0);
-	kfree(domain->priv);
-	domain->priv = NULL;
+	kfree(priv);
 }
 
-static int rockchip_iommu_domain_init(struct iommu_domain *domain)
+static struct iommu_domain *rockchip_iommu_domain_alloc(unsigned type)
 {
 	struct rk_iommu_domain *priv;
 
+	if (type != IOMMU_DOMAIN_UNMANAGED)
+		return NULL;
+
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
-		return -ENOMEM;
+		return NULL;
 
 /*rk32xx iommu use 2 level pagetable,
    level1 and leve2 both have 1024 entries,each entry  occupy 4 bytes,
@@ -1059,19 +1070,18 @@ static int rockchip_iommu_domain_init(struct iommu_domain *domain)
 	spin_lock_init(&priv->pgtablelock);
 	INIT_LIST_HEAD(&priv->clients);
 
-	domain->priv = priv;
-	return 0;
+	return &priv->domain;
 
 err_counter:
 	free_pages((unsigned long)priv->pgtable, 0);
 err_pgtable:
 	kfree(priv);
-	return -ENOMEM;
+	return NULL;
 }
 
 static struct iommu_ops rk_iommu_ops = {
-	.domain_init = rockchip_iommu_domain_init,
-	.domain_destroy = rockchip_iommu_domain_destroy,
+	.domain_alloc = rockchip_iommu_domain_alloc,
+	.domain_free = rockchip_iommu_domain_free,
 	.attach_dev = rockchip_iommu_attach_device,
 	.detach_dev = rockchip_iommu_detach_device,
 	.map = rockchip_iommu_map,
@@ -1214,6 +1224,7 @@ static const struct of_device_id iommu_dt_ids[] = {
 	{ .compatible = VPU_IOMMU_COMPATIBLE_NAME},
 	{ .compatible = ISP_IOMMU_COMPATIBLE_NAME},
 	{ .compatible = VOP_IOMMU_COMPATIBLE_NAME},
+	{ .compatible = VDEC_IOMMU_COMPATIBLE_NAME},
 	{ /* end */ }
 };
 
diff --git a/drivers/iommu/rk-iommu.h b/drivers/iommu/rk-iommu.h
new file mode 100644
index 000000000000..80e6f6fb3e39
--- /dev/null
+++ b/drivers/iommu/rk-iommu.h
@@ -0,0 +1,98 @@
+/*
+ * Data structure definition for Rockchip IOMMU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_PLAT_IOMMU_H
+#define __ASM_PLAT_IOMMU_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/genalloc.h>
+#include <linux/iommu.h>
+
+#include <linux/rockchip-iovmm.h>
+
+
+struct rk_iovmm {
+	struct iommu_domain *domain; /* iommu domain for this iovmm */
+	struct gen_pool *vmm_pool;
+	struct list_head regions_list;	/* list of rk_vm_region */
+	spinlock_t lock; /* lock for updating regions_list */
+};
+
+struct iommu_drvdata {
+	struct list_head node; /* entry of rk_iommu_domain.clients */
+	struct device *iommu;	/*  IOMMU's device descriptor */
+	struct device *master; /* IOMMU's master device descriptor */
+	int num_res_mem;
+	int num_res_irq;
+	const char *dbgname;
+	void __iomem **res_bases;
+	int activations;
+	spinlock_t data_lock;
+	struct iommu_domain *domain; /* domain given to iommu_attach_device() */
+	unsigned int pgtable;
+	struct rk_iovmm vmm;
+	rockchip_iommu_fault_handler_t fault_handler;
+};
+
+#ifdef CONFIG_RK_IOVMM
+
+#define IOVA_START 0x10000000
+#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */
+
+struct rk_vm_region {
+	struct list_head node;
+	unsigned int start;
+	unsigned int size;
+};
+
+static inline struct rk_iovmm *rockchip_get_iovmm(struct device *dev)
+{
+	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+
+	BUG_ON(!dev->archdata.iommu || !data);
+
+	return &data->vmm;
+}
+
+int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm);
+#else
+static inline int rockchip_init_iovmm(struct device *iommu,
+				struct rk_iovmm *vmm)
+{
+	return -ENOSYS;
+}
+#endif
+
+
+#ifdef CONFIG_RK_IOMMU
+
+/**
+ * rockchip_iommu_tlb_invalidate() - flush all TLB entry in iommu
+ * @owner: The device whose IOMMU.
+ *
+ * This function flush all TLB entry in iommu
+ */
+int rockchip_iommu_tlb_invalidate(struct device *owner);
+int rockchip_iommu_tlb_invalidate_global(struct device *owner);
+
+#else /* CONFIG_RK_IOMMU */
+static inline int rockchip_iommu_tlb_invalidate(struct device *owner)
+{
+	return -1;
+}
+static int rockchip_iommu_tlb_invalidate_global(struct device *owner)
+{
+	return -1;
+}
+
+#endif
+
+#endif	/*__ASM_PLAT_IOMMU_H*/
diff --git a/drivers/iommu/rk-iovmm.c b/drivers/iommu/rk-iovmm.c
new file mode 100644
index 000000000000..e071e8653dcb
--- /dev/null
+++ b/drivers/iommu/rk-iovmm.c
@@ -0,0 +1,323 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifdef CONFIG_ROCKCHIP_IOMMU_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/hardirq.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/err.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include "rk-iommu.h"
+
+#define IOMMU_REGION_GUARD		(2<<PAGE_SHIFT)
+
+static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
+{
+	struct rk_vm_region *region;
+
+	list_for_each_entry(region, &vmm->regions_list, node)
+		if (region->start == iova)
+			return region;
+
+	return NULL;
+}
+
+int rockchip_iovmm_invalidate_tlb(struct device *dev)
+{
+	int ret = rockchip_iommu_tlb_invalidate_global(dev);
+
+	return ret;
+}
+
+void rockchip_iovmm_set_fault_handler(struct device *dev,
+				       rockchip_iommu_fault_handler_t handler)
+{
+	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
+
+	data->fault_handler = handler;
+}
+
+int rockchip_iovmm_activate(struct device *dev)
+{
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+
+	return iommu_attach_device(vmm->domain, dev);
+}
+
+void rockchip_iovmm_deactivate(struct device *dev)
+{
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+
+	iommu_detach_device(vmm->domain, dev);
+}
+
+dma_addr_t rockchip_iovmm_map(struct device *dev,
+	struct scatterlist *sg, off_t offset, size_t size)
+{
+	off_t start_off;
+	dma_addr_t addr, start = 0;
+	size_t mapped_size = 0;
+	struct rk_vm_region *region;
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+	int order;
+	int ret;
+
+	for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
+		offset -= sg_dma_len(sg);
+
+	start_off = offset_in_page(sg_phys(sg) + offset);
+	size = PAGE_ALIGN(size + start_off);
+
+	order = __fls(min_t(size_t, size, SZ_1M));
+
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region) {
+		ret = -ENOMEM;
+		goto err_map_nomem;
+	}
+
+	start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool,
+					   size+IOMMU_REGION_GUARD);
+	if (!start) {
+		ret = -ENOMEM;
+		goto err_map_noiomem;
+	}
+
+	pr_debug("%s: size = %zx\n", __func__, size);
+
+	addr = start;
+	do {
+		phys_addr_t phys;
+		size_t len;
+
+		phys = sg_phys(sg);
+		len = sg_dma_len(sg);
+
+		/* if back to back sg entries are contiguous consolidate them */
+		while (sg_next(sg) && sg_phys(sg) +
+		       sg_dma_len(sg) == sg_phys(sg_next(sg))) {
+			len += sg_dma_len(sg_next(sg));
+			sg = sg_next(sg);
+		}
+
+		if (offset > 0) {
+			len -= offset;
+			phys += offset;
+			offset = 0;
+		}
+
+		if (offset_in_page(phys)) {
+			len += offset_in_page(phys);
+			phys = round_down(phys, PAGE_SIZE);
+		}
+
+		len = PAGE_ALIGN(len);
+
+		if (len > (size - mapped_size))
+			len = size - mapped_size;
+		pr_debug("addr = %pad, phys = %pa, len = %zx\n", &addr, &phys, len);
+		ret = iommu_map(vmm->domain, addr, phys, len, 0);
+		if (ret)
+			break;
+
+		addr += len;
+		mapped_size += len;
+	} while ((sg = sg_next(sg)) && (mapped_size < size));
+
+	BUG_ON(mapped_size > size);
+
+	if (mapped_size < size)
+		goto err_map_map;
+
+	region->start = start + start_off;
+	region->size = size;
+
+	INIT_LIST_HEAD(&region->node);
+
+	spin_lock(&vmm->lock);
+
+	list_add(&region->node, &vmm->regions_list);
+
+	spin_unlock(&vmm->lock);
+
+	ret = rockchip_iommu_tlb_invalidate(dev);
+	if (ret) {
+		spin_lock(&vmm->lock);
+		list_del(&region->node);
+		spin_unlock(&vmm->lock);
+		goto err_map_map;
+	}
+	dev_dbg(dev->archdata.iommu, "IOVMM: Allocated VM region @ %p/%#X bytes.\n",
+	&region->start, region->size);
+
+	return region->start;
+
+err_map_map:
+	iommu_unmap(vmm->domain, start, mapped_size);
+	gen_pool_free(vmm->vmm_pool, start, size);
+err_map_noiomem:
+	kfree(region);
+err_map_nomem:
+	dev_err(dev->archdata.iommu, "IOVMM: Failed to allocated VM region for %zx bytes.\n", size);
+	return (dma_addr_t)ret;
+}
+
+void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova)
+{
+	struct rk_vm_region *region;
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+	size_t unmapped_size;
+
+	/* This function must not be called in IRQ handlers */
+	BUG_ON(in_irq());
+
+	spin_lock(&vmm->lock);
+
+	region = find_region(vmm, iova);
+	if (WARN_ON(!region)) {
+		spin_unlock(&vmm->lock);
+		return;
+	}
+
+	list_del(&region->node);
+
+	spin_unlock(&vmm->lock);
+
+	region->start = round_down(region->start, PAGE_SIZE);
+
+	unmapped_size = iommu_unmap(vmm->domain,
+				    region->start, region->size);
+	/*
+	rockchip_iommu_tlb_invalidate(dev);
+	*/
+	gen_pool_free(vmm->vmm_pool, region->start,
+		      region->size+IOMMU_REGION_GUARD);
+
+	WARN_ON(unmapped_size != region->size);
+
+	dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
+		unmapped_size, &region->start);
+
+	kfree(region);
+}
+
+int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
+{
+	struct rk_vm_region *region;
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+	int ret;
+
+	if (WARN_ON((phys + size) >= IOVA_START)) {
+		dev_err(dev->archdata.iommu, "Unable to create one to one mapping for %zx @ %pa\n",
+		       size, &phys);
+		return -EINVAL;
+	}
+
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+	if (!region)
+		return -ENOMEM;
+
+	if (WARN_ON(phys & ~PAGE_MASK))
+		phys = round_down(phys, PAGE_SIZE);
+
+
+	ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
+	if (ret < 0) {
+		kfree(region);
+		return ret;
+	}
+
+	region->start = (dma_addr_t)phys;
+	region->size = size;
+	INIT_LIST_HEAD(&region->node);
+
+	spin_lock(&vmm->lock);
+
+	list_add(&region->node, &vmm->regions_list);
+
+	spin_unlock(&vmm->lock);
+
+	ret = rockchip_iommu_tlb_invalidate(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
+{
+	struct rk_vm_region *region;
+	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
+	size_t unmapped_size;
+
+	/* This function must not be called in IRQ handlers */
+	BUG_ON(in_irq());
+
+	if (WARN_ON(phys & ~PAGE_MASK))
+		phys = round_down(phys, PAGE_SIZE);
+
+	spin_lock(&vmm->lock);
+
+	region = find_region(vmm, (dma_addr_t)phys);
+	if (WARN_ON(!region)) {
+		spin_unlock(&vmm->lock);
+		return;
+	}
+
+	list_del(&region->node);
+
+	spin_unlock(&vmm->lock);
+
+	unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
+	WARN_ON(unmapped_size != region->size);
+	dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
+	       unmapped_size, &region->start);
+
+	kfree(region);
+}
+
+int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm)
+{
+	int ret = 0;
+
+	vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
+	if (!vmm->vmm_pool) {
+		ret = -ENOMEM;
+		goto err_setup_genalloc;
+	}
+
+	/* (1GB - 4KB) addr space from 0x10000000 */
+	ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
+	if (ret)
+		goto err_setup_domain;
+
+	vmm->domain = iommu_domain_alloc(&platform_bus_type);
+	if (!vmm->domain) {
+		ret = -ENOMEM;
+		goto err_setup_domain;
+	}
+
+	spin_lock_init(&vmm->lock);
+
+	INIT_LIST_HEAD(&vmm->regions_list);
+
+	dev_info(iommu, "IOVMM: Created %#x B IOVMM from %#x.\n",
+		IOVM_SIZE, IOVA_START);
+	return 0;
+err_setup_domain:
+	gen_pool_destroy(vmm->vmm_pool);
+err_setup_genalloc:
+	dev_err(iommu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
+
+	return ret;
+}
diff --git a/drivers/iommu/rockchip-iommu.h b/drivers/iommu/rockchip-iommu.h
deleted file mode 100644
index 46b2e8ee4f23..000000000000
--- a/drivers/iommu/rockchip-iommu.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Data structure definition for Rockchip IOMMU driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_PLAT_IOMMU_H
-#define __ASM_PLAT_IOMMU_H
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/genalloc.h>
-#include <linux/iommu.h>
-
-#include <linux/rockchip-iovmm.h>
-
-
-struct rk_iovmm {
-	struct iommu_domain *domain; /* iommu domain for this iovmm */
-	struct gen_pool *vmm_pool;
-	struct list_head regions_list;	/* list of rk_vm_region */
-	spinlock_t lock; /* lock for updating regions_list */
-};
-
-struct iommu_drvdata {
-	struct list_head node; /* entry of rk_iommu_domain.clients */
-	struct device *iommu;	/*  IOMMU's device descriptor */
-	int num_res_mem;
-	int num_res_irq;
-	const char *dbgname;
-	void __iomem **res_bases;
-	int activations;
-	spinlock_t data_lock;
-	struct iommu_domain *domain; /* domain given to iommu_attach_device() */
-	unsigned int pgtable;
-	struct rk_iovmm vmm;
-	rockchip_iommu_fault_handler_t fault_handler;
-};
-
-#ifdef CONFIG_ROCKCHIP_IOVMM
-
-#define IOVA_START 0x10000000
-#define IOVM_SIZE (SZ_1G - SZ_4K) /* last 4K is for error values */
-
-struct rk_vm_region {
-	struct list_head node;
-	unsigned int start;
-	unsigned int size;
-};
-
-static inline struct rk_iovmm *rockchip_get_iovmm(struct device *dev)
-{
-	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-
-	BUG_ON(!dev->archdata.iommu || !data);
-
-	return &data->vmm;
-}
-
-int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm);
-#else
-static inline int rockchip_init_iovmm(struct device *iommu,
-				struct rk_iovmm *vmm)
-{
-	return -ENOSYS;
-}
-#endif
-
-
-#ifdef CONFIG_ROCKCHIP_IOMMU
-
-/**
- * rockchip_iommu_tlb_invalidate() - flush all TLB entry in iommu
- * @owner: The device whose IOMMU.
- *
- * This function flush all TLB entry in iommu
- */
-int rockchip_iommu_tlb_invalidate(struct device *owner);
-int rockchip_iommu_tlb_invalidate_global(struct device *owner);
-
-#else /* CONFIG_ROCKCHIP_IOMMU */
-static inline int rockchip_iommu_tlb_invalidate(struct device *owner)
-{
-	return -1;
-}
-static int rockchip_iommu_tlb_invalidate_global(struct device *owner)
-{
-	return -1;
-}
-
-#endif
-
-#endif	/*__ASM_PLAT_IOMMU_H*/
diff --git a/drivers/iommu/rockchip-iovmm.c b/drivers/iommu/rockchip-iovmm.c
deleted file mode 100644
index 29f885fc0275..000000000000
--- a/drivers/iommu/rockchip-iovmm.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifdef CONFIG_ROCKCHIP_IOMMU_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/kernel.h>
-#include <linux/hardirq.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include <linux/err.h>
-
-#include <linux/of.h>
-#include <linux/of_platform.h>
-
-#include "rockchip-iommu.h"
-
-#define IOMMU_REGION_GUARD		(2<<PAGE_SHIFT)
-
-static struct rk_vm_region *find_region(struct rk_iovmm *vmm, dma_addr_t iova)
-{
-	struct rk_vm_region *region;
-
-	list_for_each_entry(region, &vmm->regions_list, node)
-		if (region->start == iova)
-			return region;
-
-	return NULL;
-}
-
-int rockchip_iovmm_invalidate_tlb(struct device *dev)
-{
-	int ret = rockchip_iommu_tlb_invalidate_global(dev);
-
-	return ret;
-}
-
-void rockchip_iovmm_set_fault_handler(struct device *dev,
-				       rockchip_iommu_fault_handler_t handler)
-{
-	struct iommu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-
-	data->fault_handler = handler;
-}
-
-int rockchip_iovmm_activate(struct device *dev)
-{
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-
-	return iommu_attach_device(vmm->domain, dev);
-}
-
-void rockchip_iovmm_deactivate(struct device *dev)
-{
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-
-	iommu_detach_device(vmm->domain, dev);
-}
-
-dma_addr_t rockchip_iovmm_map(struct device *dev,
-	struct scatterlist *sg, off_t offset, size_t size)
-{
-	off_t start_off;
-	dma_addr_t addr, start = 0;
-	size_t mapped_size = 0;
-	struct rk_vm_region *region;
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-	int order;
-	int ret;
-	
-	for (; sg_dma_len(sg) < offset; sg = sg_next(sg))
-		offset -= sg_dma_len(sg);
-
-	start_off = offset_in_page(sg_phys(sg) + offset);
-	size = PAGE_ALIGN(size + start_off);
-
-	order = __fls(min_t(size_t, size, SZ_1M));
-
-	region = kmalloc(sizeof(*region), GFP_KERNEL);
-	if (!region) {
-		ret = -ENOMEM;
-		goto err_map_nomem;
-	}
-
-	start = (dma_addr_t)gen_pool_alloc(vmm->vmm_pool,
-					   size+IOMMU_REGION_GUARD);
-	if (!start) {
-		ret = -ENOMEM;
-		goto err_map_noiomem;
-	}
-
-	pr_debug("%s: size = %zx\n", __func__, size);
-
-	addr = start;
-	do {
-		phys_addr_t phys;
-		size_t len;
-
-		phys = sg_phys(sg);
-		len = sg_dma_len(sg);
-
-		/* if back to back sg entries are contiguous consolidate them */
-		while (sg_next(sg) && sg_phys(sg) +
-		       sg_dma_len(sg) == sg_phys(sg_next(sg))) {
-			len += sg_dma_len(sg_next(sg));
-			sg = sg_next(sg);
-		}
-
-		if (offset > 0) {
-			len -= offset;
-			phys += offset;
-			offset = 0;
-		}
-
-		if (offset_in_page(phys)) {
-			len += offset_in_page(phys);
-			phys = round_down(phys, PAGE_SIZE);
-		}
-
-		len = PAGE_ALIGN(len);
-
-		if (len > (size - mapped_size))
-			len = size - mapped_size;
-		pr_debug("addr = %pad, phys = %pa, len = %zx\n", &addr, &phys, len);
-		ret = iommu_map(vmm->domain, addr, phys, len, 0);
-		if (ret)
-			break;
-
-		addr += len;
-		mapped_size += len;
-	} while ((sg = sg_next(sg)) && (mapped_size < size));
-
-	BUG_ON(mapped_size > size);
-
-	if (mapped_size < size)
-		goto err_map_map;
-
-	region->start = start + start_off;
-	region->size = size;
-
-	INIT_LIST_HEAD(&region->node);
-
-	spin_lock(&vmm->lock);
-
-	list_add(&region->node, &vmm->regions_list);
-
-	spin_unlock(&vmm->lock);
-
-	ret = rockchip_iommu_tlb_invalidate(dev);
-	if (ret) {
-		spin_lock(&vmm->lock);
-		list_del(&region->node);
-		spin_unlock(&vmm->lock);
-		goto err_map_map;
-	}
-	dev_dbg(dev->archdata.iommu, "IOVMM: Allocated VM region @ %p/%#X bytes.\n",
-	&region->start, region->size);
-
-	return region->start;
-
-err_map_map:
-	iommu_unmap(vmm->domain, start, mapped_size);
-	gen_pool_free(vmm->vmm_pool, start, size);
-err_map_noiomem:
-	kfree(region);
-err_map_nomem:
-	dev_err(dev->archdata.iommu, "IOVMM: Failed to allocated VM region for %zx bytes.\n", size);
-	return (dma_addr_t)ret;
-}
-
-void rockchip_iovmm_unmap(struct device *dev, dma_addr_t iova)
-{
-	struct rk_vm_region *region;
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-	size_t unmapped_size;
-
-	/* This function must not be called in IRQ handlers */
-	BUG_ON(in_irq());
-
-	spin_lock(&vmm->lock);
-
-	region = find_region(vmm, iova);
-	if (WARN_ON(!region)) {
-		spin_unlock(&vmm->lock);
-		return;
-	}
-
-	list_del(&region->node);
-
-	spin_unlock(&vmm->lock);
-
-	region->start = round_down(region->start, PAGE_SIZE);
-
-	unmapped_size = iommu_unmap(vmm->domain,
-				    region->start, region->size);
-	/*
-	rockchip_iommu_tlb_invalidate(dev);
-	*/
-	gen_pool_free(vmm->vmm_pool, region->start,
-		      region->size+IOMMU_REGION_GUARD);
-
-	WARN_ON(unmapped_size != region->size);
-	
-	dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
-		unmapped_size, &region->start);
-	
-	kfree(region);
-}
-
-int rockchip_iovmm_map_oto(struct device *dev, phys_addr_t phys, size_t size)
-{
-	struct rk_vm_region *region;
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-	int ret;
-
-	if (WARN_ON((phys + size) >= IOVA_START)) {
-		dev_err(dev->archdata.iommu, "Unable to create one to one mapping for %zx @ %pa\n",
-		       size, &phys);
-		return -EINVAL;
-	}
-
-	region = kmalloc(sizeof(*region), GFP_KERNEL);
-	if (!region)
-		return -ENOMEM;
-
-	if (WARN_ON(phys & ~PAGE_MASK))
-		phys = round_down(phys, PAGE_SIZE);
-
-
-	ret = iommu_map(vmm->domain, (dma_addr_t)phys, phys, size, 0);
-	if (ret < 0) {
-		kfree(region);
-		return ret;
-	}
-
-	region->start = (dma_addr_t)phys;
-	region->size = size;
-	INIT_LIST_HEAD(&region->node);
-
-	spin_lock(&vmm->lock);
-
-	list_add(&region->node, &vmm->regions_list);
-
-	spin_unlock(&vmm->lock);
-
-	ret = rockchip_iommu_tlb_invalidate(dev);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-void rockchip_iovmm_unmap_oto(struct device *dev, phys_addr_t phys)
-{
-	struct rk_vm_region *region;
-	struct rk_iovmm *vmm = rockchip_get_iovmm(dev);
-	size_t unmapped_size;
-
-	/* This function must not be called in IRQ handlers */
-	BUG_ON(in_irq());
-
-	if (WARN_ON(phys & ~PAGE_MASK))
-		phys = round_down(phys, PAGE_SIZE);
-
-	spin_lock(&vmm->lock);
-
-	region = find_region(vmm, (dma_addr_t)phys);
-	if (WARN_ON(!region)) {
-		spin_unlock(&vmm->lock);
-		return;
-	}
-
-	list_del(&region->node);
-
-	spin_unlock(&vmm->lock);
-
-	unmapped_size = iommu_unmap(vmm->domain, region->start, region->size);
-	WARN_ON(unmapped_size != region->size);
-	dev_dbg(dev->archdata.iommu, "IOVMM: Unmapped %zx bytes from %pad.\n",
-	       unmapped_size, &region->start);
-
-	kfree(region);
-}
-
-int rockchip_init_iovmm(struct device *iommu, struct rk_iovmm *vmm)
-{
-	int ret = 0;
-
-	vmm->vmm_pool = gen_pool_create(PAGE_SHIFT, -1);
-	if (!vmm->vmm_pool) {
-		ret = -ENOMEM;
-		goto err_setup_genalloc;
-	}
-
-	/* (1GB - 4KB) addr space from 0x10000000 */
-	ret = gen_pool_add(vmm->vmm_pool, IOVA_START, IOVM_SIZE, -1);
-	if (ret)
-		goto err_setup_domain;
-
-	vmm->domain = iommu_domain_alloc(&platform_bus_type);
-	if (!vmm->domain) {
-		ret = -ENOMEM;
-		goto err_setup_domain;
-	}
-
-	spin_lock_init(&vmm->lock);
-
-	INIT_LIST_HEAD(&vmm->regions_list);
-
-	dev_info(iommu, "IOVMM: Created %#x B IOVMM from %#x.\n",
-		IOVM_SIZE, IOVA_START);
-	return 0;
-err_setup_domain:
-	gen_pool_destroy(vmm->vmm_pool);
-err_setup_genalloc:
-	dev_err(iommu, "IOVMM: Failed to create IOVMM (%d)\n", ret);
-
-	return ret;
-}
diff --git a/include/linux/rockchip-iovmm.h b/include/linux/rockchip-iovmm.h
index 919663457d7b..ab7f8bb61f0f 100644
--- a/include/linux/rockchip-iovmm.h
+++ b/include/linux/rockchip-iovmm.h
@@ -19,6 +19,7 @@
 #define VOP_IOMMU_COMPATIBLE_NAME	"rockchip,vop_mmu"
 #define HEVC_IOMMU_COMPATIBLE_NAME "rockchip,hevc_mmu"
 #define VPU_IOMMU_COMPATIBLE_NAME "rockchip,vpu_mmu"
+#define VDEC_IOMMU_COMPATIBLE_NAME "rockchip,vdec_mmu"
 
 enum rk_iommu_inttype {
 	IOMMU_PAGEFAULT,
@@ -47,7 +48,7 @@ typedef int (*rockchip_iommu_fault_handler_t)(struct device *dev,
 struct scatterlist;
 struct device;
 
-#ifdef CONFIG_ROCKCHIP_IOVMM
+#ifdef CONFIG_RK_IOVMM
 
 int rockchip_iovmm_activate(struct device *dev);
 void rockchip_iovmm_deactivate(struct device *dev);
@@ -148,6 +149,6 @@ static inline int rockchip_iovmm_invalidate_tlb(struct device *dev)
 	return -ENOSYS;
 }
 
-#endif /* CONFIG_ROCKCHIP_IOVMM */
+#endif /* CONFIG_RK_IOVMM */
 
 #endif /*__ASM_PLAT_IOVMM_H*/