Re: [PATCH v1 2/2] iommu: add Unisoc iommu basic driver

2021-01-27 Thread Chunyan Zhang
On Fri, 22 Jan 2021 at 05:46, Robin Murphy  wrote:
>
> On 2021-01-21 11:23, Chunyan Zhang wrote:
> > From: Chunyan Zhang 
> >
> > This patch only adds display iommu support, the driver was tested with sprd
> > dpu and image codec processor.
> >
> > The iommu support for others would be added once finished tests with those
> > devices, such as a few signal processors, including VSP(video),
> > GSP(graphic), ISP(image), and camera CPP, etc.
> >
> > Signed-off-by: Chunyan Zhang 
> > ---
> >   drivers/iommu/Kconfig  |  12 +
> >   drivers/iommu/Makefile |   1 +
> >   drivers/iommu/sprd-iommu.c | 566 +
> >   3 files changed, 579 insertions(+)
> >   create mode 100644 drivers/iommu/sprd-iommu.c
> >
> > diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> > index 192ef8f61310..79af62c519ae 100644
> > --- a/drivers/iommu/Kconfig
> > +++ b/drivers/iommu/Kconfig
> > @@ -408,4 +408,16 @@ config VIRTIO_IOMMU
> >
> > Say Y here if you intend to run this kernel as a guest.
> >
> > +config SPRD_IOMMU
> > + tristate "Unisoc IOMMU Support"
> > + depends on ARCH_SPRD || COMPILE_TEST
> > + select IOMMU_API
> > + help
> > +   Support for IOMMU on Unisoc's SoCs on which multi-media subsystems
> > +   need IOMMU, such as DPU, Image codec(jpeg) processor, and a few
> > +   signal processors, including VSP(video), GSP(graphic), ISP(image), 
> > and
> > +   CPP, etc.
> > +
> > +   Say Y here if you want multi-media functions.
> > +
> >   endif # IOMMU_SUPPORT
> > diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> > index 61bd30cd8369..5925b6af2123 100644
> > --- a/drivers/iommu/Makefile
> > +++ b/drivers/iommu/Makefile
> > @@ -28,3 +28,4 @@ obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
> >   obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
> >   obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
> >   obj-$(CONFIG_IOMMU_SVA_LIB) += iommu-sva-lib.o
> > +obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
> > diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
> > new file mode 100644
> > index ..44cde44017fa
> > --- /dev/null
> > +++ b/drivers/iommu/sprd-iommu.c
> > @@ -0,0 +1,566 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Unisoc IOMMU driver
> > + *
> > + * Copyright (C) 2020 Unisoc, Inc.
> > + * Author: Chunyan Zhang 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
>
> You need  since you're using the DMA API.
>
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +/* SPRD IOMMU page is 4K size alignment */
> > +#define SPRD_IOMMU_PAGE_SHIFT12
> > +#define SPRD_IOMMU_PAGE_SIZE SZ_4K
> > +
> > +#define SPRD_EX_CFG  0x0
> > +#define SPRD_IOMMU_VAOR_BYPASS   BIT(4)
> > +#define SPRD_IOMMU_GATE_EN   BIT(1)
> > +#define SPRD_IOMMU_ENBIT(0)
> > +#define SPRD_EX_UPDATE   0x4
> > +#define SPRD_EX_FIRST_VPN0x8
> > +#define SPRD_EX_VPN_RANGE0xc
> > +#define SPRD_EX_FIRST_PPN0x10
> > +#define SPRD_EX_DEFAULT_PPN  0x14
> > +
> > +#define SPRD_IOMMU_VERSION   0x0
> > +#define SPRD_VERSION_MASKGENMASK(15, 8)
> > +#define SPRD_VERSION_SHIFT   0x8
> > +#define SPRD_VAU_CFG 0x4
> > +#define SPRD_VAU_UPDATE  0x8
> > +#define SPRD_VAU_AUTH_CFG0xc
> > +#define SPRD_VAU_FIRST_PPN   0x10
> > +#define SPRD_VAU_DEFAULT_PPN_RD  0x14
> > +#define SPRD_VAU_DEFAULT_PPN_WR  0x18
> > +#define SPRD_VAU_FIRST_VPN   0x1c
> > +#define SPRD_VAU_VPN_RANGE   0x20
> > +
> > +enum sprd_iommu_version {
> > + SPRD_IOMMU_EX,
> > + SPRD_IOMMU_VAU,
> > +};
> > +
> > +struct sprd_iommu_match_data {
> > + unsigned long reg_offset;
> > +};
> > +
> > +/*
> > + * struct sprd_iommu_device - high-level sprd iommu device representation,
> > + * including hardware information and configuration, also driver data, etc
> > + *
> > + * @mdata:   hardware configuration and information
> > + * @ver: sprd iommu device version
> > + * @prot_page:   protect page base address, data would be written to 
> > here
> > + *   while translation fault
> > + * @base:mapped base address for accessing registers
> > + * @dev: pointer to basic device structure
> > + * @iommu:   IOMMU core representation
> > + * @group:   IOMMU group
> > + */
> > +struct sprd_iommu_device {
> > + const struct sprd_iommu_match_data *mdata;
> > + enum sprd_iommu_version ver;
> > + u32 *prot_page_va;
> > + dma_addr_t  prot_page_pa;
> > + void __iomem*base;
> > + struct device   *dev;
> > + struct iommu_device iommu;
> > + struct iommu_group  *group;
> > +};
> > +
> > +struct sprd_iommu_domain {
> > + spinlock_t  pgtlock; /* lock for page table */
> > + struct iommu_domain domain;
> > + u32 *pgt_va; /* page table virtual address base */
> > + dma_addr_t  pgt_pa; /* page

Re: [PATCH v1 2/2] iommu: add Unisoc iommu basic driver

2021-01-21 Thread Robin Murphy

On 2021-01-21 11:23, Chunyan Zhang wrote:

From: Chunyan Zhang 

This patch only adds display iommu support, the driver was tested with sprd
dpu and image codec processor.

The iommu support for others would be added once finished tests with those
devices, such as a few signal processors, including VSP(video),
GSP(graphic), ISP(image), and camera CPP, etc.

Signed-off-by: Chunyan Zhang 
---
  drivers/iommu/Kconfig  |  12 +
  drivers/iommu/Makefile |   1 +
  drivers/iommu/sprd-iommu.c | 566 +
  3 files changed, 579 insertions(+)
  create mode 100644 drivers/iommu/sprd-iommu.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 192ef8f61310..79af62c519ae 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -408,4 +408,16 @@ config VIRTIO_IOMMU
  
  	  Say Y here if you intend to run this kernel as a guest.
  
+config SPRD_IOMMU

+   tristate "Unisoc IOMMU Support"
+   depends on ARCH_SPRD || COMPILE_TEST
+   select IOMMU_API
+   help
+ Support for IOMMU on Unisoc's SoCs on which multi-media subsystems
+ need IOMMU, such as DPU, Image codec(jpeg) processor, and a few
+ signal processors, including VSP(video), GSP(graphic), ISP(image), and
+ CPP, etc.
+
+ Say Y here if you want multi-media functions.
+
  endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 61bd30cd8369..5925b6af2123 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
  obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
  obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
  obj-$(CONFIG_IOMMU_SVA_LIB) += iommu-sva-lib.o
+obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
new file mode 100644
index ..44cde44017fa
--- /dev/null
+++ b/drivers/iommu/sprd-iommu.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Unisoc IOMMU driver
+ *
+ * Copyright (C) 2020 Unisoc, Inc.
+ * Author: Chunyan Zhang 
+ */
+
+#include 
+#include 
+#include 


You need  since you're using the DMA API.


+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* SPRD IOMMU page is 4K size alignment */
+#define SPRD_IOMMU_PAGE_SHIFT  12
+#define SPRD_IOMMU_PAGE_SIZE   SZ_4K
+
+#define SPRD_EX_CFG0x0
+#define SPRD_IOMMU_VAOR_BYPASS BIT(4)
+#define SPRD_IOMMU_GATE_EN BIT(1)
+#define SPRD_IOMMU_EN  BIT(0)
+#define SPRD_EX_UPDATE 0x4
+#define SPRD_EX_FIRST_VPN  0x8
+#define SPRD_EX_VPN_RANGE  0xc
+#define SPRD_EX_FIRST_PPN  0x10
+#define SPRD_EX_DEFAULT_PPN0x14
+
+#define SPRD_IOMMU_VERSION 0x0
+#define SPRD_VERSION_MASK  GENMASK(15, 8)
+#define SPRD_VERSION_SHIFT 0x8
+#define SPRD_VAU_CFG   0x4
+#define SPRD_VAU_UPDATE0x8
+#define SPRD_VAU_AUTH_CFG  0xc
+#define SPRD_VAU_FIRST_PPN 0x10
+#define SPRD_VAU_DEFAULT_PPN_RD0x14
+#define SPRD_VAU_DEFAULT_PPN_WR0x18
+#define SPRD_VAU_FIRST_VPN 0x1c
+#define SPRD_VAU_VPN_RANGE 0x20
+
+enum sprd_iommu_version {
+   SPRD_IOMMU_EX,
+   SPRD_IOMMU_VAU,
+};
+
+struct sprd_iommu_match_data {
+   unsigned long reg_offset;
+};
+
+/*
+ * struct sprd_iommu_device - high-level sprd iommu device representation,
+ * including hardware information and configuration, also driver data, etc
+ *
+ * @mdata: hardware configuration and information
+ * @ver:   sprd iommu device version
+ * @prot_page: protect page base address, data would be written to here
+ * while translation fault
+ * @base:  mapped base address for accessing registers
+ * @dev:   pointer to basic device structure
+ * @iommu: IOMMU core representation
+ * @group: IOMMU group
+ */
+struct sprd_iommu_device {
+   const struct sprd_iommu_match_data *mdata;
+   enum sprd_iommu_version ver;
+   u32 *prot_page_va;
+   dma_addr_t  prot_page_pa;
+   void __iomem*base;
+   struct device   *dev;
+   struct iommu_device iommu;
+   struct iommu_group  *group;
+};
+
+struct sprd_iommu_domain {
+   spinlock_t  pgtlock; /* lock for page table */
+   struct iommu_domain domain;
+   u32 *pgt_va; /* page table virtual address base */
+   dma_addr_t  pgt_pa; /* page table physical address base */
+   struct sprd_iommu_device*sdev;
+};
+
+static const struct iommu_ops sprd_iommu_ops;
+
+static struct sprd_iommu_domain *to_sprd_domain(struct iommu_domain *dom)
+{
+   return container_of(dom, struct sprd_iommu_domain, domain);
+}
+
+static inline void
+sprd_iommu_writel(struct sprd_iommu_device *sdev, unsigned int reg, u32 val)
+{
+   writel_relaxed(val, sdev->base + sdev->mdata->reg_offset + reg);
+}
+
+static inline u32
+sprd_iommu_readl(struct sprd_iommu_device

Re: [PATCH v1 2/2] iommu: add Unisoc iommu basic driver

2021-01-21 Thread kernel test robot
Hi Chunyan,

I love your patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on v5.11-rc4 next-20210121]
[cannot apply to iommu/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:
https://github.com/0day-ci/linux/commits/Chunyan-Zhang/Add-Unisoc-iommu-basic-driver/20210121-194023
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# 
https://github.com/0day-ci/linux/commit/891db11d7229149235a02e5bc31a61188243a5d7
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review 
Chunyan-Zhang/Add-Unisoc-iommu-basic-driver/20210121-194023
git checkout 891db11d7229149235a02e5bc31a61188243a5d7
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot 

All errors (new ones prefixed by >>):

   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_attach_device':
>> drivers/iommu/sprd-iommu.c:248:16: error: implicit declaration of function 
>> 'dma_alloc_coherent' [-Werror=implicit-function-declaration]
 248 |  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, 
GFP_KERNEL);
 |^~
   drivers/iommu/sprd-iommu.c:248:14: warning: assignment to 'u32 *' {aka 
'unsigned int *'} from 'int' makes pointer from integer without a cast 
[-Wint-conversion]
 248 |  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, 
GFP_KERNEL);
 |  ^
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_detach_device':
>> drivers/iommu/sprd-iommu.c:270:2: error: implicit declaration of function 
>> 'dma_free_coherent' [-Werror=implicit-function-declaration]
 270 |  dma_free_coherent(sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa);
 |  ^
   In file included from include/linux/device.h:15,
from drivers/iommu/sprd-iommu.c:10:
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_map':
   drivers/iommu/sprd-iommu.c:296:27: warning: format '%lx' expects argument of 
type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} 
[-Wformat=]
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |   
^
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
  19 | #define dev_fmt(fmt) fmt
 |  ^~~
   drivers/iommu/sprd-iommu.c:296:3: note: in expansion of macro 'dev_err'
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |   ^~~
   drivers/iommu/sprd-iommu.c:296:52: note: format string is defined here
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |  ~~^
 ||
 |long unsigned int
 |  %x
   drivers/iommu/sprd-iommu.c:279:38: warning: variable 'mdata' set but not 
used [-Wunused-but-set-variable]
 279 |  const struct sprd_iommu_match_data *mdata;
 |  ^
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_probe':
   drivers/iommu/sprd-iommu.c:483:21: warning: assignment to 'u32 *' {aka 
'unsigned int *'} from 'int' makes pointer from integer without a cast 
[-Wint-conversion]
 483 |  sdev->prot_page_va = dma_alloc_coherent(dev, SPRD_IOMMU_PAGE_SIZE,
 | ^
   cc1: some warnings being treated as errors


vim +/dma_alloc_coherent +248 drivers/iommu/sprd-iommu.c

   240  
   241  static int sprd_iommu_attach_device(struct iommu_domain *domain,
   242  struct device *dev)
   243  {
   244  struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
   245  struct sprd_iommu_domain *dom = to_sprd_domain(domain);
   246  size_t pgt_size = sprd_iommu_pgt_size(domain);
   247  
 > 248  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, 
 > &dom->pgt_pa, GFP_KERNEL);
   249  if (!dom->pgt_va)
   250  return -ENOMEM;
   251  
   252  dom->sdev = sdev;
   253  
   254  sprd_iommu_first_ppn(dom);
   255 

Re: [PATCH v1 2/2] iommu: add Unisoc iommu basic driver

2021-01-21 Thread kernel test robot
Hi Chunyan,

I love your patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on v5.11-rc4 next-20210121]
[cannot apply to iommu/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:
https://github.com/0day-ci/linux/commits/Chunyan-Zhang/Add-Unisoc-iommu-basic-driver/20210121-194023
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: arc-allyesconfig (attached as .config)
compiler: arceb-elf-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# 
https://github.com/0day-ci/linux/commit/891db11d7229149235a02e5bc31a61188243a5d7
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review 
Chunyan-Zhang/Add-Unisoc-iommu-basic-driver/20210121-194023
git checkout 891db11d7229149235a02e5bc31a61188243a5d7
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arc 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot 

All warnings (new ones prefixed by >>):

   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_attach_device':
   drivers/iommu/sprd-iommu.c:248:16: error: implicit declaration of function 
'dma_alloc_coherent' [-Werror=implicit-function-declaration]
 248 |  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, 
GFP_KERNEL);
 |^~
>> drivers/iommu/sprd-iommu.c:248:14: warning: assignment to 'u32 *' {aka 
>> 'unsigned int *'} from 'int' makes pointer from integer without a cast 
>> [-Wint-conversion]
 248 |  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, 
GFP_KERNEL);
 |  ^
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_detach_device':
   drivers/iommu/sprd-iommu.c:270:2: error: implicit declaration of function 
'dma_free_coherent' [-Werror=implicit-function-declaration]
 270 |  dma_free_coherent(sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa);
 |  ^
   In file included from include/linux/device.h:15,
from drivers/iommu/sprd-iommu.c:10:
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_map':
>> drivers/iommu/sprd-iommu.c:296:27: warning: format '%lx' expects argument of 
>> type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned 
>> int'} [-Wformat=]
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |   
^
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
  19 | #define dev_fmt(fmt) fmt
 |  ^~~
   drivers/iommu/sprd-iommu.c:296:3: note: in expansion of macro 'dev_err'
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |   ^~~
   drivers/iommu/sprd-iommu.c:296:52: note: format string is defined here
 296 |   dev_err(dom->sdev->dev, "(iova(0x%lx) + sixe(0x%lx)) are not in 
the range!\n",
 |  ~~^
 ||
 |long unsigned int
 |  %x
>> drivers/iommu/sprd-iommu.c:279:38: warning: variable 'mdata' set but not 
>> used [-Wunused-but-set-variable]
 279 |  const struct sprd_iommu_match_data *mdata;
 |  ^
   drivers/iommu/sprd-iommu.c: In function 'sprd_iommu_probe':
   drivers/iommu/sprd-iommu.c:483:21: warning: assignment to 'u32 *' {aka 
'unsigned int *'} from 'int' makes pointer from integer without a cast 
[-Wint-conversion]
 483 |  sdev->prot_page_va = dma_alloc_coherent(dev, SPRD_IOMMU_PAGE_SIZE,
 | ^
   cc1: some warnings being treated as errors


vim +248 drivers/iommu/sprd-iommu.c

   240  
   241  static int sprd_iommu_attach_device(struct iommu_domain *domain,
   242  struct device *dev)
   243  {
   244  struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
   245  struct sprd_iommu_domain *dom = to_sprd_domain(domain);
   246  size_t pgt_size = sprd_iommu_pgt_size(domain);
   247  
 > 248  dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, 
 > &dom->pgt_pa, GFP_KERNEL);
   249  if (!dom->pgt_va)
   250  return -ENOMEM;
   251  
   252  dom->sdev = sdev;
   253  
   254  sprd_iommu_first_ppn(dom);
   255  s

[PATCH v1 2/2] iommu: add Unisoc iommu basic driver

2021-01-21 Thread Chunyan Zhang
From: Chunyan Zhang 

This patch only adds display iommu support, the driver was tested with sprd
dpu and image codec processor.

The iommu support for others would be added once finished tests with those
devices, such as a few signal processors, including VSP(video),
GSP(graphic), ISP(image), and camera CPP, etc.

Signed-off-by: Chunyan Zhang 
---
 drivers/iommu/Kconfig  |  12 +
 drivers/iommu/Makefile |   1 +
 drivers/iommu/sprd-iommu.c | 566 +
 3 files changed, 579 insertions(+)
 create mode 100644 drivers/iommu/sprd-iommu.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 192ef8f61310..79af62c519ae 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -408,4 +408,16 @@ config VIRTIO_IOMMU
 
  Say Y here if you intend to run this kernel as a guest.
 
+config SPRD_IOMMU
+   tristate "Unisoc IOMMU Support"
+   depends on ARCH_SPRD || COMPILE_TEST
+   select IOMMU_API
+   help
+ Support for IOMMU on Unisoc's SoCs on which multi-media subsystems
+ need IOMMU, such as DPU, Image codec(jpeg) processor, and a few
+ signal processors, including VSP(video), GSP(graphic), ISP(image), and
+ CPP, etc.
+
+ Say Y here if you want multi-media functions.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 61bd30cd8369..5925b6af2123 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_S390_IOMMU) += s390-iommu.o
 obj-$(CONFIG_HYPERV_IOMMU) += hyperv-iommu.o
 obj-$(CONFIG_VIRTIO_IOMMU) += virtio-iommu.o
 obj-$(CONFIG_IOMMU_SVA_LIB) += iommu-sva-lib.o
+obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
new file mode 100644
index ..44cde44017fa
--- /dev/null
+++ b/drivers/iommu/sprd-iommu.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Unisoc IOMMU driver
+ *
+ * Copyright (C) 2020 Unisoc, Inc.
+ * Author: Chunyan Zhang 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* SPRD IOMMU page is 4K size alignment */
+#define SPRD_IOMMU_PAGE_SHIFT  12
+#define SPRD_IOMMU_PAGE_SIZE   SZ_4K
+
+#define SPRD_EX_CFG0x0
+#define SPRD_IOMMU_VAOR_BYPASS BIT(4)
+#define SPRD_IOMMU_GATE_EN BIT(1)
+#define SPRD_IOMMU_EN  BIT(0)
+#define SPRD_EX_UPDATE 0x4
+#define SPRD_EX_FIRST_VPN  0x8
+#define SPRD_EX_VPN_RANGE  0xc
+#define SPRD_EX_FIRST_PPN  0x10
+#define SPRD_EX_DEFAULT_PPN0x14
+
+#define SPRD_IOMMU_VERSION 0x0
+#define SPRD_VERSION_MASK  GENMASK(15, 8)
+#define SPRD_VERSION_SHIFT 0x8
+#define SPRD_VAU_CFG   0x4
+#define SPRD_VAU_UPDATE0x8
+#define SPRD_VAU_AUTH_CFG  0xc
+#define SPRD_VAU_FIRST_PPN 0x10
+#define SPRD_VAU_DEFAULT_PPN_RD0x14
+#define SPRD_VAU_DEFAULT_PPN_WR0x18
+#define SPRD_VAU_FIRST_VPN 0x1c
+#define SPRD_VAU_VPN_RANGE 0x20
+
+enum sprd_iommu_version {
+   SPRD_IOMMU_EX,
+   SPRD_IOMMU_VAU,
+};
+
+struct sprd_iommu_match_data {
+   unsigned long reg_offset;
+};
+
+/*
+ * struct sprd_iommu_device - high-level sprd iommu device representation,
+ * including hardware information and configuration, also driver data, etc
+ *
+ * @mdata: hardware configuration and information
+ * @ver:   sprd iommu device version
+ * @prot_page: protect page base address, data would be written to here
+ * while translation fault
+ * @base:  mapped base address for accessing registers
+ * @dev:   pointer to basic device structure
+ * @iommu: IOMMU core representation
+ * @group: IOMMU group
+ */
+struct sprd_iommu_device {
+   const struct sprd_iommu_match_data *mdata;
+   enum sprd_iommu_version ver;
+   u32 *prot_page_va;
+   dma_addr_t  prot_page_pa;
+   void __iomem*base;
+   struct device   *dev;
+   struct iommu_device iommu;
+   struct iommu_group  *group;
+};
+
+struct sprd_iommu_domain {
+   spinlock_t  pgtlock; /* lock for page table */
+   struct iommu_domain domain;
+   u32 *pgt_va; /* page table virtual address base */
+   dma_addr_t  pgt_pa; /* page table physical address base */
+   struct sprd_iommu_device*sdev;
+};
+
+static const struct iommu_ops sprd_iommu_ops;
+
+static struct sprd_iommu_domain *to_sprd_domain(struct iommu_domain *dom)
+{
+   return container_of(dom, struct sprd_iommu_domain, domain);
+}
+
+static inline void
+sprd_iommu_writel(struct sprd_iommu_device *sdev, unsigned int reg, u32 val)
+{
+   writel_relaxed(val, sdev->base + sdev->mdata->reg_offset + reg);
+}
+
+static inline u32
+sprd_iommu_readl(struct sprd_iommu_device *sdev, unsigned int reg)
+{
+   return readl_relaxed(sdev->base + sdev->mdata->reg_offset +