LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [RFC PATCH 0/5] MT8173 IOMMU support
@ 2015-03-06 10:48 yong.wu
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
                   ` (4 more replies)
  0 siblings, 5 replies; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu

  This is based on Robin Murphy's arm64: IOMMU-backed DMA mapping[1]. 
This patch adds support for m4u(Multimedia Memory Management Unit),
Currently it only support the m4u with 2 levels of page table on mt8173.

  Please check the hardware block diagram of Mediatek IOMMU.

              EMI (External Memory Interface)
               |
              m4u (Multimedia Memory Management Unit)
               |
              smi (Smart Multimedia Interface)
               |
        +---------------+-------
        |               |
        |               |
    vdec larb       disp larb      ... SoCs have different local arbiter(larb).
        |               |
        |               |
   +----+----+    +-----+-----+
   |    |    |    |     |     |    ...
   |    |    |    |     |     |    ...
   |    |    |    |     |     |    ...
  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... 
  
  Normally we specify a local arbiter(larb) for each multimedia hardware like
display, video decode, video encode and camera. And there are different ports in
each larb. Take a example, there are some ports like MC, PP, UFO, VLD, AVC_MV,
PRED_RD, PRED_WR in video larb, all the ports are according to the video hardware.

	From the diagram, all the multimedia module connect with m4u via smi.
SMI is responsible to enable/disable iommu and control the clocks of each local
arbiter. If we should enable the iommu of video decode, it should config the 
video's ports. And if the video hardware work wether enable/disable iommu, 
it should enable the clock of its larb's clock. So we add a special driver for smi.

[1] http://lists.linuxfoundation.org/pipermail/iommu/2015-February/012236.html

Yong Wu (5):
  soc: mediatek: Add SMI driver
  iommu/mediatek: Add mt8173 IOMMU driver
  dt-bindings: mediatek: Add smi dts binding
  dt-bindings: iommu: Add binding for mediatek IOMMU
  dts: mt8173: Add iommu/smi nodes for mt8173

 .../devicetree/bindings/iommu/mediatek,iommu.txt   |  41 ++
 .../bindings/soc/mediatek/mediatek,smi.txt         |  17 +
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |  60 ++
 drivers/iommu/Kconfig                              |  11 +
 drivers/iommu/Makefile                             |   1 +
 drivers/iommu/mtk_iommu.c                          | 754 +++++++++++++++++++++
 drivers/iommu/mtk_iommu.h                          |  73 ++
 drivers/iommu/mtk_iommu_pagetable.c                | 439 ++++++++++++
 drivers/iommu/mtk_iommu_pagetable.h                |  49 ++
 drivers/soc/mediatek/Kconfig                       |   7 +
 drivers/soc/mediatek/Makefile                      |   1 +
 drivers/soc/mediatek/mt8173-smi.c                  | 143 ++++
 include/dt-bindings/iommu/mt8173-iommu-port.h      | 127 ++++
 include/linux/mtk-smi.h                            |  40 ++
 14 files changed, 1763 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
 create mode 100644 drivers/iommu/mtk_iommu.c
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.c
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.h
 create mode 100644 drivers/soc/mediatek/mt8173-smi.c
 create mode 100644 include/dt-bindings/iommu/mt8173-iommu-port.h
 create mode 100644 include/linux/mtk-smi.h

-- 
1.8.1.1.dirty

^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
@ 2015-03-06 10:48 ` yong.wu
  2015-03-06 11:30   ` Paul Bolle
                     ` (2 more replies)
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu, Yong Wu

From: Yong Wu <yong.wu@mediatek.com>

    This patch add SMI(Smart Multimedia Interface) driver. This driver is
responsible to enable/disable iommu and control the clocks of each
local arbiter.

Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
 drivers/soc/mediatek/Kconfig      |   7 ++
 drivers/soc/mediatek/Makefile     |   1 +
 drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
 include/linux/mtk-smi.h           |  40 +++++++++++
 4 files changed, 191 insertions(+)
 create mode 100644 drivers/soc/mediatek/mt8173-smi.c
 create mode 100644 include/linux/mtk-smi.h

diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 729f93e..27fb26c 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
 	  PMIC wrapper is a proprietary hardware in MT8173 to make
 	  communication protocols to access PMIC device.
 	  This driver implement access protocols for MT8173.
+
+config MTK_SMI
+        bool
+	help
+	  Smi help enable/disable iommu in mt8173 and control the
+	  clock of each local arbiter.
+	  It should be true while MTK_IOMMU enable.
diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
index 9b5709b..cdfe95c 100644
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MT8135_PMIC_WRAP)		+= mt8135-pmic-wrap.o
 obj-$(CONFIG_MT8173_PMIC_WRAP)		+= mt8173-pmic-wrap.o
+obj-$(CONFIG_MTK_SMI)                   += mt8173-smi.o
diff --git a/drivers/soc/mediatek/mt8173-smi.c b/drivers/soc/mediatek/mt8173-smi.c
new file mode 100644
index 0000000..4e3fab9
--- /dev/null
+++ b/drivers/soc/mediatek/mt8173-smi.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+
+#define SMI_LARB_MMU_EN                 (0xf00)
+#define F_SMI_MMU_EN(port)              (1 << (port))
+
+struct mtk_smi_larb {
+	void __iomem *larb_base;
+	struct clk *larb_clk[3];/* each larb has 3 clk at most */
+};
+
+static const char * const mtk_smi_clk_name[] = {
+	"larb_sub0", "larb_sub1", "larb_sub2"
+};
+
+static const struct of_device_id mtk_smi_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-smi-larb",
+	},
+	{}
+};
+
+int mtk_smi_larb_get(struct platform_device *plarbdev)
+{
+	struct mtk_smi_larb *larbpriv = dev_get_drvdata(&plarbdev->dev);
+	int i, ret = 0;
+
+	for (i = 0; i < 3; i++)
+		if (larbpriv->larb_clk[i]) {
+			ret = clk_prepare_enable(larbpriv->larb_clk[i]);
+			if (ret) {
+				dev_err(&plarbdev->dev,
+					"failed to enable larbclk%d:%d\n",
+					i, ret);
+				break;
+			}
+		}
+	return ret;
+}
+
+void mtk_smi_larb_put(struct platform_device *plarbdev)
+{
+	struct mtk_smi_larb *larbpriv = dev_get_drvdata(&plarbdev->dev);
+	int i;
+
+	for (i = 2; i >= 0; i--)
+		if (larbpriv->larb_clk[i])
+			clk_disable_unprepare(larbpriv->larb_clk[i]);
+}
+
+int mtk_smi_config_port(struct platform_device *plarbdev,
+			unsigned int larbportid)
+{
+	struct mtk_smi_larb *larbpriv = dev_get_drvdata(&plarbdev->dev);
+	int ret;
+	u32 reg;
+
+	ret = mtk_smi_larb_get(plarbdev);
+	if (ret)
+		return ret;
+
+	reg = readl(larbpriv->larb_base + SMI_LARB_MMU_EN);
+	reg &= ~F_SMI_MMU_EN(larbportid);
+	reg |= F_SMI_MMU_EN(larbportid);
+	writel(reg, larbpriv->larb_base + SMI_LARB_MMU_EN);
+
+	mtk_smi_larb_put(plarbdev);
+
+	return 0;
+}
+
+static int mtk_smi_probe(struct platform_device *pdev)
+{
+	struct mtk_smi_larb *larbpriv;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	unsigned int i;
+
+	larbpriv = devm_kzalloc(dev, sizeof(struct mtk_smi_larb), GFP_KERNEL);
+	if (!larbpriv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	larbpriv->larb_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(larbpriv->larb_base)) {
+		dev_err(dev, "larbbase %p err\n", larbpriv->larb_base);
+		return PTR_ERR(larbpriv->larb_base);
+	}
+
+	for (i = 0; i < 3; i++) {
+		larbpriv->larb_clk[i] = devm_clk_get(dev, mtk_smi_clk_name[i]);
+
+		if (IS_ERR(larbpriv->larb_clk[i])) {
+			if (i == 2) {/* some larb may have only 2 clock */
+				larbpriv->larb_clk[i] = NULL;
+			} else {
+				dev_err(dev, "clock-%d err: %p\n", i,
+					larbpriv->larb_clk[i]);
+				return PTR_ERR(larbpriv->larb_clk[i]);
+			}
+		}
+	}
+	dev_set_drvdata(dev, larbpriv);
+	return 0;
+}
+
+static int mtk_smi_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver mtk_smi_driver = {
+	.probe	= mtk_smi_probe,
+	.remove	= mtk_smi_remove,
+	.driver	= {
+		.name = "mtksmi",
+		.of_match_table = mtk_smi_of_ids,
+	}
+};
+
+static int __init mtk_smi_init(void)
+{
+	return platform_driver_register(&mtk_smi_driver);
+}
+
+subsys_initcall(mtk_smi_init);
+
diff --git a/include/linux/mtk-smi.h b/include/linux/mtk-smi.h
new file mode 100644
index 0000000..1411f7b
--- /dev/null
+++ b/include/linux/mtk-smi.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MTK_IOMMU_SMI_H
+#define MTK_IOMMU_SMI_H
+#include <linux/platform_device.h>
+
+/*
+ * Enable iommu for each port, it is only for iommu.
+ *
+ * Returns 0 if successfully, others if failed.
+ */
+int mtk_smi_config_port(struct platform_device *pdev,
+			unsigned int larbportid);
+
+/*
+ * The multimedia module should call the two function below
+ * which help open/close the clock of the larb.
+ * so the client dtsi should add the larb like "larb = <&larb0>"
+ * to get platform_device.
+ *
+ * mtk_smi_larb_get should be called before the multimedia h/w work.
+ * mtk_smi_larb_put should be called after h/w done.
+ *
+ * Returns 0 if successfully, others if failed.
+ */
+int mtk_smi_larb_get(struct platform_device *plarbdev);
+void mtk_smi_larb_put(struct platform_device *plarbdev);
+
+#endif
-- 
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
@ 2015-03-06 10:48 ` yong.wu
  2015-03-06 10:58   ` Will Deacon
                     ` (5 more replies)
  2015-03-06 10:48 ` [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding yong.wu
                   ` (2 subsequent siblings)
  4 siblings, 6 replies; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu, Yong Wu

From: Yong Wu <yong.wu@mediatek.com>

This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.

Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
 drivers/iommu/Kconfig               |  11 +
 drivers/iommu/Makefile              |   1 +
 drivers/iommu/mtk_iommu.c           | 754 ++++++++++++++++++++++++++++++++++++
 drivers/iommu/mtk_iommu.h           |  73 ++++
 drivers/iommu/mtk_iommu_pagetable.c | 439 +++++++++++++++++++++
 drivers/iommu/mtk_iommu_pagetable.h |  49 +++
 6 files changed, 1327 insertions(+)
 create mode 100644 drivers/iommu/mtk_iommu.c
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.c
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.h

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 19027bb..e63f5b6 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -326,4 +326,15 @@ config ARM_SMMU
 	  Say Y here if your SoC includes an IOMMU device implementing
 	  the ARM SMMU architecture.
 
+config MTK_IOMMU
+	bool "MTK IOMMU Support"
+	select IOMMU_API
+	select IOMMU_DMA
+	select MTK_SMI
+	help
+	  Support for the IOMMUs on certain Mediatek SOCs.
+	  These IOMMUs allow the multimedia hardware access discontinuous memory.
+
+	  If unsure, say N here.
+
 endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 37bfc4e..f2a8027 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
 obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
 obj-$(CONFIG_IOMMU_IOVA) += iova.o
 obj-$(CONFIG_OF_IOMMU)	+= of_iommu.o
+obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o mtk_iommu_pagetable.o
 obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
new file mode 100644
index 0000000..d62d4ab
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "m4u:"fmt
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/iommu.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-iommu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/mtk-smi.h>
+#include <asm/cacheflush.h>
+
+#include "mtk_iommu.h"
+
+#define REG_MMUG_PT_BASE	 0x0
+
+#define REG_MMU_INVLD		 0x20
+#define F_MMU_INV_ALL		 0x2
+#define F_MMU_INV_RANGE		 0x1
+
+#define REG_MMU_INVLD_SA	 0x24
+#define REG_MMU_INVLD_EA         0x28
+
+#define REG_MMU_INVLD_SEC         0x2c
+#define F_MMU_INV_SEC_ALL          0x2
+#define F_MMU_INV_SEC_RANGE        0x1
+
+#define REG_INVLID_SEL	         0x38
+#define F_MMU_INV_EN_L1		 BIT(0)
+#define F_MMU_INV_EN_L2		 BIT(1)
+
+#define REG_MMU_STANDARD_AXI_MODE   0x48
+#define REG_MMU_DCM_DIS             0x50
+#define REG_MMU_LEGACY_4KB_MODE     0x60
+
+#define REG_MMU_CTRL_REG                 0x110
+#define F_MMU_CTRL_REROUTE_PFQ_TO_MQ_EN  BIT(4)
+#define F_MMU_CTRL_TF_PROT_VAL(prot)      (((prot) & 0x3)<<5)
+#define F_MMU_CTRL_COHERE_EN             BIT(8)
+
+#define REG_MMU_IVRP_PADDR               0x114
+#define F_MMU_IVRP_PA_SET(PA)            (PA>>1)
+
+#define REG_MMU_INT_L2_CONTROL      0x120
+#define F_INT_L2_CLR_BIT            BIT(12)
+
+#define REG_MMU_INT_MAIN_CONTROL    0x124
+#define F_INT_TRANSLATION_FAULT(MMU)           (1<<(0+(((MMU)<<1)|((MMU)<<2))))
+#define F_INT_MAIN_MULTI_HIT_FAULT(MMU)        (1<<(1+(((MMU)<<1)|((MMU)<<2))))
+#define F_INT_INVALID_PA_FAULT(MMU)            (1<<(2+(((MMU)<<1)|((MMU)<<2))))
+#define F_INT_ENTRY_REPLACEMENT_FAULT(MMU)     (1<<(3+(((MMU)<<1)|((MMU)<<2))))
+#define F_INT_TLB_MISS_FAULT(MMU)              (1<<(4+(((MMU)<<1)|((MMU)<<2))))
+#define F_INT_PFH_FIFO_ERR(MMU)                (1<<(6+(((MMU)<<1)|((MMU)<<2))))
+
+#define REG_MMU_CPE_DONE              0x12C
+
+#define REG_MMU_MAIN_FAULT_ST         0x134
+
+#define REG_MMU_FAULT_VA(mmu)         (0x13c+((mmu)<<3))
+#define F_MMU_FAULT_VA_MSK            ((~0x0)<<12)
+#define F_MMU_FAULT_VA_WRITE_BIT       BIT(1)
+#define F_MMU_FAULT_VA_LAYER_BIT       BIT(0)
+
+#define REG_MMU_INVLD_PA(mmu)         (0x140+((mmu)<<3))
+#define REG_MMU_INT_ID(mmu)           (0x150+((mmu)<<2))
+#define F_MMU0_INT_ID_TF_MSK          (~0x3)	/* only for MM iommu. */
+
+#define MTK_TFID(larbid, portid) ((larbid << 7) | (portid << 2))
+
+static const struct mtk_iommu_port mtk_iommu_mt8173_port[] = {
+	/* port name                m4uid slaveid larbid portid tfid */
+	/* larb0 */
+	{"M4U_PORT_DISP_OVL0",          0,  0,    0,  0, MTK_TFID(0, 0)},
+	{"M4U_PORT_DISP_RDMA0",         0,  0,    0,  1, MTK_TFID(0, 1)},
+	{"M4U_PORT_DISP_WDMA0",         0,  0,    0,  2, MTK_TFID(0, 2)},
+	{"M4U_PORT_DISP_OD_R",          0,  0,    0,  3, MTK_TFID(0, 3)},
+	{"M4U_PORT_DISP_OD_W",          0,  0,    0,  4, MTK_TFID(0, 4)},
+	{"M4U_PORT_MDP_RDMA0",          0,  0,    0,  5, MTK_TFID(0, 5)},
+	{"M4U_PORT_MDP_WDMA",           0,  0,    0,  6, MTK_TFID(0, 6)},
+	{"M4U_PORT_MDP_WROT0",          0,  0,    0,  7, MTK_TFID(0, 7)},
+
+	/* larb1 */
+	{"M4U_PORT_HW_VDEC_MC_EXT",      0,  0,   1,  0, MTK_TFID(1, 0)},
+	{"M4U_PORT_HW_VDEC_PP_EXT",      0,  0,   1,  1, MTK_TFID(1, 1)},
+	{"M4U_PORT_HW_VDEC_UFO_EXT",     0,  0,   1,  2, MTK_TFID(1, 2)},
+	{"M4U_PORT_HW_VDEC_VLD_EXT",     0,  0,   1,  3, MTK_TFID(1, 3)},
+	{"M4U_PORT_HW_VDEC_VLD2_EXT",    0,  0,   1,  4, MTK_TFID(1, 4)},
+	{"M4U_PORT_HW_VDEC_AVC_MV_EXT",  0,  0,   1,  5, MTK_TFID(1, 5)},
+	{"M4U_PORT_HW_VDEC_PRED_RD_EXT", 0,  0,   1,  6, MTK_TFID(1, 6)},
+	{"M4U_PORT_HW_VDEC_PRED_WR_EXT", 0,  0,   1,  7, MTK_TFID(1, 7)},
+	{"M4U_PORT_HW_VDEC_PPWRAP_EXT",  0,  0,   1,  8, MTK_TFID(1, 8)},
+
+	/* larb2 */
+	{"M4U_PORT_IMGO",                0,  0,    2,  0, MTK_TFID(2, 0)},
+	{"M4U_PORT_RRZO",                0,  0,    2,  1, MTK_TFID(2, 1)},
+	{"M4U_PORT_AAO",                 0,  0,    2,  2, MTK_TFID(2, 2)},
+	{"M4U_PORT_LCSO",                0,  0,    2,  3, MTK_TFID(2, 3)},
+	{"M4U_PORT_ESFKO",               0,  0,    2,  4, MTK_TFID(2, 4)},
+	{"M4U_PORT_IMGO_D",              0,  0,    2,  5, MTK_TFID(2, 5)},
+	{"M4U_PORT_LSCI",                0,  0,    2,  6, MTK_TFID(2, 6)},
+	{"M4U_PORT_LSCI_D",              0,  0,    2,  7, MTK_TFID(2, 7)},
+	{"M4U_PORT_BPCI",                0,  0,    2,  8, MTK_TFID(2, 8)},
+	{"M4U_PORT_BPCI_D",              0,  0,    2,  9, MTK_TFID(2, 9)},
+	{"M4U_PORT_UFDI",                0,  0,    2,  10, MTK_TFID(2, 10)},
+	{"M4U_PORT_IMGI",                0,  0,    2,  11, MTK_TFID(2, 11)},
+	{"M4U_PORT_IMG2O",               0,  0,    2,  12, MTK_TFID(2, 12)},
+	{"M4U_PORT_IMG3O",               0,  0,    2,  13, MTK_TFID(2, 13)},
+	{"M4U_PORT_VIPI",                0,  0,    2,  14, MTK_TFID(2, 14)},
+	{"M4U_PORT_VIP2I",               0,  0,    2,  15, MTK_TFID(2, 15)},
+	{"M4U_PORT_VIP3I",               0,  0,    2,  16, MTK_TFID(2, 16)},
+	{"M4U_PORT_LCEI",                0,  0,    2,  17, MTK_TFID(2, 17)},
+	{"M4U_PORT_RB",                  0,  0,    2,  18, MTK_TFID(2, 18)},
+	{"M4U_PORT_RP",                  0,  0,    2,  19, MTK_TFID(2, 19)},
+	{"M4U_PORT_WR",                  0,  0,    2,  20, MTK_TFID(2, 20)},
+
+	/* larb3 */
+	{"M4U_PORT_VENC_RCPU",            0,  0,   3,  0, MTK_TFID(3, 0)},
+	{"M4U_PORT_VENC_REC",             0,  0,   3,  1, MTK_TFID(3, 1)},
+	{"M4U_PORT_VENC_BSDMA",           0,  0,   3,  2, MTK_TFID(3, 2)},
+	{"M4U_PORT_VENC_SV_COMV",         0,  0,   3,  3, MTK_TFID(3, 3)},
+	{"M4U_PORT_VENC_RD_COMV",         0,  0,   3,  4, MTK_TFID(3, 4)},
+	{"M4U_PORT_JPGENC_RDMA",          0,  0,   3,  5, MTK_TFID(3, 5)},
+	{"M4U_PORT_JPGENC_BSDMA",         0,  0,   3,  6, MTK_TFID(3, 6)},
+	{"M4U_PORT_JPGDEC_WDMA",          0,  0,   3,  7, MTK_TFID(3, 7)},
+	{"M4U_PORT_JPGDEC_BSDMA",         0,  0,   3,  8, MTK_TFID(3, 8)},
+	{"M4U_PORT_VENC_CUR_LUMA",        0,  0,   3,  9, MTK_TFID(3, 9)},
+	{"M4U_PORT_VENC_CUR_CHROMA",      0,  0,   3,  10, MTK_TFID(3, 10)},
+	{"M4U_PORT_VENC_REF_LUMA",        0,  0,   3,  11, MTK_TFID(3, 11)},
+	{"M4U_PORT_VENC_REF_CHROMA",      0,  0,   3,  12, MTK_TFID(3, 12)},
+	{"M4U_PORT_VENC_NBM_RDMA",        0,  0,   3,  13, MTK_TFID(3, 13)},
+	{"M4U_PORT_VENC_NBM_WDMA",        0,  0,   3,  14, MTK_TFID(3, 14)},
+
+	/* larb4 */
+	{"M4U_PORT_DISP_OVL1",             0,  0,   4,  0, MTK_TFID(4, 0)},
+	{"M4U_PORT_DISP_RDMA1",            0,  0,   4,  1, MTK_TFID(4, 1)},
+	{"M4U_PORT_DISP_RDMA2",            0,  0,   4,  2, MTK_TFID(4, 2)},
+	{"M4U_PORT_DISP_WDMA1",            0,  0,   4,  3, MTK_TFID(4, 3)},
+	{"M4U_PORT_MDP_RDMA1",             0,  0,   4,  4, MTK_TFID(4, 4)},
+	{"M4U_PORT_MDP_WROT1",             0,  0,   4,  5, MTK_TFID(4, 5)},
+
+	/* larb5 */
+	{"M4U_PORT_VENC_RCPU_SET2",        0,  0,    5,  0, MTK_TFID(5, 0)},
+	{"M4U_PORT_VENC_REC_FRM_SET2",     0,  0,    5,  1, MTK_TFID(5, 1)},
+	{"M4U_PORT_VENC_REF_LUMA_SET2",    0,  0,    5,  2, MTK_TFID(5, 2)},
+	{"M4U_PORT_VENC_REC_CHROMA_SET2",  0,  0,    5,  3, MTK_TFID(5, 3)},
+	{"M4U_PORT_VENC_BSDMA_SET2",       0,  0,    5,  4, MTK_TFID(5, 4)},
+	{"M4U_PORT_VENC_CUR_LUMA_SET2",    0,  0,    5,  5, MTK_TFID(5, 5)},
+	{"M4U_PORT_VENC_CUR_CHROMA_SET2",  0,  0,    5,  6, MTK_TFID(5, 6)},
+	{"M4U_PORT_VENC_RD_COMA_SET2",     0,  0,    5,  7, MTK_TFID(5, 7)},
+	{"M4U_PORT_VENC_SV_COMA_SET2",     0,  0,    5,  8, MTK_TFID(5, 8)},
+
+	/* perisys iommu */
+	{"M4U_PORT_RESERVE",               1,  0,    6,  0, 0xff},
+	{"M4U_PORT_SPM",                   1,  0,    6,  1, 0x50},
+	{"M4U_PORT_MD32",                  1,  0,    6,  2, 0x90},
+	{"M4U_PORT_PTP_THERM",             1,  0,    6,  4, 0xd0},
+	{"M4U_PORT_PWM",                   1,  0,    6,  5, 0x1},
+	{"M4U_PORT_MSDC1",                 1,  0,    6,  6, 0x21},
+	{"M4U_PORT_MSDC2",                 1,  0,    6,  7, 0x41},
+	{"M4U_PORT_NFI",                   1,  0,    6,  8, 0x8},
+	{"M4U_PORT_AUDIO",                 1,  0,    6,  9, 0x48},
+	{"M4U_PORT_RESERVED2",             1,  0,    6,  10, 0xfe},
+	{"M4U_PORT_HSIC_XHCI",             1,  0,    6,  11, 0x9},
+
+	{"M4U_PORT_HSIC_MAS",              1,  0,    6,  12, 0x11},
+	{"M4U_PORT_HSIC_DEV",              1,  0,    6,  13, 0x19},
+	{"M4U_PORT_AP_DMA",                1,  0,    6,  14, 0x18},
+	{"M4U_PORT_HSIC_DMA",              1,  0,    6,  15, 0xc8},
+	{"M4U_PORT_MSDC0",                 1,  0,    6,  16, 0x0},
+	{"M4U_PORT_MSDC3",                 1,  0,    6,  17, 0x20},
+	{"M4U_PORT_UNKNOWN",               1,  0,    6,  18, 0xf},
+};
+
+static const struct mtk_iommu_cfg mtk_iommu_mt8173_cfg = {
+	.larb_nr = 6,
+	.m4u_port_nr = ARRAY_SIZE(mtk_iommu_mt8173_port),
+	.pport = mtk_iommu_mt8173_port,
+};
+
+static const char *mtk_iommu_get_port_name(const struct mtk_iommu_info *piommu,
+					   unsigned int portid)
+{
+	const struct mtk_iommu_port *pcurport = NULL;
+
+	pcurport = piommu->imucfg->pport + portid;
+	if (portid < piommu->imucfg->m4u_port_nr && pcurport)
+		return pcurport->port_name;
+	else
+		return "UNKNOWN_PORT";
+}
+
+static int mtk_iommu_get_port_by_tfid(const struct mtk_iommu_info *pimu,
+				      int tf_id)
+{
+	const struct mtk_iommu_cfg *pimucfg = pimu->imucfg;
+	int i;
+	unsigned int portid = pimucfg->m4u_port_nr;
+
+	for (i = 0; i < pimucfg->m4u_port_nr; i++) {
+		if (pimucfg->pport[i].tf_id == tf_id) {
+			portid = i;
+			break;
+		}
+	}
+	if (i == pimucfg->m4u_port_nr)
+		dev_err(pimu->dev, "tf_id find fail, tfid %d\n", tf_id);
+	return portid;
+}
+
+static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
+{
+	struct iommu_domain *domain = dev_id;
+	struct mtk_iommu_domain *mtkdomain = domain->priv;
+	struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
+
+	if (irq == piommu->irq)
+		report_iommu_fault(domain, piommu->dev, 0, 0);
+	else
+		dev_err(piommu->dev, "irq number:%d\n", irq);
+
+	return IRQ_HANDLED;
+}
+
+static inline void mtk_iommu_clear_intr(void __iomem *m4u_base)
+{
+	u32 val;
+
+	val = readl(m4u_base + REG_MMU_INT_L2_CONTROL);
+	val |= F_INT_L2_CLR_BIT;
+	writel(val, m4u_base + REG_MMU_INT_L2_CONTROL);
+}
+
+static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
+				    int isinvall, unsigned int iova_start,
+				    unsigned int iova_end)
+{
+	void __iomem *m4u_base = piommu->m4u_base;
+	u32 val;
+	u64 start, end;
+
+	start = sched_clock();
+
+	if (!isinvall) {
+		iova_start = round_down(iova_start, SZ_4K);
+		iova_end = round_up(iova_end, SZ_4K);
+	}
+
+	val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
+
+	writel(val, m4u_base + REG_INVLID_SEL);
+
+	if (isinvall) {
+		writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
+	} else {
+		writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
+		writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
+		writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
+
+		while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
+			end = sched_clock();
+			if (end - start >= 100000000ULL) {
+				dev_warn(piommu->dev, "invalid don't done\n");
+				writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
+			}
+		};
+		writel(0, m4u_base + REG_MMU_CPE_DONE);
+	}
+
+	return 0;
+}
+
+static int mtk_iommu_fault_handler(struct iommu_domain *imudomain,
+				   struct device *dev, unsigned long iova,
+				   int m4uindex, void *pimu)
+{
+	void __iomem *m4u_base;
+	u32 int_state, regval;
+	int m4u_slave_id = 0;
+	unsigned int layer, write, m4u_port;
+	unsigned int fault_mva, fault_pa;
+	struct mtk_iommu_info *piommu = pimu;
+	struct mtk_iommu_domain *mtkdomain = imudomain->priv;
+
+	m4u_base = piommu->m4u_base;
+	int_state = readl(m4u_base + REG_MMU_MAIN_FAULT_ST);
+
+	/* read error info from registers */
+	fault_mva = readl(m4u_base + REG_MMU_FAULT_VA(m4u_slave_id));
+	layer = !!(fault_mva & F_MMU_FAULT_VA_LAYER_BIT);
+	write = !!(fault_mva & F_MMU_FAULT_VA_WRITE_BIT);
+	fault_mva &= F_MMU_FAULT_VA_MSK;
+	fault_pa = readl(m4u_base + REG_MMU_INVLD_PA(m4u_slave_id));
+	regval = readl(m4u_base + REG_MMU_INT_ID(m4u_slave_id));
+	regval &= F_MMU0_INT_ID_TF_MSK;
+	m4u_port = mtk_iommu_get_port_by_tfid(piommu, regval);
+
+	if (int_state & F_INT_TRANSLATION_FAULT(m4u_slave_id)) {
+		struct m4u_pte_info_t pte;
+		unsigned long flags;
+
+		spin_lock_irqsave(&mtkdomain->pgtlock, flags);
+		m4u_get_pte_info(mtkdomain, fault_mva, &pte);
+		spin_unlock_irqrestore(&mtkdomain->pgtlock, flags);
+
+		if (pte.size == MMU_SMALL_PAGE_SIZE ||
+		    pte.size == MMU_LARGE_PAGE_SIZE) {
+			dev_err_ratelimited(
+				dev,
+				"fault:port=%s iova=0x%x pa=0x%x layer=%d %s;"
+				"pgd(0x%x)->pte(0x%x)->pa(%pad)sz(0x%x)Valid(%d)\n",
+				mtk_iommu_get_port_name(piommu, m4u_port),
+				fault_mva, fault_pa, layer,
+				write ? "write" : "read",
+				imu_pgd_val(*pte.pgd), imu_pte_val(*pte.pte),
+				&pte.pa, pte.size, pte.valid);
+		} else {
+			dev_err_ratelimited(
+				dev,
+				"fault:port=%s iova=0x%x pa=0x%x layer=%d %s;"
+				"pgd(0x%x)->pa(%pad)sz(0x%x)Valid(%d)\n",
+				mtk_iommu_get_port_name(piommu, m4u_port),
+				fault_mva, fault_pa, layer,
+				write ? "write" : "read",
+				imu_pgd_val(*pte.pgd),
+				&pte.pa, pte.size, pte.valid);
+		}
+	}
+
+	if (int_state & F_INT_MAIN_MULTI_HIT_FAULT(m4u_slave_id))
+		dev_err_ratelimited(dev, "multi-hit!port=%s iova=0x%x\n",
+				    mtk_iommu_get_port_name(piommu, m4u_port),
+				    fault_mva);
+
+	if (int_state & F_INT_INVALID_PA_FAULT(m4u_slave_id)) {
+		if (!(int_state & F_INT_TRANSLATION_FAULT(m4u_slave_id)))
+			dev_err_ratelimited(dev, "invalid pa!port=%s iova=0x%x\n",
+					    mtk_iommu_get_port_name(piommu,
+								    m4u_port),
+					    fault_mva);
+	}
+	if (int_state & F_INT_ENTRY_REPLACEMENT_FAULT(m4u_slave_id))
+		dev_err_ratelimited(dev, "replace-fault!port=%s iova=0x%x\n",
+				    mtk_iommu_get_port_name(piommu, m4u_port),
+				    fault_mva);
+
+	if (int_state & F_INT_TLB_MISS_FAULT(m4u_slave_id))
+		dev_err_ratelimited(dev, "tlb miss-fault!port=%s iova=0x%x\n",
+				    mtk_iommu_get_port_name(piommu, m4u_port),
+				    fault_mva);
+
+	mtk_iommu_invalidate_tlb(piommu, 1, 0, 0);
+
+	mtk_iommu_clear_intr(m4u_base);
+
+	return 0;
+}
+
+static int mtk_iommu_parse_dt(struct platform_device *pdev,
+			      struct mtk_iommu_info *piommu)
+{
+	struct device *piommudev = &pdev->dev;
+	struct device_node *ofnode;
+	struct resource *res;
+	unsigned int mtk_iommu_cell = 0;
+	unsigned int i;
+
+	ofnode = piommudev->of_node;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	piommu->m4u_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(piommu->m4u_base)) {
+		dev_err(piommudev, "m4u_base %p err\n", piommu->m4u_base);
+		goto iommu_dts_err;
+	}
+
+	piommu->irq = platform_get_irq(pdev, 0);
+	if (piommu->irq < 0) {
+		dev_err(piommudev, "irq err %d\n", piommu->irq);
+		goto iommu_dts_err;
+	}
+
+	piommu->m4u_infra_clk = devm_clk_get(piommudev, "infra_m4u");
+	if (IS_ERR(piommu->m4u_infra_clk)) {
+		dev_err(piommudev, "clk err %p\n", piommu->m4u_infra_clk);
+		goto iommu_dts_err;
+	}
+
+	of_property_read_u32(ofnode, "#iommu-cells", &mtk_iommu_cell);
+	if (mtk_iommu_cell != 1) {
+		dev_err(piommudev, "iommu-cell fail:%d\n", mtk_iommu_cell);
+		goto iommu_dts_err;
+	}
+
+	for (i = 0; i < piommu->imucfg->larb_nr; i++) {
+		struct device_node *larbnode;
+
+		larbnode = of_parse_phandle(ofnode, "larb", i);
+		piommu->larbpdev[i] = of_find_device_by_node(larbnode);
+		of_node_put(larbnode);
+		if (!piommu->larbpdev[i]) {
+			dev_err(piommudev, "larb pdev fail@larb%d\n", i);
+			goto iommu_dts_err;
+		}
+	}
+
+	return 0;
+
+iommu_dts_err:
+	return -EINVAL;
+}
+
+static int mtk_iommu_hw_init(const struct mtk_iommu_domain *mtkdomain)
+{
+	struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
+	void __iomem *gm4ubaseaddr = piommu->m4u_base;
+	phys_addr_t protectpa;
+	u32 regval, protectreg;
+	int ret = 0;
+
+	ret = clk_prepare_enable(piommu->m4u_infra_clk);
+	if (ret) {
+		dev_err(piommu->dev, "m4u clk enable error\n");
+		return -ENODEV;
+	}
+
+	writel((u32)mtkdomain->pgd_pa, gm4ubaseaddr + REG_MMUG_PT_BASE);
+
+	regval = F_MMU_CTRL_REROUTE_PFQ_TO_MQ_EN |
+		F_MMU_CTRL_TF_PROT_VAL(2) |
+		F_MMU_CTRL_COHERE_EN;
+	writel(regval, gm4ubaseaddr + REG_MMU_CTRL_REG);
+
+	writel(0x6f, gm4ubaseaddr + REG_MMU_INT_L2_CONTROL);
+	writel(0xffffffff, gm4ubaseaddr + REG_MMU_INT_MAIN_CONTROL);
+
+	/* protect memory,HW will write here while translation fault */
+	protectpa = __virt_to_phys(piommu->protect_va);
+	protectpa = ALIGN(protectpa, MTK_PROTECT_PA_ALIGN);
+	protectreg = (u32)F_MMU_IVRP_PA_SET(protectpa);
+	writel(protectreg, gm4ubaseaddr + REG_MMU_IVRP_PADDR);
+
+	writel(0, gm4ubaseaddr + REG_MMU_DCM_DIS);
+	writel(0, gm4ubaseaddr + REG_MMU_STANDARD_AXI_MODE);
+
+	return 0;
+}
+
+static inline void mtk_iommu_config_port(struct mtk_iommu_info *piommu,
+					 int portid)
+{
+	int larb, larb_port;
+
+	larb = piommu->imucfg->pport[portid].larb_id;
+	larb_port = piommu->imucfg->pport[portid].port_id;
+
+	mtk_smi_config_port(piommu->larbpdev[larb], larb_port);
+}
+
+/*
+ * pimudev is a global var for dma_alloc_coherent.
+ * It is not accepatable, we will delete it if "domain_alloc" is enabled
+ */
+static struct device *pimudev;
+
+static int mtk_iommu_domain_init(struct iommu_domain *domain)
+{
+	struct mtk_iommu_domain *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->pgd = dma_alloc_coherent(pimudev, M4U_PGD_SIZE, &priv->pgd_pa,
+				       GFP_KERNEL);
+	if (!priv->pgd) {
+		pr_err("dma_alloc_coherent pagetable fail\n");
+		goto err_pgtable;
+	}
+
+	if (!IS_ALIGNED(priv->pgd_pa, M4U_PGD_SIZE)) {
+		pr_err("pagetable not aligned pa 0x%pad-0x%p align 0x%x\n",
+		       &priv->pgd_pa, priv->pgd, M4U_PGD_SIZE);
+		goto err_pgtable;
+	}
+
+	memset(priv->pgd, 0, M4U_PGD_SIZE);
+
+	spin_lock_init(&priv->pgtlock);
+	spin_lock_init(&priv->portlock);
+	domain->priv = priv;
+
+	domain->geometry.aperture_start = 0;
+	domain->geometry.aperture_end   = (unsigned int)~0;
+	domain->geometry.force_aperture = true;
+
+	return 0;
+
+err_pgtable:
+	if (priv->pgd)
+		dma_free_coherent(pimudev, M4U_PGD_SIZE, priv->pgd,
+				  priv->pgd_pa);
+	kfree(priv);
+	return -ENOMEM;
+}
+
+static void mtk_iommu_domain_destroy(struct iommu_domain *domain)
+{
+	struct mtk_iommu_domain *priv = domain->priv;
+
+	dma_free_coherent(priv->piommuinfo->dev, M4U_PGD_SIZE,
+			  priv->pgd, priv->pgd_pa);
+	kfree(domain->priv);
+	domain->priv = NULL;
+}
+
+static int mtk_iommu_attach_device(struct iommu_domain *domain,
+				   struct device *dev)
+{
+	unsigned long flags;
+	struct mtk_iommu_domain *priv = domain->priv;
+	struct mtk_iommu_info *piommu = priv->piommuinfo;
+	struct of_phandle_args out_args = {0};
+	struct device *imudev;
+	unsigned int i = 0;
+
+	if (!piommu)
+		goto imudev;
+	else
+		imudev = piommu->dev;
+
+	spin_lock_irqsave(&priv->portlock, flags);
+
+	while (!of_parse_phandle_with_args(dev->of_node, "iommus",
+					   "#iommu-cells", i, &out_args)) {
+		if (1 == out_args.args_count) {
+			unsigned int portid = out_args.args[0];
+
+			dev_dbg(dev, "iommu add port:%d\n", portid);
+
+			mtk_iommu_config_port(piommu, portid);
+
+			if (i == 0)
+				dev->archdata.dma_ops =
+					piommu->dev->archdata.dma_ops;
+		}
+		i++;
+	}
+
+	spin_unlock_irqrestore(&priv->portlock, flags);
+
+imudev:
+	return 0;
+}
+
+static void mtk_iommu_detach_device(struct iommu_domain *domain,
+				    struct device *dev)
+{
+}
+
+static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
+			 phys_addr_t paddr, size_t size, int prot)
+{
+	struct mtk_iommu_domain *priv = domain->priv;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&priv->pgtlock, flags);
+	ret = m4u_map(priv, (unsigned int)iova, paddr, size, prot);
+	mtk_iommu_invalidate_tlb(priv->piommuinfo, 0,
+				 iova, iova + size - 1);
+	spin_unlock_irqrestore(&priv->pgtlock, flags);
+
+	return ret;
+}
+
+static size_t mtk_iommu_unmap(struct iommu_domain *domain,
+			      unsigned long iova, size_t size)
+{
+	struct mtk_iommu_domain *priv = domain->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->pgtlock, flags);
+	m4u_unmap(priv, (unsigned int)iova, size);
+	mtk_iommu_invalidate_tlb(priv->piommuinfo, 0,
+				 iova, iova + size - 1);
+	spin_unlock_irqrestore(&priv->pgtlock, flags);
+
+	return size;
+}
+
+static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
+					  dma_addr_t iova)
+{
+	struct mtk_iommu_domain *priv = domain->priv;
+	unsigned long flags;
+	struct m4u_pte_info_t pte;
+
+	spin_lock_irqsave(&priv->pgtlock, flags);
+	m4u_get_pte_info(priv, (unsigned int)iova, &pte);
+	spin_unlock_irqrestore(&priv->pgtlock, flags);
+
+	return pte.pa;
+}
+
+static struct iommu_ops mtk_iommu_ops = {
+	.domain_init = mtk_iommu_domain_init,
+	.domain_destroy = mtk_iommu_domain_destroy,
+	.attach_dev = mtk_iommu_attach_device,
+	.detach_dev = mtk_iommu_detach_device,
+	.map = mtk_iommu_map,
+	.unmap = mtk_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.iova_to_phys = mtk_iommu_iova_to_phys,
+	.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
+};
+
+static const struct of_device_id mtk_iommu_of_ids[] = {
+	{ .compatible = "mediatek,mt8173-iommu",
+	  .data = &mtk_iommu_mt8173_cfg,
+	},
+	{}
+};
+
+static int mtk_iommu_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct iommu_domain *domain;
+	struct mtk_iommu_domain *mtk_domain;
+	struct mtk_iommu_info *piommu;
+	struct iommu_dma_domain  *dom;
+	const struct of_device_id *of_id;
+
+	piommu = devm_kzalloc(&pdev->dev, sizeof(struct mtk_iommu_info),
+			      GFP_KERNEL);
+	if (!piommu)
+		return -ENOMEM;
+
+	pimudev = &pdev->dev;
+	piommu->dev = &pdev->dev;
+
+	of_id = of_match_node(mtk_iommu_of_ids, pdev->dev.of_node);
+	if (!of_id)
+		return -ENODEV;
+
+	piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
+					  GFP_KERNEL);
+	if (!piommu->protect_va)
+		goto protect_err;
+	memset(piommu->protect_va, 0x55, MTK_PROTECT_PA_ALIGN*2);
+
+	piommu->imucfg = (const struct mtk_iommu_cfg *)of_id->data;
+
+	ret = mtk_iommu_parse_dt(pdev, piommu);
+	if (ret) {
+		dev_err(piommu->dev, "iommu dt parse fail\n");
+		goto protect_err;
+	}
+
+	/* alloc memcache for level-2 pgt */
+	piommu->m4u_pte_kmem = kmem_cache_create("m4u_pte", IMU_BYTES_PER_PTE,
+						 IMU_BYTES_PER_PTE, 0, NULL);
+
+	if (IS_ERR_OR_NULL(piommu->m4u_pte_kmem)) {
+		dev_err(piommu->dev, "pte cached create fail %p\n",
+			piommu->m4u_pte_kmem);
+		goto protect_err;
+	}
+
+	arch_setup_dma_ops(piommu->dev, 0, (1ULL<<32) - 1, &mtk_iommu_ops, 0);
+
+	dom = get_dma_domain(piommu->dev);
+	domain = iommu_dma_raw_domain(dom);
+
+	mtk_domain = domain->priv;
+	mtk_domain->piommuinfo = piommu;
+
+	if (!domain)
+		goto pte_err;
+
+	ret = mtk_iommu_hw_init(mtk_domain);
+	if (ret < 0)
+		goto hw_err;
+
+	if (devm_request_irq(piommu->dev, piommu->irq,
+			     mtk_iommu_isr, IRQF_TRIGGER_NONE,
+			     "mtkiommu", (void *)domain)) {
+		dev_err(piommu->dev, "IRQ request %d failed\n",
+			piommu->irq);
+		goto hw_err;
+	}
+
+	iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);
+
+	dev_set_drvdata(piommu->dev, piommu);
+
+	return 0;
+hw_err:
+	arch_teardown_dma_ops(piommu->dev);
+pte_err:
+	kmem_cache_destroy(piommu->m4u_pte_kmem);
+protect_err:
+	dev_err(piommu->dev, "probe error\n");
+	return 0;
+}
+
+static int mtk_iommu_remove(struct platform_device *pdev)
+{
+	struct mtk_iommu_info *piommu =	dev_get_drvdata(&pdev->dev);
+
+	arch_teardown_dma_ops(piommu->dev);
+	kmem_cache_destroy(piommu->m4u_pte_kmem);
+
+	return 0;
+}
+
+static struct platform_driver mtk_iommu_driver = {
+	.probe	= mtk_iommu_probe,
+	.remove	= mtk_iommu_remove,
+	.driver	= {
+		.name = "mtkiommu",
+		.of_match_table = mtk_iommu_of_ids,
+	}
+};
+
+static int __init mtk_iommu_init(void)
+{
+	return platform_driver_register(&mtk_iommu_driver);
+}
+
+subsys_initcall(mtk_iommu_init);
+
diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h
new file mode 100644
index 0000000..239471f
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MTK_IOMMU_PLATFORM_H
+#define MTK_IOMMU_PLATFORM_H
+
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+
+#include "mtk_iommu_pagetable.h"
+
+#define M4U_PGD_SIZE       SZ_16K   /* pagetable size,mt8173 */
+
+#define MTK_PROTECT_PA_ALIGN  128
+
+#define MTK_IOMMU_LARB_MAX_NR 8
+#define MTK_IOMMU_PORT_MAX_NR 100
+
+struct mtk_iommu_port {
+	const char *port_name;
+	unsigned int m4u_id:2;
+	unsigned int m4u_slave:2;/* main tlb index in mm iommu */
+	unsigned int larb_id:4;
+	unsigned int port_id:8;/* port id in larb */
+	unsigned int tf_id:16; /* translation fault id */
+};
+
+struct mtk_iommu_cfg {
+	unsigned int larb_nr;
+	unsigned int m4u_port_nr;
+	const struct mtk_iommu_port *pport;
+};
+
+struct mtk_iommu_info {
+	void __iomem *m4u_base;
+	unsigned int  irq;
+	struct platform_device *larbpdev[MTK_IOMMU_LARB_MAX_NR];
+	struct clk *m4u_infra_clk;
+	void __iomem *protect_va;
+	struct device *dev;
+	struct kmem_cache *m4u_pte_kmem;
+	const struct mtk_iommu_cfg *imucfg;
+};
+
+struct mtk_iommu_domain {
+	struct imu_pgd_t *pgd;
+	dma_addr_t pgd_pa;
+	spinlock_t pgtlock;	/* lock for modifying page table */
+	spinlock_t portlock;    /* lock for config port */
+	struct mtk_iommu_info *piommuinfo;
+};
+
+int m4u_map(struct mtk_iommu_domain *m4u_domain, unsigned int iova,
+	    phys_addr_t paddr, unsigned int size, unsigned int prot);
+int m4u_unmap(struct mtk_iommu_domain *domain, unsigned int iova,
+	      unsigned int size);
+int m4u_get_pte_info(const struct mtk_iommu_domain *domain,
+		     unsigned int iova, struct m4u_pte_info_t *pte_info);
+
+#endif
diff --git a/drivers/iommu/mtk_iommu_pagetable.c b/drivers/iommu/mtk_iommu_pagetable.c
new file mode 100644
index 0000000..5fe9640
--- /dev/null
+++ b/drivers/iommu/mtk_iommu_pagetable.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/iommu.h>
+#include <linux/errno.h>
+#include "asm/cacheflush.h"
+
+#include "mtk_iommu.h"
+#include "mtk_iommu_pagetable.h"
+
+/* 2 level pagetable: pgd -> pte */
+#define F_PTE_TYPE_GET(regval)  (regval & 0x3)
+#define F_PTE_TYPE_LARGE         BIT(0)
+#define F_PTE_TYPE_SMALL         BIT(1)
+#define F_PTE_B_BIT              BIT(2)
+#define F_PTE_C_BIT              BIT(3)
+#define F_PTE_BIT32_BIT          BIT(9)
+#define F_PTE_S_BIT              BIT(10)
+#define F_PTE_NG_BIT             BIT(11)
+#define F_PTE_PA_LARGE_MSK            (~0UL << 16)
+#define F_PTE_PA_LARGE_GET(regval)    ((regval >> 16) & 0xffff)
+#define F_PTE_PA_SMALL_MSK            (~0UL << 12)
+#define F_PTE_PA_SMALL_GET(regval)    ((regval >> 12) & (~0))
+#define F_PTE_TYPE_IS_LARGE_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
+					F_PTE_TYPE_LARGE)
+#define F_PTE_TYPE_IS_SMALL_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
+					F_PTE_TYPE_SMALL)
+
+#define F_PGD_TYPE_PAGE         (0x1)
+#define F_PGD_TYPE_PAGE_MSK     (0x3)
+#define F_PGD_TYPE_SECTION      (0x2)
+#define F_PGD_TYPE_SUPERSECTION   (0x2 | (1 << 18))
+#define F_PGD_TYPE_SECTION_MSK    (0x3 | (1 << 18))
+#define F_PGD_TYPE_IS_PAGE(pgd)   ((imu_pgd_val(pgd)&3) == 1)
+#define F_PGD_TYPE_IS_SECTION(pgd) \
+	(F_PGD_TYPE_IS_PAGE(pgd) ? 0 : \
+		((imu_pgd_val(pgd) & F_PGD_TYPE_SECTION_MSK) == \
+			F_PGD_TYPE_SECTION))
+#define F_PGD_TYPE_IS_SUPERSECTION(pgd) \
+	(F_PGD_TYPE_IS_PAGE(pgd) ? 0 : \
+		((imu_pgd_val(pgd) & F_PGD_TYPE_SECTION_MSK) ==\
+			F_PGD_TYPE_SUPERSECTION))
+
+#define F_PGD_B_BIT                     BIT(2)
+#define F_PGD_C_BIT                     BIT(3)
+#define F_PGD_BIT32_BIT                 BIT(9)
+#define F_PGD_S_BIT                     BIT(16)
+#define F_PGD_NG_BIT                    BIT(17)
+#define F_PGD_NS_BIT_PAGE(ns)           (ns << 3)
+#define F_PGD_NS_BIT_SECTION(ns)        (ns << 19)
+#define F_PGD_NS_BIT_SUPERSECTION(ns)   (ns << 19)
+
+#define imu_pgd_index(addr)		((addr) >> IMU_PGDIR_SHIFT)
+#define imu_pgd_offset(domain, addr) ((domain)->pgd + imu_pgd_index(addr))
+
+#define imu_pte_index(addr)    (((addr)>>IMU_PAGE_SHIFT)&(IMU_PTRS_PER_PTE - 1))
+#define imu_pte_offset_map(pgd, addr) (imu_pte_map(pgd) + imu_pte_index(addr))
+
+#define F_PGD_PA_PAGETABLE_MSK            (~0 << 10)
+#define F_PGD_PA_SECTION_MSK              (~0 << 20)
+#define F_PGD_PA_SUPERSECTION_MSK         (~0 << 24)
+
+static inline struct imu_pte_t *imu_pte_map(struct imu_pgd_t *pgd)
+{
+	unsigned int pte_pa = imu_pgd_val(*pgd);
+
+	return (struct imu_pte_t *)(__va(pte_pa
+					& F_PGD_PA_PAGETABLE_MSK));
+}
+
+static inline struct imu_pgd_t *imu_supersection_start(struct imu_pgd_t *pgd)
+{
+	return (struct imu_pgd_t *)(round_down((unsigned long)pgd, (16 * 4)));
+}
+
+static inline void m4u_set_pgd_val(struct imu_pgd_t *pgd, unsigned int val)
+{
+	imu_pgd_val(*pgd) = val;
+}
+
+static inline unsigned int __m4u_get_pgd_attr(unsigned int prot,
+					      bool super, bool imu4gmode)
+{
+	unsigned int pgprot;
+
+	pgprot = F_PGD_NS_BIT_SECTION(1) | F_PGD_S_BIT;
+	pgprot |= super ? F_PGD_TYPE_SUPERSECTION : F_PGD_TYPE_SECTION;
+	pgprot |= (prot & IOMMU_CACHE) ? (F_PGD_C_BIT | F_PGD_B_BIT) : 0;
+	pgprot |= imu4gmode ? F_PGD_BIT32_BIT : 0;
+
+	return pgprot;
+}
+
+static inline unsigned int __m4u_get_pte_attr(unsigned int prot,
+					      bool large, bool imu4gmode)
+{
+	unsigned int pgprot;
+
+	pgprot = F_PTE_S_BIT;
+	pgprot |= large ? F_PTE_TYPE_LARGE : F_PTE_TYPE_SMALL;
+	pgprot |= (prot & IOMMU_CACHE) ? (F_PGD_C_BIT | F_PGD_B_BIT) : 0;
+	pgprot |= imu4gmode ? F_PTE_BIT32_BIT : 0;
+
+	return pgprot;
+}
+
+static inline void m4u_pgtable_flush(void *vastart, void *vaend)
+{
+	/*
+	 * this function is not acceptable, we will use dma_map_single
+	 * or use dma_pool_create for the level2 pagetable.
+	 */
+	__dma_flush_range(vastart, vaend);
+}
+
+/* @return   0 -- pte is allocated
+ *     1 -- pte is not allocated, because it's allocated by others
+ *     <0 -- error
+ */
+static int m4u_alloc_pte(struct mtk_iommu_domain *domain, struct imu_pgd_t *pgd,
+			 unsigned int pgprot)
+{
+	void *pte_new_va;
+	phys_addr_t pte_new;
+	struct kmem_cache *pte_kmem = domain->piommuinfo->m4u_pte_kmem;
+	struct device *dev = domain->piommuinfo->dev;
+	unsigned int ret;
+
+	pte_new_va = kmem_cache_zalloc(pte_kmem, GFP_KERNEL);
+	if (unlikely(!pte_new_va)) {
+		dev_err(dev, "%s:fail, no memory\n", __func__);
+		return -ENOMEM;
+	}
+	pte_new = __virt_to_phys(pte_new_va);
+
+	/* check pte alignment -- must 1K align */
+	if (unlikely(pte_new & (IMU_BYTES_PER_PTE - 1))) {
+		dev_err(dev, "%s:fail, not align pa=0x%pa, va=0x%p\n",
+			__func__, &pte_new, pte_new_va);
+		kmem_cache_free(pte_kmem, (void *)pte_new_va);
+		return -ENOMEM;
+	}
+
+	/* because someone else may have allocated for this pgd first */
+	if (likely(!imu_pgd_val(*pgd))) {
+		m4u_set_pgd_val(pgd, (unsigned int)(pte_new) | pgprot);
+		dev_dbg(dev, "%s:pgd:0x%p,pte_va:0x%p,pte_pa:%pa,value:0x%x\n",
+			__func__, pgd, pte_new_va,
+			&pte_new, (unsigned int)(pte_new) | pgprot);
+		ret = 0;
+	} else {
+		/* allocated by other thread */
+		dev_dbg(dev, "m4u pte allocated by others: pgd=0x%p\n", pgd);
+		kmem_cache_free(pte_kmem, (void *)pte_new_va);
+		ret = 1;
+	}
+	return ret;
+}
+
+static int m4u_free_pte(struct mtk_iommu_domain *domain, struct imu_pgd_t *pgd)
+{
+	struct imu_pte_t *pte_old;
+	struct kmem_cache *pte_kmem = domain->piommuinfo->m4u_pte_kmem;
+
+	pte_old = imu_pte_map(pgd);
+	m4u_set_pgd_val(pgd, 0);
+
+	kmem_cache_free(pte_kmem, pte_old);
+
+	return 0;
+}
+
+static int m4u_map_page(struct mtk_iommu_domain *m4u_domain, unsigned int iova,
+			phys_addr_t pa, unsigned int prot, bool largepage)
+{
+	int ret;
+	struct imu_pgd_t *pgd;
+	struct imu_pte_t *pte;
+	unsigned int pte_new, pgprot;
+	unsigned int padscpt;
+	struct device *dev = m4u_domain->piommuinfo->dev;
+	unsigned int mask = largepage ?
+				F_PTE_PA_LARGE_MSK : F_PTE_PA_SMALL_MSK;
+	unsigned int i, ptenum = largepage ? 16 : 1;
+	bool imu4gmode = (pa > 0xffffffffL) ? true : false;
+
+	if ((iova & (~mask)) != ((unsigned int)pa & (~mask))) {
+		dev_err(dev, "error to mk_pte: iova=0x%x, pa=0x%pa, type=%s\n",
+			iova, &pa, largepage ? "large page" : "small page");
+		return -EINVAL;
+	}
+
+	iova &= mask;
+	padscpt = (unsigned int)pa & mask;
+
+	pgprot = F_PGD_TYPE_PAGE | F_PGD_NS_BIT_PAGE(1);
+	pgd = imu_pgd_offset(m4u_domain, iova);
+	if (!imu_pgd_val(*pgd)) {
+		ret = m4u_alloc_pte(m4u_domain, pgd, pgprot);
+		if (ret < 0)
+			return ret;
+		else if (ret > 0)
+			pte_new = 0;
+		else
+			pte_new = 1;
+	} else {
+		if ((imu_pgd_val(*pgd) & (~F_PGD_PA_PAGETABLE_MSK)) != pgprot) {
+			dev_err(dev, "%s: iova=0x%x, pgd=0x%x, pgprot=0x%x\n",
+				__func__, iova, imu_pgd_val(*pgd), pgprot);
+			return -1;
+		}
+		pte_new = 0;
+	}
+
+	pgprot = __m4u_get_pte_attr(prot, largepage, imu4gmode);
+	pte = imu_pte_offset_map(pgd, iova);
+
+	dev_dbg(dev, "%s:iova:0x%x,pte:0x%p(0x%p+0x%x),pa:%pa,value:0x%x-%s\n",
+		__func__, iova, &imu_pte_val(*pte), imu_pte_map(pgd),
+		imu_pte_index(iova), &pa, padscpt | pgprot,
+		largepage ? "large page" : "small page");
+
+	for (i = 0; i < ptenum; i++) {
+		if (imu_pte_val(pte[i])) {
+			dev_err(dev, "%s: pte=0x%x, i=%d\n", __func__,
+				imu_pte_val(pte[i]), i);
+			goto err_out;
+		}
+		imu_pte_val(pte[i]) = padscpt | pgprot;
+	}
+
+	m4u_pgtable_flush(pte, pte + ptenum);
+
+	return 0;
+
+ err_out:
+	for (i--; i >= 0; i--)
+		imu_pte_val(pte[i]) = 0;
+	return -EEXIST;
+}
+
+static int m4u_map_section(struct mtk_iommu_domain *m4u_domain,
+			   unsigned int iova, phys_addr_t pa,
+			   unsigned int prot, bool supersection)
+{
+	int i;
+	struct imu_pgd_t *pgd;
+	unsigned int pgprot;
+	unsigned int padscpt;
+	struct device *dev = m4u_domain->piommuinfo->dev;
+	unsigned int mask = supersection ?
+			F_PGD_PA_SUPERSECTION_MSK : F_PGD_PA_SECTION_MSK;
+	unsigned int pgdnum = supersection ? 16 : 1;
+	bool imu4gmode = (pa > 0xffffffffL) ? true : false;
+
+	if ((iova & (~mask)) != ((unsigned int)pa & (~mask))) {
+		dev_err(dev, "error to mk_pte: iova=0x%x, pa=0x%pa,type=%s\n",
+			iova, &pa, supersection ? "supersection" : "section");
+		return -EINVAL;
+	}
+
+	iova &= mask;
+	padscpt = (unsigned int)pa & mask;
+
+	pgprot = __m4u_get_pgd_attr(prot, supersection, imu4gmode);
+	pgd = imu_pgd_offset(m4u_domain, iova);
+
+	dev_dbg(dev, "%s:iova:0x%x,pgd:0x%p(0x%p+0x%x),pa:%pa,value:0x%x-%s\n",
+		__func__, iova, pgd, (m4u_domain)->pgd, imu_pgd_index(iova),
+		&pa, padscpt | pgprot,
+		supersection ? "supersection" : "section");
+
+	for (i = 0; i < pgdnum; i++) {
+		if (unlikely(imu_pgd_val(*pgd))) {
+			dev_err(dev, "%s:iova=0x%x, pgd=0x%x, i=%d\n", __func__,
+				iova, imu_pgd_val(*pgd), i);
+			goto err_out;
+		}
+		m4u_set_pgd_val(pgd, padscpt | pgprot);
+		pgd++;
+	}
+	return 0;
+
+ err_out:
+	for (pgd--; i > 0; i--) {
+		m4u_set_pgd_val(pgd, 0);
+		pgd--;
+	}
+	return -EEXIST;
+}
+
+int m4u_map(struct mtk_iommu_domain *m4u_domain, unsigned int iova,
+	    phys_addr_t paddr, unsigned int size, unsigned int prot)
+{
+	if (size == SZ_4K) {/* most case */
+		return m4u_map_page(m4u_domain, iova, paddr, prot, false);
+	} else if (size == SZ_64K) {
+		return m4u_map_page(m4u_domain, iova, paddr, prot, true);
+	} else if (size == SZ_1M) {
+		return m4u_map_section(m4u_domain, iova, paddr, prot, false);
+	} else if (size == SZ_16M) {
+		return m4u_map_section(m4u_domain, iova, paddr, prot, true);
+	} else {
+		return -EINVAL;
+	}
+}
+
+static int m4u_check_free_pte(struct mtk_iommu_domain *domain,
+			      struct imu_pgd_t *pgd)
+{
+	struct imu_pte_t *pte;
+	int i;
+
+	pte = imu_pte_map(pgd);
+	for (i = 0; i < IMU_PTRS_PER_PTE; i++, pte++) {
+		if (imu_pte_val(*pte) != 0)
+			return 1;
+	}
+
+	m4u_free_pte(domain, pgd);
+	return 0;
+}
+
+int m4u_unmap(struct mtk_iommu_domain *domain, unsigned int iova,
+	      unsigned int size)
+{
+	struct imu_pgd_t *pgd;
+	int i, ret;
+	unsigned long end_plus_1 = (unsigned long)iova + size;
+
+	do {
+		pgd = imu_pgd_offset(domain, iova);
+
+		if (F_PGD_TYPE_IS_PAGE(*pgd)) {
+			struct imu_pte_t *pte;
+			unsigned int pte_offset;
+			unsigned int num_to_clean;
+
+			pte_offset = imu_pte_index(iova);
+			num_to_clean =
+			    min((unsigned int)((end_plus_1 - iova) / PAGE_SIZE),
+				(unsigned int)(IMU_PTRS_PER_PTE - pte_offset));
+
+			pte = imu_pte_offset_map(pgd, iova);
+
+			memset(pte, 0, num_to_clean << 2);
+
+			ret = m4u_check_free_pte(domain, pgd);
+			if (ret == 1)/* pte is not freed, need to flush pte */
+				m4u_pgtable_flush(pte, pte + num_to_clean);
+
+			iova += num_to_clean << PAGE_SHIFT;
+		} else if (F_PGD_TYPE_IS_SECTION(*pgd)) {
+			m4u_set_pgd_val(pgd, 0);
+			iova += MMU_SECTION_SIZE;
+		} else if (F_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
+			struct imu_pgd_t *start = imu_supersection_start(pgd);
+
+			if (unlikely(start != pgd))
+				dev_err(domain->piommuinfo->dev,
+					"%s:supper not align,iova=0x%x,pgd=0x%x\n",
+					__func__, iova, imu_pgd_val(*pgd));
+
+			for (i = 0; i < 16; i++)
+				m4u_set_pgd_val((start+i), 0);
+
+			iova = (iova + MMU_SUPERSECTION_SIZE) &
+				(~(MMU_SUPERSECTION_SIZE - 1));
+		} else {
+			iova += MMU_SECTION_SIZE;
+		}
+	} while (iova < end_plus_1 && iova);
+
+	return 0;
+}
+
+int m4u_get_pte_info(const struct mtk_iommu_domain *domain, unsigned int iova,
+		     struct m4u_pte_info_t *pte_info)
+{
+	struct imu_pgd_t *pgd;
+	struct imu_pte_t *pte;
+	unsigned int pa = 0;
+	unsigned int size;
+	int valid = 1;
+
+	pgd = imu_pgd_offset(domain, iova);
+
+	if (F_PGD_TYPE_IS_PAGE(*pgd)) {
+		pte = imu_pte_offset_map(pgd, iova);
+		if (F_PTE_TYPE_GET(imu_pte_val(*pte)) == F_PTE_TYPE_LARGE) {
+			pa = imu_pte_val(*pte) & F_PTE_PA_LARGE_MSK;
+			pa |= iova & (~F_PTE_PA_LARGE_MSK);
+			size = MMU_LARGE_PAGE_SIZE;
+		} else if (F_PTE_TYPE_GET(imu_pte_val(*pte))
+			   == F_PTE_TYPE_SMALL) {
+			pa = imu_pte_val(*pte) & F_PTE_PA_SMALL_MSK;
+			pa |= iova & (~F_PTE_PA_SMALL_MSK);
+			size = MMU_SMALL_PAGE_SIZE;
+		} else {
+			valid = 0;
+			size = MMU_SMALL_PAGE_SIZE;
+		}
+	} else {
+		pte = NULL;
+		if (F_PGD_TYPE_IS_SECTION(*pgd)) {
+			pa = imu_pgd_val(*pgd) & F_PGD_PA_SECTION_MSK;
+			pa |= iova & (~F_PGD_PA_SECTION_MSK);
+			size = MMU_SECTION_SIZE;
+		} else if (F_PGD_TYPE_IS_SUPERSECTION(*pgd)) {
+			pa = imu_pgd_val(*pgd) & F_PGD_PA_SUPERSECTION_MSK;
+			pa |= iova & (~F_PGD_PA_SUPERSECTION_MSK);
+			size = MMU_SUPERSECTION_SIZE;
+		} else {
+			valid = 0;
+			size = MMU_SECTION_SIZE;
+		}
+	}
+
+	pte_info->pgd = pgd;
+	pte_info->pte = pte;
+	pte_info->iova = iova;
+	pte_info->pa = pa;
+	pte_info->size = size;
+	pte_info->valid = valid;
+	return 0;
+}
+
diff --git a/drivers/iommu/mtk_iommu_pagetable.h b/drivers/iommu/mtk_iommu_pagetable.h
new file mode 100644
index 0000000..ebdfc6c
--- /dev/null
+++ b/drivers/iommu/mtk_iommu_pagetable.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef MTK_IOMMU_PAGETABLE_H
+#define MTK_IOMMU_PAGETABLE_H
+
+#define MMU_SMALL_PAGE_SIZE     (SZ_4K)
+#define MMU_LARGE_PAGE_SIZE     (SZ_64K)
+#define MMU_SECTION_SIZE        (SZ_1M)
+#define MMU_SUPERSECTION_SIZE   (SZ_16M)
+
+#define IMU_PGDIR_SHIFT   20
+#define IMU_PAGE_SHIFT    12
+#define IMU_PTRS_PER_PGD  4096
+#define IMU_PTRS_PER_PTE  256
+#define IMU_BYTES_PER_PTE (IMU_PTRS_PER_PTE*sizeof(unsigned int))
+
+struct imu_pte_t {
+	unsigned int imu_pte;
+};
+
+struct imu_pgd_t {
+	unsigned int imu_pgd;
+};
+
+#define imu_pte_val(x)      ((x).imu_pte)
+#define imu_pgd_val(x)      ((x).imu_pgd)
+
+struct m4u_pte_info_t {
+	struct imu_pgd_t *pgd;
+	struct imu_pte_t *pte;
+	unsigned int iova;
+	phys_addr_t pa;
+	unsigned int size;
+	int valid;
+};
+
+#endif
+
-- 
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
@ 2015-03-06 10:48 ` yong.wu
  2015-03-06 11:13   ` Mark Rutland
  2015-03-06 14:48   ` Sergei Shtylyov
  2015-03-06 10:48 ` [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU yong.wu
  2015-03-06 10:48 ` [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 yong.wu
  4 siblings, 2 replies; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu, Yong Wu

From: Yong Wu <yong.wu@mediatek.com>

This patch add smi binding document.

Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
 .../devicetree/bindings/soc/mediatek/mediatek,smi.txt   | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt

diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
new file mode 100644
index 0000000..0fc9d1a
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
@@ -0,0 +1,17 @@
+SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
+
+Required properties:
+- compatible : must be "mediatek,mediatek,mt8173-smi-larb"
+- reg : the register of each local arbiter
+- clocks : the clocks of each local arbiter
+- clock-name: larb_sub*(3 clockes at most)
+
+Example:
+	larb1:larb@16010000 {
+	        compatible = "mediatek,mt8173-smi-larb";
+		reg = <0 0x16010000 0 0x1000>;
+		clocks = <&mmsys MM_SMI_COMMON>,
+		        <&vdecsys VDEC_CKEN>,
+                        <&vdecsys VDEC_LARB_CKEN>;
+		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
+	};
-- 
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU
  2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
                   ` (2 preceding siblings ...)
  2015-03-06 10:48 ` [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding yong.wu
@ 2015-03-06 10:48 ` yong.wu
  2015-03-06 11:21   ` Mark Rutland
  2015-03-06 10:48 ` [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 yong.wu
  4 siblings, 1 reply; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu, Yong Wu

From: Yong Wu <yong.wu@mediatek.com>

This patch add mediatek iommu dts binding document.

Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
 .../devicetree/bindings/iommu/mediatek,iommu.txt   | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/mediatek,iommu.txt

diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
new file mode 100644
index 0000000..db01c92
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
@@ -0,0 +1,41 @@
+/******************************************************/
+/*    Mediatek IOMMU Hardware block diagram           */
+/******************************************************/
+              EMI (External Memory Interface)
+               |
+              m4u (Multimedia Memory Management Unit)
+               |
+              smi (Smart Multimedia Interface)
+               |
+        +---------------+-------
+        |               |
+        |               |
+    vdec larb       disp larb      ... SoCs have different local arbiter(larb).
+        |               |
+        |               |
+   +----+----+    +-----+-----+
+   |    |    |    |     |     |    ...
+   |    |    |    |     |     |    ...
+   |    |    |    |     |     |    ...
+  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... There are different ports in each larb.
+
+Required properties:
+- compatible : must be "mediatek,mt8173-iommu"
+- reg : m4u register base
+- interrupts : must contain the interrupts from each internal translation unit
+- clocks : must contain one entry for each clock-name
+- clock-name: m4u clock
+- larb : must contain the larbes of current platform
+- iommu-cells : must be 1. Specifies the client PortID as defined in
+dt-binding/iommu/mt**-iommu-port.h
+
+Example:
+		iommu: mmsys_iommu@10205000 {
+			compatible = "mediatek,mt8173-iommu";
+			reg = <0 0x10205000 0 0x1000>;
+			interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&infrasys INFRA_M4U>;
+			clock-names = "infra_m4u";
+			larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
+			#iommu-cells = <1>;
+		};
\ No newline at end of file
-- 
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173
  2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
                   ` (3 preceding siblings ...)
  2015-03-06 10:48 ` [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU yong.wu
@ 2015-03-06 10:48 ` yong.wu
  2015-03-07 15:20   ` Daniel Kurtz
  4 siblings, 1 reply; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:48 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu, Yong Wu

From: Yong Wu <yong.wu@mediatek.com>

This patch add the iommu/larbs nodes for mt8173

Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173.dtsi      |  60 ++++++++++++
 include/dt-bindings/iommu/mt8173-iommu-port.h | 127 ++++++++++++++++++++++++++
 2 files changed, 187 insertions(+)
 create mode 100644 include/dt-bindings/iommu/mt8173-iommu-port.h

diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index c2a057f..805a7cd 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -16,6 +16,7 @@
 #include <dt-bindings/reset-controller/mt8173-resets.h>
 #include "mt8173-pinfunc.h"
 #include <dt-bindings/clock/mt8173-clk.h>
+#include <dt-bindings/iommu/mt8173-iommu-port.h>
 
 / {
 	compatible = "mediatek,mt8173";
@@ -249,6 +250,65 @@
 			interrupts = <0 86 8>;
 			clocks = <&uart_clk>;
 		};
+
+		iommu: mmsys_iommu@10205000 {
+			compatible = "mediatek,mt8173-iommu";
+			reg = <0 0x10205000 0 0x1000>;
+			interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
+			clocks = <&infrasys INFRA_M4U>;
+			clock-names = "infra_m4u";
+			larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
+			#iommu-cells = <1>;
+		};
+
+		larb0:larb@14021000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x14021000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB0>;
+			clock-names = "larb_sub0", "larb_sub1";
+		};
+
+		larb1:larb@16010000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x16010000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>,
+					<&vdecsys VDEC_CKEN>,
+					<&vdecsys VDEC_LARB_CKEN>;
+			clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
+		};
+
+		larb2:larb@16010000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x15001000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>,
+					<&imgsys IMG_LARB2_SMI>;
+			clock-names = "larb_sub0", "larb_sub1";
+		};
+
+		larb3:larb@18001000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x18001000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>,
+					<&vencsys VENC_CKE0>,
+					<&vencsys VENC_CKE1>;
+			clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
+		};
+
+		larb4:larb@14027000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x14027000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB4>;
+			clock-names = "larb_sub0", "larb_sub1";
+		};
+
+		larb5:larb@19001000 {
+			compatible = "mediatek,mt8173-smi-larb";
+			reg = <0 0x19001000 0 0x1000>;
+			clocks = <&mmsys MM_SMI_COMMON>,
+					<&vencltsys VENCLT_CKE0>,
+					<&vencltsys VENCLT_CKE1>;
+			clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
+		};
 	};
 
 };
diff --git a/include/dt-bindings/iommu/mt8173-iommu-port.h b/include/dt-bindings/iommu/mt8173-iommu-port.h
new file mode 100644
index 0000000..e9e6569
--- /dev/null
+++ b/include/dt-bindings/iommu/mt8173-iommu-port.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Yong Wu <yong.wu@mediatek.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DTS_IOMMU_PORT_MT8173_H
+#define __DTS_IOMMU_PORT_MT8173_H
+
+#define M4U_LARB0_PORT(n)      ((n) + 0)
+#define M4U_LARB1_PORT(n)      ((n) + 8)
+#define M4U_LARB2_PORT(n)      ((n) + 17)
+#define M4U_LARB3_PORT(n)      ((n) + 38)
+#define M4U_LARB4_PORT(n)      ((n) + 53)
+#define M4U_LARB5_PORT(n)      ((n) + 59)
+#define M4U_PERISYS_PORT(n)    ((n) + 68)
+
+/* larb0 */
+#define	M4U_PORT_DISP_OVL0    M4U_LARB0_PORT(0)
+#define	M4U_PORT_DISP_RDMA0   M4U_LARB0_PORT(1)
+#define	M4U_PORT_DISP_WDMA0   M4U_LARB0_PORT(2)
+#define	M4U_PORT_DISP_OD_R    M4U_LARB0_PORT(3)
+#define	M4U_PORT_DISP_OD_W    M4U_LARB0_PORT(4)
+#define	M4U_PORT_MDP_RDMA0    M4U_LARB0_PORT(5)
+#define	M4U_PORT_MDP_WDMA     M4U_LARB0_PORT(6)
+#define	M4U_PORT_MDP_WROT0    M4U_LARB0_PORT(7)
+
+/* larb1 */
+#define	M4U_PORT_HW_VDEC_MC_EXT       M4U_LARB1_PORT(0)
+#define	M4U_PORT_HW_VDEC_PP_EXT       M4U_LARB1_PORT(1)
+#define	M4U_PORT_HW_VDEC_UFO_EXT      M4U_LARB1_PORT(2)
+#define	M4U_PORT_HW_VDEC_VLD_EXT      M4U_LARB1_PORT(3)
+#define	M4U_PORT_HW_VDEC_VLD2_EXT     M4U_LARB1_PORT(4)
+#define	M4U_PORT_HW_VDEC_AVC_MV_EXT   M4U_LARB1_PORT(5)
+#define	M4U_PORT_HW_VDEC_PRED_RD_EXT  M4U_LARB1_PORT(6)
+#define	M4U_PORT_HW_VDEC_PRED_WR_EXT  M4U_LARB1_PORT(7)
+#define	M4U_PORT_HW_VDEC_PPWRAP_EXT   M4U_LARB1_PORT(8)
+
+/* larb2 */
+#define	M4U_PORT_IMGO      M4U_LARB2_PORT(0)
+#define	M4U_PORT_RRZO      M4U_LARB2_PORT(1)
+#define	M4U_PORT_AAO       M4U_LARB2_PORT(2)
+#define	M4U_PORT_LCSO      M4U_LARB2_PORT(3)
+#define	M4U_PORT_ESFKO     M4U_LARB2_PORT(4)
+#define	M4U_PORT_IMGO_D    M4U_LARB2_PORT(5)
+#define	M4U_PORT_LSCI      M4U_LARB2_PORT(6)
+#define	M4U_PORT_LSCI_D    M4U_LARB2_PORT(7)
+#define	M4U_PORT_BPCI      M4U_LARB2_PORT(8)
+#define	M4U_PORT_BPCI_D    M4U_LARB2_PORT(9)
+#define	M4U_PORT_UFDI      M4U_LARB2_PORT(10)
+#define	M4U_PORT_IMGI      M4U_LARB2_PORT(11)
+#define	M4U_PORT_IMG2O     M4U_LARB2_PORT(12)
+#define	M4U_PORT_IMG3O     M4U_LARB2_PORT(13)
+#define	M4U_PORT_VIPI      M4U_LARB2_PORT(14)
+#define	M4U_PORT_VIP2I     M4U_LARB2_PORT(15)
+#define	M4U_PORT_VIP3I     M4U_LARB2_PORT(16)
+#define	M4U_PORT_LCEI      M4U_LARB2_PORT(17)
+#define	M4U_PORT_RB        M4U_LARB2_PORT(18)
+#define	M4U_PORT_RP        M4U_LARB2_PORT(19)
+#define	M4U_PORT_WR        M4U_LARB2_PORT(20)
+
+/* larb3 */
+#define	M4U_PORT_VENC_RCPU         M4U_LARB3_PORT(0)
+#define	M4U_PORT_VENC_REC          M4U_LARB3_PORT(1)
+#define	M4U_PORT_VENC_BSDMA        M4U_LARB3_PORT(2)
+#define	M4U_PORT_VENC_SV_COMV      M4U_LARB3_PORT(3)
+#define	M4U_PORT_VENC_RD_COMV      M4U_LARB3_PORT(4)
+#define	M4U_PORT_JPGENC_RDMA       M4U_LARB3_PORT(5)
+#define	M4U_PORT_JPGENC_BSDMA      M4U_LARB3_PORT(6)
+#define	M4U_PORT_JPGDEC_WDMA       M4U_LARB3_PORT(7)
+#define	M4U_PORT_JPGDEC_BSDMA      M4U_LARB3_PORT(8)
+#define	M4U_PORT_VENC_CUR_LUMA     M4U_LARB3_PORT(9)
+#define	M4U_PORT_VENC_CUR_CHROMA   M4U_LARB3_PORT(10)
+#define	M4U_PORT_VENC_REF_LUMA     M4U_LARB3_PORT(11)
+#define	M4U_PORT_VENC_REF_CHROMA   M4U_LARB3_PORT(12)
+#define	M4U_PORT_VENC_NBM_RDMA     M4U_LARB3_PORT(13)
+#define	M4U_PORT_VENC_NBM_WDMA     M4U_LARB3_PORT(14)
+
+/* larb4 */
+#define	M4U_PORT_DISP_OVL1        M4U_LARB4_PORT(0)
+#define	M4U_PORT_DISP_RDMA1       M4U_LARB4_PORT(1)
+#define	M4U_PORT_DISP_RDMA2       M4U_LARB4_PORT(2)
+#define	M4U_PORT_DISP_WDMA1       M4U_LARB4_PORT(3)
+#define	M4U_PORT_MDP_RDMA1        M4U_LARB4_PORT(4)
+#define	M4U_PORT_MDP_WROT1        M4U_LARB4_PORT(5)
+
+/* larb5 */
+#define	M4U_PORT_VENC_RCPU_SET2         M4U_LARB5_PORT(0)
+#define	M4U_PORT_VENC_REC_FRM_SET2      M4U_LARB5_PORT(1)
+#define	M4U_PORT_VENC_REF_LUMA_SET2     M4U_LARB5_PORT(2)
+#define	M4U_PORT_VENC_REC_CHROMA_SET2   M4U_LARB5_PORT(3)
+#define	M4U_PORT_VENC_BSDMA_SET2        M4U_LARB5_PORT(4)
+#define	M4U_PORT_VENC_CUR_LUMA_SET2     M4U_LARB5_PORT(5)
+#define	M4U_PORT_VENC_CUR_CHROMA_SET2   M4U_LARB5_PORT(6)
+#define	M4U_PORT_VENC_RD_COMA_SET2      M4U_LARB5_PORT(7)
+#define	M4U_PORT_VENC_SV_COMA_SET2      M4U_LARB5_PORT(8)
+
+/* perisys iommu */
+#define	M4U_PORT_RESERVE      M4U_PERISYS_PORT(0)
+#define	M4U_PORT_SPM          M4U_PERISYS_PORT(1)
+#define	M4U_PORT_MD32         M4U_PERISYS_PORT(2)
+#define	M4U_PORT_PTP_THERM    M4U_PERISYS_PORT(3)
+#define	M4U_PORT_PWM          M4U_PERISYS_PORT(4)
+#define	M4U_PORT_MSDC1        M4U_PERISYS_PORT(5)
+#define	M4U_PORT_MSDC2        M4U_PERISYS_PORT(6)
+#define	M4U_PORT_SPI0         M4U_PERISYS_PORT(7)
+#define	M4U_PORT_NFI          M4U_PERISYS_PORT(8)
+#define	M4U_PORT_AUDIO        M4U_PERISYS_PORT(9)
+#define	M4U_PORT_RESERVED2    M4U_PERISYS_PORT(10)
+#define	M4U_PORT_HSIC_XHCI    M4U_PERISYS_PORT(11)
+
+#define	M4U_PORT_HSIC_MAS     M4U_PERISYS_PORT(12)
+#define	M4U_PORT_HSIC_DEV     M4U_PERISYS_PORT(13)
+#define	M4U_PORT_AP_DMA       M4U_PERISYS_PORT(14)
+#define	M4U_PORT_HSIC_DMA     M4U_PERISYS_PORT(15)
+#define	M4U_PORT_MSDC0        M4U_PERISYS_PORT(16)
+#define	M4U_PORT_MSDC3        M4U_PERISYS_PORT(17)
+
+#endif
+
-- 
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
@ 2015-03-06 10:58   ` Will Deacon
  2015-03-09 12:11     ` Yong Wu
  2015-03-06 17:15   ` Mitchel Humpherys
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 55+ messages in thread
From: Will Deacon @ 2015-03-06 10:58 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Daniel Kurtz, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

On Fri, Mar 06, 2015 at 10:48:17AM +0000, yong.wu@mediatek.com wrote:
> From: Yong Wu <yong.wu@mediatek.com>
> 
> This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.

[...]

> diff --git a/drivers/iommu/mtk_iommu_pagetable.c b/drivers/iommu/mtk_iommu_pagetable.c
> new file mode 100644
> index 0000000..5fe9640
> --- /dev/null
> +++ b/drivers/iommu/mtk_iommu_pagetable.c
> @@ -0,0 +1,439 @@
> +/*
> + * Copyright (c) 2014-2015 MediaTek Inc.
> + * Author: Yong Wu <yong.wu@mediatek.com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#include <linux/err.h>
> +#include <linux/mm.h>
> +#include <linux/iommu.h>
> +#include <linux/errno.h>
> +#include "asm/cacheflush.h"
> +
> +#include "mtk_iommu.h"
> +#include "mtk_iommu_pagetable.h"
> +
> +/* 2 level pagetable: pgd -> pte */
> +#define F_PTE_TYPE_GET(regval)  (regval & 0x3)
> +#define F_PTE_TYPE_LARGE         BIT(0)
> +#define F_PTE_TYPE_SMALL         BIT(1)
> +#define F_PTE_B_BIT              BIT(2)
> +#define F_PTE_C_BIT              BIT(3)
> +#define F_PTE_BIT32_BIT          BIT(9)
> +#define F_PTE_S_BIT              BIT(10)
> +#define F_PTE_NG_BIT             BIT(11)
> +#define F_PTE_PA_LARGE_MSK            (~0UL << 16)
> +#define F_PTE_PA_LARGE_GET(regval)    ((regval >> 16) & 0xffff)
> +#define F_PTE_PA_SMALL_MSK            (~0UL << 12)
> +#define F_PTE_PA_SMALL_GET(regval)    ((regval >> 12) & (~0))
> +#define F_PTE_TYPE_IS_LARGE_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> +                                       F_PTE_TYPE_LARGE)
> +#define F_PTE_TYPE_IS_SMALL_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> +                                       F_PTE_TYPE_SMALL)

This looks like the ARM short-descriptor format to me. Could you please
add a new page table format to the io-pgtable code, so that other IOMMU
drivers can make use of this? I know there was some interest in using
short descriptor for the ARM SMMU, for example.

Cheers,

Will

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 10:48 ` [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding yong.wu
@ 2015-03-06 11:13   ` Mark Rutland
  2015-03-09 12:55     ` Yong Wu
  2015-04-14  9:07     ` Yong Wu
  2015-03-06 14:48   ` Sergei Shtylyov
  1 sibling, 2 replies; 55+ messages in thread
From: Mark Rutland @ 2015-03-06 11:13 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> From: Yong Wu <yong.wu@mediatek.com>
> 
> This patch add smi binding document.

Please move binding documents to the start of the series. It makes
things far easier to review.

> 
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  .../devicetree/bindings/soc/mediatek/mediatek,smi.txt   | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> 
> diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> new file mode 100644
> index 0000000..0fc9d1a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> @@ -0,0 +1,17 @@
> +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> +
> +Required properties:
> +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"

Double vendor prefix?

What does "larb" mean? It would be nice for the intorductory paragraph
in this file to explain.

> +- reg : the register of each local arbiter
> +- clocks : the clocks of each local arbiter
> +- clock-name: larb_sub*(3 clockes at most)

The names required _must_ be specified here, or clock-names is
pointless.

The clock names should be from the PoV of _this_ device (i.e. they
should be the names of the inputs) not from the PoV of the provider
(i.e. they should not be the names of the outputs from the provider).

Mark.

> +
> +Example:
> +	larb1:larb@16010000 {
> +	        compatible = "mediatek,mt8173-smi-larb";
> +		reg = <0 0x16010000 0 0x1000>;
> +		clocks = <&mmsys MM_SMI_COMMON>,
> +		        <&vdecsys VDEC_CKEN>,
> +                        <&vdecsys VDEC_LARB_CKEN>;
> +		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> +	};
> -- 
> 1.8.1.1.dirty
> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU
  2015-03-06 10:48 ` [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU yong.wu
@ 2015-03-06 11:21   ` Mark Rutland
  2015-03-09 11:30     ` Yong Wu
  0 siblings, 1 reply; 55+ messages in thread
From: Mark Rutland @ 2015-03-06 11:21 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

On Fri, Mar 06, 2015 at 10:48:19AM +0000, yong.wu@mediatek.com wrote:
> From: Yong Wu <yong.wu@mediatek.com>
> 
> This patch add mediatek iommu dts binding document.
> 
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  .../devicetree/bindings/iommu/mediatek,iommu.txt   | 41 ++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> 
> diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> new file mode 100644
> index 0000000..db01c92
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> @@ -0,0 +1,41 @@
> +/******************************************************/
> +/*    Mediatek IOMMU Hardware block diagram           */
> +/******************************************************/
> +              EMI (External Memory Interface)
> +               |
> +              m4u (Multimedia Memory Management Unit)
> +               |
> +              smi (Smart Multimedia Interface)
> +               |
> +        +---------------+-------
> +        |               |
> +        |               |
> +    vdec larb       disp larb      ... SoCs have different local arbiter(larb).
> +        |               |
> +        |               |
> +   +----+----+    +-----+-----+
> +   |    |    |    |     |     |    ...
> +   |    |    |    |     |     |    ...
> +   |    |    |    |     |     |    ...
> +  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... There are different ports in each larb.
> +
> +Required properties:
> +- compatible : must be "mediatek,mt8173-iommu"

s/iommu/m4u/ -- the name should match what the hardware is called.

> +- reg : m4u register base

... and size

> +- interrupts : must contain the interrupts from each internal translation unit

How many "internal translation units" are there?

How should the interrupts be ordered?

How do these relate to the larbs?

> +- clocks : must contain one entry for each clock-name
> +- clock-name: m4u clock

This does not match the example.

s/clock-name/clock-names/

Please format this like a list, with names quoted, e.g.

- clock-names: must contain:
  * "m4u" - The functional clock for the m4u

> +- larb : must contain the larbes of current platform

s/larbes/local arbiters/

How should these be ordered? Surely there's a relationship with
registers/interrupts/etc in this unit?

> +- iommu-cells : must be 1. Specifies the client PortID as defined in
> +dt-binding/iommu/mt**-iommu-port.h

Give the absolute filename.

The include file should be added in this patch (it's part of the
binding). The whole patch should be moved earlier in the series.

Thanks,
Mark.

> +
> +Example:
> +		iommu: mmsys_iommu@10205000 {
> +			compatible = "mediatek,mt8173-iommu";
> +			reg = <0 0x10205000 0 0x1000>;
> +			interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
> +			clocks = <&infrasys INFRA_M4U>;
> +			clock-names = "infra_m4u";
> +			larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
> +			#iommu-cells = <1>;
> +		};
> \ No newline at end of file
> -- 
> 1.8.1.1.dirty
> 
> 

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
@ 2015-03-06 11:30   ` Paul Bolle
  2015-03-09 11:57     ` Yong Wu
  2015-03-09  3:26   ` Yingjoe Chen
  2015-03-09 11:03   ` Sascha Hauer
  2 siblings, 1 reply; 55+ messages in thread
From: Paul Bolle @ 2015-03-06 11:30 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Mark Rutland, Catalin Marinas, linux-mediatek, Sasha Hauer,
	srv_heupstream, devicetree, linux-kernel, linux-arm-kernel,
	iommu

On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> --- a/drivers/soc/mediatek/Kconfig
> +++ b/drivers/soc/mediatek/Kconfig
> @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
>  	  PMIC wrapper is a proprietary hardware in MT8173 to make
>  	  communication protocols to access PMIC device.
>  	  This driver implement access protocols for MT8173.
> +
> +config MTK_SMI
> +        bool

Nit: make this one tab instead of 8 spaces, please.

> +	help
> +	  Smi help enable/disable iommu in mt8173 and control the
> +	  clock of each local arbiter.
> +	  It should be true while MTK_IOMMU enable.

I don't think anyone using the *config tools will ever see this text, as
there's no prompt. So you might as well make this a comment or drop it
altogether.

Is this selected by more than just MTK_IOMMU (see 2/5)? If not, I think
MTK_SMI will be set and unset in lockstep with MTK_IOMMU. In other
words, you could as well use one Kconfig symbol.

Thanks,


Paul Bolle


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 10:48 ` [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding yong.wu
  2015-03-06 11:13   ` Mark Rutland
@ 2015-03-06 14:48   ` Sergei Shtylyov
  2015-03-09 12:32     ` Yong Wu
  1 sibling, 1 reply; 55+ messages in thread
From: Sergei Shtylyov @ 2015-03-06 14:48 UTC (permalink / raw)
  To: yong.wu, Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Mark Rutland, devicetree, srv_heupstream, Catalin Marinas,
	Will Deacon, linux-kernel, Tomasz Figa, iommu, Daniel Kurtz,
	Sasha Hauer, linux-mediatek, Robin Murphy, linux-arm-kernel,
	Lucas Stach

Hello.

On 3/6/2015 1:48 PM, yong.wu@mediatek.com wrote:

> From: Yong Wu <yong.wu@mediatek.com>

> This patch add smi binding document.

> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>   .../devicetree/bindings/soc/mediatek/mediatek,smi.txt   | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt

> diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> new file mode 100644
> index 0000000..0fc9d1a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> @@ -0,0 +1,17 @@
> +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> +
> +Required properties:
> +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"

    One "mediatek," is enough. :-)

> +- reg : the register of each local arbiter
> +- clocks : the clocks of each local arbiter
> +- clock-name: larb_sub*(3 clockes at most)

    clock-names.

> +
> +Example:
> +	larb1:larb@16010000 {
> +	        compatible = "mediatek,mt8173-smi-larb";
> +		reg = <0 0x16010000 0 0x1000>;
> +		clocks = <&mmsys MM_SMI_COMMON>,
> +		        <&vdecsys VDEC_CKEN>,

    Please align with the < above.

> +                        <&vdecsys VDEC_LARB_CKEN>;

    Use tabs instead of spaces, please.

> +		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> +	};

WBR, Sergei


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
  2015-03-06 10:58   ` Will Deacon
@ 2015-03-06 17:15   ` Mitchel Humpherys
  2015-03-09 12:16     ` Yong Wu
  2015-03-08  4:12   ` Tomasz Figa
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 55+ messages in thread
From: Mitchel Humpherys @ 2015-03-06 17:15 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Daniel Kurtz, Sasha Hauer,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach

On Fri, Mar 06 2015 at 02:48:17 AM, <yong.wu@mediatek.com> wrote:
> From: Yong Wu <yong.wu@mediatek.com>
>
> This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.

[...]

> +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
> +				    int isinvall, unsigned int iova_start,
> +				    unsigned int iova_end)
> +{
> +	void __iomem *m4u_base = piommu->m4u_base;
> +	u32 val;
> +	u64 start, end;
> +
> +	start = sched_clock();
> +
> +	if (!isinvall) {
> +		iova_start = round_down(iova_start, SZ_4K);
> +		iova_end = round_up(iova_end, SZ_4K);
> +	}
> +
> +	val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
> +
> +	writel(val, m4u_base + REG_INVLID_SEL);
> +
> +	if (isinvall) {
> +		writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> +	} else {
> +		writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
> +		writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
> +		writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
> +
> +		while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
> +			end = sched_clock();
> +			if (end - start >= 100000000ULL) {
> +				dev_warn(piommu->dev, "invalid don't done\n");
> +				writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> +			}
> +		};

Superfluous `;'.  Also, maybe you should be using readl_poll_timeout?

> +		writel(0, m4u_base + REG_MMU_CPE_DONE);
> +	}
> +
> +	return 0;
> +}



-Mitch

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173
  2015-03-06 10:48 ` [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 yong.wu
@ 2015-03-07 15:20   ` Daniel Kurtz
  2015-03-09 12:18     ` Yong Wu
  0 siblings, 1 reply; 55+ messages in thread
From: Daniel Kurtz @ 2015-03-07 15:20 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	open list:OPEN FIRMWARE AND...,
	linux-kernel, linux-arm-kernel, open list:IOMMU DRIVERS

Hi Yong,

On Fri, Mar 6, 2015 at 6:48 PM,  <yong.wu@mediatek.com> wrote:
> From: Yong Wu <yong.wu@mediatek.com>
>
> This patch add the iommu/larbs nodes for mt8173
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  arch/arm64/boot/dts/mediatek/mt8173.dtsi      |  60 ++++++++++++
>  include/dt-bindings/iommu/mt8173-iommu-port.h | 127 ++++++++++++++++++++++++++
>  2 files changed, 187 insertions(+)
>  create mode 100644 include/dt-bindings/iommu/mt8173-iommu-port.h
>
> diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> index c2a057f..805a7cd 100644
> --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> @@ -16,6 +16,7 @@
>  #include <dt-bindings/reset-controller/mt8173-resets.h>
>  #include "mt8173-pinfunc.h"
>  #include <dt-bindings/clock/mt8173-clk.h>
> +#include <dt-bindings/iommu/mt8173-iommu-port.h>
>
>  / {
>         compatible = "mediatek,mt8173";
> @@ -249,6 +250,65 @@
>                         interrupts = <0 86 8>;
>                         clocks = <&uart_clk>;
>                 };
> +
> +               iommu: mmsys_iommu@10205000 {
> +                       compatible = "mediatek,mt8173-iommu";
> +                       reg = <0 0x10205000 0 0x1000>;
> +                       interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
> +                       clocks = <&infrasys INFRA_M4U>;
> +                       clock-names = "infra_m4u";
> +                       larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
> +                       #iommu-cells = <1>;
> +               };
> +
> +               larb0:larb@14021000 {
> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x14021000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB0>;
> +                       clock-names = "larb_sub0", "larb_sub1";
> +               };
> +
> +               larb1:larb@16010000 {
> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x16010000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>,
> +                                       <&vdecsys VDEC_CKEN>,
> +                                       <&vdecsys VDEC_LARB_CKEN>;
> +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> +               };
> +
> +               larb2:larb@16010000 {

I think this one should be:
   larb2: larb@15001000 {

Also, I am not a devicetree expert, but I believe nodes are usually
arranged in register order.
If that is the case, the order, as unfortunate as this looks, should be:

 larb0: larb@14021000
 larb4: larb@14027000
 larb2: larb@15001000
 larb1: larb@16010000
 larb3: larb@18001000
 larb5: larb@19001000

-Dan


> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x15001000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>,
> +                                       <&imgsys IMG_LARB2_SMI>;
> +                       clock-names = "larb_sub0", "larb_sub1";
> +               };
> +
> +               larb3:larb@18001000 {
> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x18001000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>,
> +                                       <&vencsys VENC_CKE0>,
> +                                       <&vencsys VENC_CKE1>;
> +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> +               };
> +
> +               larb4:larb@14027000 {
> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x14027000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB4>;
> +                       clock-names = "larb_sub0", "larb_sub1";
> +               };
> +
> +               larb5:larb@19001000 {
> +                       compatible = "mediatek,mt8173-smi-larb";
> +                       reg = <0 0x19001000 0 0x1000>;
> +                       clocks = <&mmsys MM_SMI_COMMON>,
> +                                       <&vencltsys VENCLT_CKE0>,
> +                                       <&vencltsys VENCLT_CKE1>;
> +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> +               };
>         };
>
>  };
> diff --git a/include/dt-bindings/iommu/mt8173-iommu-port.h b/include/dt-bindings/iommu/mt8173-iommu-port.h
> new file mode 100644
> index 0000000..e9e6569
> --- /dev/null
> +++ b/include/dt-bindings/iommu/mt8173-iommu-port.h
> @@ -0,0 +1,127 @@
> +/*
> + * Copyright (c) 2014-2015 MediaTek Inc.
> + * Author: Yong Wu <yong.wu@mediatek.com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef __DTS_IOMMU_PORT_MT8173_H
> +#define __DTS_IOMMU_PORT_MT8173_H
> +
> +#define M4U_LARB0_PORT(n)      ((n) + 0)
> +#define M4U_LARB1_PORT(n)      ((n) + 8)
> +#define M4U_LARB2_PORT(n)      ((n) + 17)
> +#define M4U_LARB3_PORT(n)      ((n) + 38)
> +#define M4U_LARB4_PORT(n)      ((n) + 53)
> +#define M4U_LARB5_PORT(n)      ((n) + 59)
> +#define M4U_PERISYS_PORT(n)    ((n) + 68)
> +
> +/* larb0 */
> +#define        M4U_PORT_DISP_OVL0    M4U_LARB0_PORT(0)
> +#define        M4U_PORT_DISP_RDMA0   M4U_LARB0_PORT(1)
> +#define        M4U_PORT_DISP_WDMA0   M4U_LARB0_PORT(2)
> +#define        M4U_PORT_DISP_OD_R    M4U_LARB0_PORT(3)
> +#define        M4U_PORT_DISP_OD_W    M4U_LARB0_PORT(4)
> +#define        M4U_PORT_MDP_RDMA0    M4U_LARB0_PORT(5)
> +#define        M4U_PORT_MDP_WDMA     M4U_LARB0_PORT(6)
> +#define        M4U_PORT_MDP_WROT0    M4U_LARB0_PORT(7)
> +
> +/* larb1 */
> +#define        M4U_PORT_HW_VDEC_MC_EXT       M4U_LARB1_PORT(0)
> +#define        M4U_PORT_HW_VDEC_PP_EXT       M4U_LARB1_PORT(1)
> +#define        M4U_PORT_HW_VDEC_UFO_EXT      M4U_LARB1_PORT(2)
> +#define        M4U_PORT_HW_VDEC_VLD_EXT      M4U_LARB1_PORT(3)
> +#define        M4U_PORT_HW_VDEC_VLD2_EXT     M4U_LARB1_PORT(4)
> +#define        M4U_PORT_HW_VDEC_AVC_MV_EXT   M4U_LARB1_PORT(5)
> +#define        M4U_PORT_HW_VDEC_PRED_RD_EXT  M4U_LARB1_PORT(6)
> +#define        M4U_PORT_HW_VDEC_PRED_WR_EXT  M4U_LARB1_PORT(7)
> +#define        M4U_PORT_HW_VDEC_PPWRAP_EXT   M4U_LARB1_PORT(8)
> +
> +/* larb2 */
> +#define        M4U_PORT_IMGO      M4U_LARB2_PORT(0)
> +#define        M4U_PORT_RRZO      M4U_LARB2_PORT(1)
> +#define        M4U_PORT_AAO       M4U_LARB2_PORT(2)
> +#define        M4U_PORT_LCSO      M4U_LARB2_PORT(3)
> +#define        M4U_PORT_ESFKO     M4U_LARB2_PORT(4)
> +#define        M4U_PORT_IMGO_D    M4U_LARB2_PORT(5)
> +#define        M4U_PORT_LSCI      M4U_LARB2_PORT(6)
> +#define        M4U_PORT_LSCI_D    M4U_LARB2_PORT(7)
> +#define        M4U_PORT_BPCI      M4U_LARB2_PORT(8)
> +#define        M4U_PORT_BPCI_D    M4U_LARB2_PORT(9)
> +#define        M4U_PORT_UFDI      M4U_LARB2_PORT(10)
> +#define        M4U_PORT_IMGI      M4U_LARB2_PORT(11)
> +#define        M4U_PORT_IMG2O     M4U_LARB2_PORT(12)
> +#define        M4U_PORT_IMG3O     M4U_LARB2_PORT(13)
> +#define        M4U_PORT_VIPI      M4U_LARB2_PORT(14)
> +#define        M4U_PORT_VIP2I     M4U_LARB2_PORT(15)
> +#define        M4U_PORT_VIP3I     M4U_LARB2_PORT(16)
> +#define        M4U_PORT_LCEI      M4U_LARB2_PORT(17)
> +#define        M4U_PORT_RB        M4U_LARB2_PORT(18)
> +#define        M4U_PORT_RP        M4U_LARB2_PORT(19)
> +#define        M4U_PORT_WR        M4U_LARB2_PORT(20)
> +
> +/* larb3 */
> +#define        M4U_PORT_VENC_RCPU         M4U_LARB3_PORT(0)
> +#define        M4U_PORT_VENC_REC          M4U_LARB3_PORT(1)
> +#define        M4U_PORT_VENC_BSDMA        M4U_LARB3_PORT(2)
> +#define        M4U_PORT_VENC_SV_COMV      M4U_LARB3_PORT(3)
> +#define        M4U_PORT_VENC_RD_COMV      M4U_LARB3_PORT(4)
> +#define        M4U_PORT_JPGENC_RDMA       M4U_LARB3_PORT(5)
> +#define        M4U_PORT_JPGENC_BSDMA      M4U_LARB3_PORT(6)
> +#define        M4U_PORT_JPGDEC_WDMA       M4U_LARB3_PORT(7)
> +#define        M4U_PORT_JPGDEC_BSDMA      M4U_LARB3_PORT(8)
> +#define        M4U_PORT_VENC_CUR_LUMA     M4U_LARB3_PORT(9)
> +#define        M4U_PORT_VENC_CUR_CHROMA   M4U_LARB3_PORT(10)
> +#define        M4U_PORT_VENC_REF_LUMA     M4U_LARB3_PORT(11)
> +#define        M4U_PORT_VENC_REF_CHROMA   M4U_LARB3_PORT(12)
> +#define        M4U_PORT_VENC_NBM_RDMA     M4U_LARB3_PORT(13)
> +#define        M4U_PORT_VENC_NBM_WDMA     M4U_LARB3_PORT(14)
> +
> +/* larb4 */
> +#define        M4U_PORT_DISP_OVL1        M4U_LARB4_PORT(0)
> +#define        M4U_PORT_DISP_RDMA1       M4U_LARB4_PORT(1)
> +#define        M4U_PORT_DISP_RDMA2       M4U_LARB4_PORT(2)
> +#define        M4U_PORT_DISP_WDMA1       M4U_LARB4_PORT(3)
> +#define        M4U_PORT_MDP_RDMA1        M4U_LARB4_PORT(4)
> +#define        M4U_PORT_MDP_WROT1        M4U_LARB4_PORT(5)
> +
> +/* larb5 */
> +#define        M4U_PORT_VENC_RCPU_SET2         M4U_LARB5_PORT(0)
> +#define        M4U_PORT_VENC_REC_FRM_SET2      M4U_LARB5_PORT(1)
> +#define        M4U_PORT_VENC_REF_LUMA_SET2     M4U_LARB5_PORT(2)
> +#define        M4U_PORT_VENC_REC_CHROMA_SET2   M4U_LARB5_PORT(3)
> +#define        M4U_PORT_VENC_BSDMA_SET2        M4U_LARB5_PORT(4)
> +#define        M4U_PORT_VENC_CUR_LUMA_SET2     M4U_LARB5_PORT(5)
> +#define        M4U_PORT_VENC_CUR_CHROMA_SET2   M4U_LARB5_PORT(6)
> +#define        M4U_PORT_VENC_RD_COMA_SET2      M4U_LARB5_PORT(7)
> +#define        M4U_PORT_VENC_SV_COMA_SET2      M4U_LARB5_PORT(8)
> +
> +/* perisys iommu */
> +#define        M4U_PORT_RESERVE      M4U_PERISYS_PORT(0)
> +#define        M4U_PORT_SPM          M4U_PERISYS_PORT(1)
> +#define        M4U_PORT_MD32         M4U_PERISYS_PORT(2)
> +#define        M4U_PORT_PTP_THERM    M4U_PERISYS_PORT(3)
> +#define        M4U_PORT_PWM          M4U_PERISYS_PORT(4)
> +#define        M4U_PORT_MSDC1        M4U_PERISYS_PORT(5)
> +#define        M4U_PORT_MSDC2        M4U_PERISYS_PORT(6)
> +#define        M4U_PORT_SPI0         M4U_PERISYS_PORT(7)
> +#define        M4U_PORT_NFI          M4U_PERISYS_PORT(8)
> +#define        M4U_PORT_AUDIO        M4U_PERISYS_PORT(9)
> +#define        M4U_PORT_RESERVED2    M4U_PERISYS_PORT(10)
> +#define        M4U_PORT_HSIC_XHCI    M4U_PERISYS_PORT(11)
> +
> +#define        M4U_PORT_HSIC_MAS     M4U_PERISYS_PORT(12)
> +#define        M4U_PORT_HSIC_DEV     M4U_PERISYS_PORT(13)
> +#define        M4U_PORT_AP_DMA       M4U_PERISYS_PORT(14)
> +#define        M4U_PORT_HSIC_DMA     M4U_PERISYS_PORT(15)
> +#define        M4U_PORT_MSDC0        M4U_PERISYS_PORT(16)
> +#define        M4U_PORT_MSDC3        M4U_PERISYS_PORT(17)
> +
> +#endif
> +
> --
> 1.8.1.1.dirty

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
  2015-03-06 10:58   ` Will Deacon
  2015-03-06 17:15   ` Mitchel Humpherys
@ 2015-03-08  4:12   ` Tomasz Figa
  2015-03-12 14:16     ` Yong Wu
  2015-03-09  8:24   ` Daniel Kurtz
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 55+ messages in thread
From: Tomasz Figa @ 2015-03-08  4:12 UTC (permalink / raw)
  To: Yong Wu (吴勇)
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi Yong Wu,

Thanks for this series. Please see my comments inline.

On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:
> From: Yong Wu <yong.wu@mediatek.com>
>
> This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.

[snip]

> diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
> new file mode 100644
> index 0000000..d62d4ab
> --- /dev/null
> +++ b/drivers/iommu/mtk_iommu.c
> @@ -0,0 +1,754 @@
> +/*
> + * Copyright (c) 2014-2015 MediaTek Inc.
> + * Author: Yong Wu <yong.wu@mediatek.com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "m4u:"fmt

This format is not very useful, especially when using dev_ helpers
prepends messages with device name.

> +
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/mm.h>
> +#include <linux/iommu.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/memblock.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/dma-iommu.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/mtk-smi.h>
> +#include <asm/cacheflush.h>
> +
> +#include "mtk_iommu.h"

CodingStyle: The definitions below do not seem to be aligned
correctly. Please make sure all the values are in the same column and
are aligned using tabs only (remembering that tab width specified by
Linux coding style is 8 characters).

> +
> +#define REG_MMUG_PT_BASE        0x0
> +
> +#define REG_MMU_INVLD           0x20
> +#define F_MMU_INV_ALL           0x2
> +#define F_MMU_INV_RANGE                 0x1
> +
> +#define REG_MMU_INVLD_SA        0x24
> +#define REG_MMU_INVLD_EA         0x28
> +
> +#define REG_MMU_INVLD_SEC         0x2c
> +#define F_MMU_INV_SEC_ALL          0x2
> +#define F_MMU_INV_SEC_RANGE        0x1
> +
> +#define REG_INVLID_SEL          0x38
> +#define F_MMU_INV_EN_L1                 BIT(0)
> +#define F_MMU_INV_EN_L2                 BIT(1)
> +
> +#define REG_MMU_STANDARD_AXI_MODE   0x48
> +#define REG_MMU_DCM_DIS             0x50
> +#define REG_MMU_LEGACY_4KB_MODE     0x60
> +
> +#define REG_MMU_CTRL_REG                 0x110
> +#define F_MMU_CTRL_REROUTE_PFQ_TO_MQ_EN  BIT(4)
> +#define F_MMU_CTRL_TF_PROT_VAL(prot)      (((prot) & 0x3)<<5)

CodingStyle: Operators (e.g. <<) should have spaces on both sides.

> +#define F_MMU_CTRL_COHERE_EN             BIT(8)
> +
> +#define REG_MMU_IVRP_PADDR               0x114
> +#define F_MMU_IVRP_PA_SET(PA)            (PA>>1)

Please make sure that all references to macro arguments in macro
definitions are surrounded by parentheses to avoid issues with
operator precedence. (i.e. ((pa) >> 1))

CodingStyle: Macro arguments should be lowercase.

> +
> +#define REG_MMU_INT_L2_CONTROL      0x120
> +#define F_INT_L2_CLR_BIT            BIT(12)
> +
> +#define REG_MMU_INT_MAIN_CONTROL    0x124
> +#define F_INT_TRANSLATION_FAULT(MMU)           (1<<(0+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_MAIN_MULTI_HIT_FAULT(MMU)        (1<<(1+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_INVALID_PA_FAULT(MMU)            (1<<(2+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_ENTRY_REPLACEMENT_FAULT(MMU)     (1<<(3+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_TLB_MISS_FAULT(MMU)              (1<<(4+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_PFH_FIFO_ERR(MMU)                (1<<(6+(((MMU)<<1)|((MMU)<<2))))

Multiple coding style issues in these 6 macros, as per my comments above.

> +
> +#define REG_MMU_CPE_DONE              0x12C
> +
> +#define REG_MMU_MAIN_FAULT_ST         0x134
> +
> +#define REG_MMU_FAULT_VA(mmu)         (0x13c+((mmu)<<3))
> +#define F_MMU_FAULT_VA_MSK            ((~0x0)<<12)

Please specify the mask manually to avoid ambiguities with result type.
+ CodingStyle

> +#define F_MMU_FAULT_VA_WRITE_BIT       BIT(1)
> +#define F_MMU_FAULT_VA_LAYER_BIT       BIT(0)
> +
> +#define REG_MMU_INVLD_PA(mmu)         (0x140+((mmu)<<3))
> +#define REG_MMU_INT_ID(mmu)           (0x150+((mmu)<<2))
> +#define F_MMU0_INT_ID_TF_MSK          (~0x3)   /* only for MM iommu. */

Ditto.

> +
> +#define MTK_TFID(larbid, portid) ((larbid << 7) | (portid << 2))

Missing parentheses around macro arguments.

> +
> +static const struct mtk_iommu_port mtk_iommu_mt8173_port[] = {
> +       /* port name                m4uid slaveid larbid portid tfid */
> +       /* larb0 */
> +       {"M4U_PORT_DISP_OVL0",          0,  0,    0,  0, MTK_TFID(0, 0)},
> +       {"M4U_PORT_DISP_RDMA0",         0,  0,    0,  1, MTK_TFID(0, 1)},
> +       {"M4U_PORT_DISP_WDMA0",         0,  0,    0,  2, MTK_TFID(0, 2)},
> +       {"M4U_PORT_DISP_OD_R",          0,  0,    0,  3, MTK_TFID(0, 3)},
> +       {"M4U_PORT_DISP_OD_W",          0,  0,    0,  4, MTK_TFID(0, 4)},
> +       {"M4U_PORT_MDP_RDMA0",          0,  0,    0,  5, MTK_TFID(0, 5)},
> +       {"M4U_PORT_MDP_WDMA",           0,  0,    0,  6, MTK_TFID(0, 6)},
> +       {"M4U_PORT_MDP_WROT0",          0,  0,    0,  7, MTK_TFID(0, 7)},

[snip]

> +       {"M4U_PORT_HSIC_MAS",              1,  0,    6,  12, 0x11},
> +       {"M4U_PORT_HSIC_DEV",              1,  0,    6,  13, 0x19},
> +       {"M4U_PORT_AP_DMA",                1,  0,    6,  14, 0x18},
> +       {"M4U_PORT_HSIC_DMA",              1,  0,    6,  15, 0xc8},
> +       {"M4U_PORT_MSDC0",                 1,  0,    6,  16, 0x0},
> +       {"M4U_PORT_MSDC3",                 1,  0,    6,  17, 0x20},
> +       {"M4U_PORT_UNKNOWN",               1,  0,    6,  18, 0xf},

Why the MTK_TFID() macro is not used for perisys iommu?

> +};
> +

Anyway, is it really necessary to hardcode the SoC specific topology
data in this driver? Is there really any use besides of printing port
name? If not, you could just print the values in a way letting you
quickly look up in the datasheet, without hardcoding this. Or even
better, you could print which devices are attached to the port.

> +static const struct mtk_iommu_cfg mtk_iommu_mt8173_cfg = {
> +       .larb_nr = 6,
> +       .m4u_port_nr = ARRAY_SIZE(mtk_iommu_mt8173_port),
> +       .pport = mtk_iommu_mt8173_port,
> +};
> +
> +static const char *mtk_iommu_get_port_name(const struct mtk_iommu_info *piommu,
> +                                          unsigned int portid)
> +{
> +       const struct mtk_iommu_port *pcurport = NULL;
> +
> +       pcurport = piommu->imucfg->pport + portid;
> +       if (portid < piommu->imucfg->m4u_port_nr && pcurport)
> +               return pcurport->port_name;
> +       else
> +               return "UNKNOWN_PORT";
> +}

This function seems to be used just for printing the hardcoded port names.

> +
> +static int mtk_iommu_get_port_by_tfid(const struct mtk_iommu_info *pimu,
> +                                     int tf_id)
> +{
> +       const struct mtk_iommu_cfg *pimucfg = pimu->imucfg;
> +       int i;
> +       unsigned int portid = pimucfg->m4u_port_nr;
> +
> +       for (i = 0; i < pimucfg->m4u_port_nr; i++) {
> +               if (pimucfg->pport[i].tf_id == tf_id) {
> +                       portid = i;
> +                       break;
> +               }
> +       }
> +       if (i == pimucfg->m4u_port_nr)
> +               dev_err(pimu->dev, "tf_id find fail, tfid %d\n", tf_id);
> +       return portid;
> +}

This function seems to be used just for finding an index into the
array of hardcoded port names for printing purposes.

> +
> +static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
> +{
> +       struct iommu_domain *domain = dev_id;
> +       struct mtk_iommu_domain *mtkdomain = domain->priv;
> +       struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
> +
> +       if (irq == piommu->irq)
> +               report_iommu_fault(domain, piommu->dev, 0, 0);

This doesn't look like a good use of report_iommu_fault(). You should
pass real values of iova and flags arguments.

> +       else

This is impossible, no need to check this.

> +               dev_err(piommu->dev, "irq number:%d\n", irq);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static inline void mtk_iommu_clear_intr(void __iomem *m4u_base)

Please let the compiler decide if this function should be inline or not.

> +{
> +       u32 val;
> +
> +       val = readl(m4u_base + REG_MMU_INT_L2_CONTROL);
> +       val |= F_INT_L2_CLR_BIT;
> +       writel(val, m4u_base + REG_MMU_INT_L2_CONTROL);
> +}
> +
> +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
> +                                   int isinvall, unsigned int iova_start,
> +                                   unsigned int iova_end)
> +{
> +       void __iomem *m4u_base = piommu->m4u_base;
> +       u32 val;
> +       u64 start, end;
> +
> +       start = sched_clock();

I don't think this is the preferred way of checking time in kernel
drivers, especially after seeing this comment:
http://lxr.free-electrons.com/source/include/linux/sched.h#L2134

You should use ktime_get() and other ktime_ helpers.

> +
> +       if (!isinvall) {
> +               iova_start = round_down(iova_start, SZ_4K);
> +               iova_end = round_up(iova_end, SZ_4K);
> +       }
> +
> +       val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
> +
> +       writel(val, m4u_base + REG_INVLID_SEL);
> +
> +       if (isinvall) {
> +               writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);

Please move invalidate all into separate function and just call it
wherever the code currently passes true as invall argument. You will
get rid of two of the ifs in this function.

> +       } else {
> +               writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
> +               writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
> +               writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
> +
> +               while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
> +                       end = sched_clock();
> +                       if (end - start >= 100000000ULL) {

Looks like a very interesting magic number. Please define a macro and
use normal time units along with ktime_to_<unit>() helpers.

> +                               dev_warn(piommu->dev, "invalid don't done\n");
> +                               writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);

By following my comment above, you could just call the new invalidate
all function here instead of duplicating the same register write.

> +                       }
> +               };

nit: Unnecessary semicolon.

> +               writel(0, m4u_base + REG_MMU_CPE_DONE);
> +       }
> +
> +       return 0;
> +}
> +
> +static int mtk_iommu_fault_handler(struct iommu_domain *imudomain,
> +                                  struct device *dev, unsigned long iova,
> +                                  int m4uindex, void *pimu)
> +{
> +       void __iomem *m4u_base;
> +       u32 int_state, regval;
> +       int m4u_slave_id = 0;

Why 0? Also this variable doesn't seem to be assigned further in the
code. Should it be a constant? Moreover, shouldn't it be unsigned?

> +       unsigned int layer, write, m4u_port;

Shouldn't layer and write be bool?

> +       unsigned int fault_mva, fault_pa;
> +       struct mtk_iommu_info *piommu = pimu;
> +       struct mtk_iommu_domain *mtkdomain = imudomain->priv;
> +
> +       m4u_base = piommu->m4u_base;
> +       int_state = readl(m4u_base + REG_MMU_MAIN_FAULT_ST);
> +
> +       /* read error info from registers */
> +       fault_mva = readl(m4u_base + REG_MMU_FAULT_VA(m4u_slave_id));
> +       layer = !!(fault_mva & F_MMU_FAULT_VA_LAYER_BIT);
> +       write = !!(fault_mva & F_MMU_FAULT_VA_WRITE_BIT);
> +       fault_mva &= F_MMU_FAULT_VA_MSK;

So I assume the IOMMU virtual address space is 32-bit, so fault_mva
can be unsigned int. However it would be better to use an explicitly
sized type for this, i.e. u32.

> +       fault_pa = readl(m4u_base + REG_MMU_INVLD_PA(m4u_slave_id));

It is not clear from any documentation added by this series how wide
is the physical address space of this IOMMU, especially since the SoC
has ARM64 cores. Please make sure that fault_pa variable is using
explicitly sized type which matches width of the register.

End of part 1. Will continue when I find next chunk of time to spend
on review. :)

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
  2015-03-06 11:30   ` Paul Bolle
@ 2015-03-09  3:26   ` Yingjoe Chen
  2015-03-09 21:56     ` Arnd Bergmann
  2015-03-09 11:03   ` Sascha Hauer
  2 siblings, 1 reply; 55+ messages in thread
From: Yingjoe Chen @ 2015-03-09  3:26 UTC (permalink / raw)
  To: yong.wu, Matthias Brugger, Arnd Bergmann
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Daniel Kurtz, Sasha Hauer,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach

On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> From: Yong Wu <yong.wu@mediatek.com>
> 
>     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> responsible to enable/disable iommu and control the clocks of each
> local arbiter.
> 
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  drivers/soc/mediatek/Kconfig      |   7 ++
>  drivers/soc/mediatek/Makefile     |   1 +
>  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
>  include/linux/mtk-smi.h           |  40 +++++++++++
>  4 files changed, 191 insertions(+)
>  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
>  create mode 100644 include/linux/mtk-smi.h
> 

Hi Arnd, Matthias,

For the SMI driver, we can't find a better place, so we put it in
drivers/soc/mediatek now. Please let us know if you have any suggestion
or concern. Thanks

You can find more description about SMI and how we use it in the cover
letter:
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/328451.html

Joe.C




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
                     ` (2 preceding siblings ...)
  2015-03-08  4:12   ` Tomasz Figa
@ 2015-03-09  8:24   ` Daniel Kurtz
  2015-03-09 11:11   ` Tomasz Figa
  2015-03-11 10:53   ` Tomasz Figa
  5 siblings, 0 replies; 55+ messages in thread
From: Daniel Kurtz @ 2015-03-09  8:24 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	open list:OPEN FIRMWARE AND...,
	linux-kernel, linux-arm-kernel, open list:IOMMU DRIVERS

Hi Yong Wu,

On Fri, Mar 6, 2015 at 6:48 PM,  <yong.wu@mediatek.com> wrote:
> From: Yong Wu <yong.wu@mediatek.com>
>
> This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  drivers/iommu/Kconfig               |  11 +
>  drivers/iommu/Makefile              |   1 +
>  drivers/iommu/mtk_iommu.c           | 754 ++++++++++++++++++++++++++++++++++++
>  drivers/iommu/mtk_iommu.h           |  73 ++++
>  drivers/iommu/mtk_iommu_pagetable.c | 439 +++++++++++++++++++++
>  drivers/iommu/mtk_iommu_pagetable.h |  49 +++
>  6 files changed, 1327 insertions(+)
>  create mode 100644 drivers/iommu/mtk_iommu.c
>  create mode 100644 drivers/iommu/mtk_iommu.h
>  create mode 100644 drivers/iommu/mtk_iommu_pagetable.c
>  create mode 100644 drivers/iommu/mtk_iommu_pagetable.h
>
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 19027bb..e63f5b6 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -326,4 +326,15 @@ config ARM_SMMU
>           Say Y here if your SoC includes an IOMMU device implementing
>           the ARM SMMU architecture.
>
> +config MTK_IOMMU
> +       bool "MTK IOMMU Support"
> +       select IOMMU_API
> +       select IOMMU_DMA
> +       select MTK_SMI
> +       help
> +         Support for the IOMMUs on certain Mediatek SOCs.
> +         These IOMMUs allow the multimedia hardware access discontinuous memory.
> +
> +         If unsure, say N here.
> +
>  endif # IOMMU_SUPPORT
> diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> index 37bfc4e..f2a8027 100644
> --- a/drivers/iommu/Makefile
> +++ b/drivers/iommu/Makefile
> @@ -4,6 +4,7 @@ obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
>  obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
>  obj-$(CONFIG_IOMMU_IOVA) += iova.o
>  obj-$(CONFIG_OF_IOMMU) += of_iommu.o
> +obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o mtk_iommu_pagetable.o
>  obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
>  obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
>  obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
> diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
> new file mode 100644
> index 0000000..d62d4ab
> --- /dev/null
> +++ b/drivers/iommu/mtk_iommu.c
> @@ -0,0 +1,754 @@
> +/*
> + * Copyright (c) 2014-2015 MediaTek Inc.
> + * Author: Yong Wu <yong.wu@mediatek.com>
> + *
> + * 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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt) "m4u:"fmt
> +
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/mm.h>
> +#include <linux/iommu.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/memblock.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/dma-iommu.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/mtk-smi.h>
> +#include <asm/cacheflush.h>
> +
> +#include "mtk_iommu.h"
> +
> +#define REG_MMUG_PT_BASE        0x0

It would be a lot easier to follow the driver if the register names
matched the datasheet:

REG_MMU_PT_BASE_ADDR  0x000
REG_MMU_INT_CONTROL     0x220
REG_MMU_INT_FAULT_ST     0x224
REG_MMU_INVALIDATE          0x5c0
REG_MMU_INVLD_START_A  0x5c4
REG_MMU_INVLD_END_A      0x5c8
REG_MMU_INV_SEL                0x5d8
REG_MMU_DCM                       0x5f0

> +
> +#define REG_MMU_INVLD           0x20
> +#define F_MMU_INV_ALL           0x2
> +#define F_MMU_INV_RANGE                 0x1
> +
> +#define REG_MMU_INVLD_SA        0x24
> +#define REG_MMU_INVLD_EA         0x28
> +
> +#define REG_MMU_INVLD_SEC         0x2c
> +#define F_MMU_INV_SEC_ALL          0x2
> +#define F_MMU_INV_SEC_RANGE        0x1
> +
> +#define REG_INVLID_SEL          0x38
> +#define F_MMU_INV_EN_L1                 BIT(0)
> +#define F_MMU_INV_EN_L2                 BIT(1)
> +
> +#define REG_MMU_STANDARD_AXI_MODE   0x48
> +#define REG_MMU_DCM_DIS             0x50
> +#define REG_MMU_LEGACY_4KB_MODE     0x60
> +
> +#define REG_MMU_CTRL_REG                 0x110
> +#define F_MMU_CTRL_REROUTE_PFQ_TO_MQ_EN  BIT(4)
> +#define F_MMU_CTRL_TF_PROT_VAL(prot)      (((prot) & 0x3)<<5)
> +#define F_MMU_CTRL_COHERE_EN             BIT(8)
> +
> +#define REG_MMU_IVRP_PADDR               0x114
> +#define F_MMU_IVRP_PA_SET(PA)            (PA>>1)
> +
> +#define REG_MMU_INT_L2_CONTROL      0x120
> +#define F_INT_L2_CLR_BIT            BIT(12)
> +
> +#define REG_MMU_INT_MAIN_CONTROL    0x124
> +#define F_INT_TRANSLATION_FAULT(MMU)           (1<<(0+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_MAIN_MULTI_HIT_FAULT(MMU)        (1<<(1+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_INVALID_PA_FAULT(MMU)            (1<<(2+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_ENTRY_REPLACEMENT_FAULT(MMU)     (1<<(3+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_TLB_MISS_FAULT(MMU)              (1<<(4+(((MMU)<<1)|((MMU)<<2))))
> +#define F_INT_PFH_FIFO_ERR(MMU)                (1<<(6+(((MMU)<<1)|((MMU)<<2))))

This is not readable.  For one thing, kernel style is to always place
spaces around operators.
Did you run checkpatch?

Assuming MMU is either 0 or 1, this would shift the error bits for
MMU=1 by "(((MMU) << 1) | ((MMU) << 2))" = 6 bits.
( This "MMU" does not look like it could possibly be correct since
F_INT_PFH_FIFO_ERR(0) == F_INT_TRANSLATION_FAULT(1).

Since in the code below, "MMU" is always m4u_slave_id, (a constant 0),
just remove all of this complexity until it is actually used.
For now just define these macros as:

#define F_INT_TRANSLATION_FAULT        BIT(0)
#define F_INT_MAIN_MULTI_HIT_FAULT     BIT(1)
#define F_INT_INVALID_PA_FAULT         BIT(2)
#define F_INT_ENTRY_REPLACEMENT_FAULT  BIT(3)
#define F_INT_TLB_MISS_FAULT           BIT(4)
#define F_INT_PFH_FIFO_ERR             BIT(6)

A later patch that adds support for slave_id != 0 can then fix up
these macros to do what ever it is you are trying to do here.

> +
> +#define REG_MMU_CPE_DONE              0x12C
> +
> +#define REG_MMU_MAIN_FAULT_ST         0x134
> +
> +#define REG_MMU_FAULT_VA(mmu)         (0x13c+((mmu)<<3))
> +#define F_MMU_FAULT_VA_MSK            ((~0x0)<<12)
> +#define F_MMU_FAULT_VA_WRITE_BIT       BIT(1)
> +#define F_MMU_FAULT_VA_LAYER_BIT       BIT(0)
> +
> +#define REG_MMU_INVLD_PA(mmu)         (0x140+((mmu)<<3))
> +#define REG_MMU_INT_ID(mmu)           (0x150+((mmu)<<2))
> +#define F_MMU0_INT_ID_TF_MSK          (~0x3)   /* only for MM iommu. */
> +
> +#define MTK_TFID(larbid, portid) ((larbid << 7) | (portid << 2))
> +
> +static const struct mtk_iommu_port mtk_iommu_mt8173_port[] = {
> +       /* port name                m4uid slaveid larbid portid tfid */
> +       /* larb0 */
> +       {"M4U_PORT_DISP_OVL0",          0,  0,    0,  0, MTK_TFID(0, 0)},
> +       {"M4U_PORT_DISP_RDMA0",         0,  0,    0,  1, MTK_TFID(0, 1)},
> +       {"M4U_PORT_DISP_WDMA0",         0,  0,    0,  2, MTK_TFID(0, 2)},
> +       {"M4U_PORT_DISP_OD_R",          0,  0,    0,  3, MTK_TFID(0, 3)},
> +       {"M4U_PORT_DISP_OD_W",          0,  0,    0,  4, MTK_TFID(0, 4)},
> +       {"M4U_PORT_MDP_RDMA0",          0,  0,    0,  5, MTK_TFID(0, 5)},
> +       {"M4U_PORT_MDP_WDMA",           0,  0,    0,  6, MTK_TFID(0, 6)},
> +       {"M4U_PORT_MDP_WROT0",          0,  0,    0,  7, MTK_TFID(0, 7)},
> +
> +       /* larb1 */
> +       {"M4U_PORT_HW_VDEC_MC_EXT",      0,  0,   1,  0, MTK_TFID(1, 0)},
> +       {"M4U_PORT_HW_VDEC_PP_EXT",      0,  0,   1,  1, MTK_TFID(1, 1)},
> +       {"M4U_PORT_HW_VDEC_UFO_EXT",     0,  0,   1,  2, MTK_TFID(1, 2)},
> +       {"M4U_PORT_HW_VDEC_VLD_EXT",     0,  0,   1,  3, MTK_TFID(1, 3)},
> +       {"M4U_PORT_HW_VDEC_VLD2_EXT",    0,  0,   1,  4, MTK_TFID(1, 4)},
> +       {"M4U_PORT_HW_VDEC_AVC_MV_EXT",  0,  0,   1,  5, MTK_TFID(1, 5)},
> +       {"M4U_PORT_HW_VDEC_PRED_RD_EXT", 0,  0,   1,  6, MTK_TFID(1, 6)},
> +       {"M4U_PORT_HW_VDEC_PRED_WR_EXT", 0,  0,   1,  7, MTK_TFID(1, 7)},
> +       {"M4U_PORT_HW_VDEC_PPWRAP_EXT",  0,  0,   1,  8, MTK_TFID(1, 8)},
> +
> +       /* larb2 */
> +       {"M4U_PORT_IMGO",                0,  0,    2,  0, MTK_TFID(2, 0)},
> +       {"M4U_PORT_RRZO",                0,  0,    2,  1, MTK_TFID(2, 1)},
> +       {"M4U_PORT_AAO",                 0,  0,    2,  2, MTK_TFID(2, 2)},
> +       {"M4U_PORT_LCSO",                0,  0,    2,  3, MTK_TFID(2, 3)},
> +       {"M4U_PORT_ESFKO",               0,  0,    2,  4, MTK_TFID(2, 4)},
> +       {"M4U_PORT_IMGO_D",              0,  0,    2,  5, MTK_TFID(2, 5)},
> +       {"M4U_PORT_LSCI",                0,  0,    2,  6, MTK_TFID(2, 6)},
> +       {"M4U_PORT_LSCI_D",              0,  0,    2,  7, MTK_TFID(2, 7)},
> +       {"M4U_PORT_BPCI",                0,  0,    2,  8, MTK_TFID(2, 8)},
> +       {"M4U_PORT_BPCI_D",              0,  0,    2,  9, MTK_TFID(2, 9)},
> +       {"M4U_PORT_UFDI",                0,  0,    2,  10, MTK_TFID(2, 10)},
> +       {"M4U_PORT_IMGI",                0,  0,    2,  11, MTK_TFID(2, 11)},
> +       {"M4U_PORT_IMG2O",               0,  0,    2,  12, MTK_TFID(2, 12)},
> +       {"M4U_PORT_IMG3O",               0,  0,    2,  13, MTK_TFID(2, 13)},
> +       {"M4U_PORT_VIPI",                0,  0,    2,  14, MTK_TFID(2, 14)},
> +       {"M4U_PORT_VIP2I",               0,  0,    2,  15, MTK_TFID(2, 15)},
> +       {"M4U_PORT_VIP3I",               0,  0,    2,  16, MTK_TFID(2, 16)},
> +       {"M4U_PORT_LCEI",                0,  0,    2,  17, MTK_TFID(2, 17)},
> +       {"M4U_PORT_RB",                  0,  0,    2,  18, MTK_TFID(2, 18)},
> +       {"M4U_PORT_RP",                  0,  0,    2,  19, MTK_TFID(2, 19)},
> +       {"M4U_PORT_WR",                  0,  0,    2,  20, MTK_TFID(2, 20)},
> +
> +       /* larb3 */
> +       {"M4U_PORT_VENC_RCPU",            0,  0,   3,  0, MTK_TFID(3, 0)},
> +       {"M4U_PORT_VENC_REC",             0,  0,   3,  1, MTK_TFID(3, 1)},
> +       {"M4U_PORT_VENC_BSDMA",           0,  0,   3,  2, MTK_TFID(3, 2)},
> +       {"M4U_PORT_VENC_SV_COMV",         0,  0,   3,  3, MTK_TFID(3, 3)},
> +       {"M4U_PORT_VENC_RD_COMV",         0,  0,   3,  4, MTK_TFID(3, 4)},
> +       {"M4U_PORT_JPGENC_RDMA",          0,  0,   3,  5, MTK_TFID(3, 5)},
> +       {"M4U_PORT_JPGENC_BSDMA",         0,  0,   3,  6, MTK_TFID(3, 6)},
> +       {"M4U_PORT_JPGDEC_WDMA",          0,  0,   3,  7, MTK_TFID(3, 7)},
> +       {"M4U_PORT_JPGDEC_BSDMA",         0,  0,   3,  8, MTK_TFID(3, 8)},
> +       {"M4U_PORT_VENC_CUR_LUMA",        0,  0,   3,  9, MTK_TFID(3, 9)},
> +       {"M4U_PORT_VENC_CUR_CHROMA",      0,  0,   3,  10, MTK_TFID(3, 10)},
> +       {"M4U_PORT_VENC_REF_LUMA",        0,  0,   3,  11, MTK_TFID(3, 11)},
> +       {"M4U_PORT_VENC_REF_CHROMA",      0,  0,   3,  12, MTK_TFID(3, 12)},
> +       {"M4U_PORT_VENC_NBM_RDMA",        0,  0,   3,  13, MTK_TFID(3, 13)},
> +       {"M4U_PORT_VENC_NBM_WDMA",        0,  0,   3,  14, MTK_TFID(3, 14)},
> +
> +       /* larb4 */
> +       {"M4U_PORT_DISP_OVL1",             0,  0,   4,  0, MTK_TFID(4, 0)},
> +       {"M4U_PORT_DISP_RDMA1",            0,  0,   4,  1, MTK_TFID(4, 1)},
> +       {"M4U_PORT_DISP_RDMA2",            0,  0,   4,  2, MTK_TFID(4, 2)},
> +       {"M4U_PORT_DISP_WDMA1",            0,  0,   4,  3, MTK_TFID(4, 3)},
> +       {"M4U_PORT_MDP_RDMA1",             0,  0,   4,  4, MTK_TFID(4, 4)},
> +       {"M4U_PORT_MDP_WROT1",             0,  0,   4,  5, MTK_TFID(4, 5)},
> +
> +       /* larb5 */
> +       {"M4U_PORT_VENC_RCPU_SET2",        0,  0,    5,  0, MTK_TFID(5, 0)},
> +       {"M4U_PORT_VENC_REC_FRM_SET2",     0,  0,    5,  1, MTK_TFID(5, 1)},
> +       {"M4U_PORT_VENC_REF_LUMA_SET2",    0,  0,    5,  2, MTK_TFID(5, 2)},
> +       {"M4U_PORT_VENC_REC_CHROMA_SET2",  0,  0,    5,  3, MTK_TFID(5, 3)},
> +       {"M4U_PORT_VENC_BSDMA_SET2",       0,  0,    5,  4, MTK_TFID(5, 4)},
> +       {"M4U_PORT_VENC_CUR_LUMA_SET2",    0,  0,    5,  5, MTK_TFID(5, 5)},
> +       {"M4U_PORT_VENC_CUR_CHROMA_SET2",  0,  0,    5,  6, MTK_TFID(5, 6)},
> +       {"M4U_PORT_VENC_RD_COMA_SET2",     0,  0,    5,  7, MTK_TFID(5, 7)},
> +       {"M4U_PORT_VENC_SV_COMA_SET2",     0,  0,    5,  8, MTK_TFID(5, 8)},
> +
> +       /* perisys iommu */
> +       {"M4U_PORT_RESERVE",               1,  0,    6,  0, 0xff},
> +       {"M4U_PORT_SPM",                   1,  0,    6,  1, 0x50},
> +       {"M4U_PORT_MD32",                  1,  0,    6,  2, 0x90},
> +       {"M4U_PORT_PTP_THERM",             1,  0,    6,  4, 0xd0},
> +       {"M4U_PORT_PWM",                   1,  0,    6,  5, 0x1},
> +       {"M4U_PORT_MSDC1",                 1,  0,    6,  6, 0x21},
> +       {"M4U_PORT_MSDC2",                 1,  0,    6,  7, 0x41},
> +       {"M4U_PORT_NFI",                   1,  0,    6,  8, 0x8},
> +       {"M4U_PORT_AUDIO",                 1,  0,    6,  9, 0x48},
> +       {"M4U_PORT_RESERVED2",             1,  0,    6,  10, 0xfe},
> +       {"M4U_PORT_HSIC_XHCI",             1,  0,    6,  11, 0x9},
> +
> +       {"M4U_PORT_HSIC_MAS",              1,  0,    6,  12, 0x11},
> +       {"M4U_PORT_HSIC_DEV",              1,  0,    6,  13, 0x19},
> +       {"M4U_PORT_AP_DMA",                1,  0,    6,  14, 0x18},
> +       {"M4U_PORT_HSIC_DMA",              1,  0,    6,  15, 0xc8},
> +       {"M4U_PORT_MSDC0",                 1,  0,    6,  16, 0x0},
> +       {"M4U_PORT_MSDC3",                 1,  0,    6,  17, 0x20},
> +       {"M4U_PORT_UNKNOWN",               1,  0,    6,  18, 0xf},
> +};
> +
> +static const struct mtk_iommu_cfg mtk_iommu_mt8173_cfg = {
> +       .larb_nr = 6,
> +       .m4u_port_nr = ARRAY_SIZE(mtk_iommu_mt8173_port),
> +       .pport = mtk_iommu_mt8173_port,
> +};
> +
> +static const char *mtk_iommu_get_port_name(const struct mtk_iommu_info *piommu,
> +                                          unsigned int portid)
> +{
> +       const struct mtk_iommu_port *pcurport = NULL;

No need for NULL init.

> +
> +       pcurport = piommu->imucfg->pport + portid;
> +       if (portid < piommu->imucfg->m4u_port_nr && pcurport)

The pcurport NULL check is a bit superfluous here, right?

> +               return pcurport->port_name;
> +       else
> +               return "UNKNOWN_PORT";
> +}
> +
> +static int mtk_iommu_get_port_by_tfid(const struct mtk_iommu_info *pimu,
> +                                     int tf_id)
> +{
> +       const struct mtk_iommu_cfg *pimucfg = pimu->imucfg;
> +       int i;
> +       unsigned int portid = pimucfg->m4u_port_nr;
> +
> +       for (i = 0; i < pimucfg->m4u_port_nr; i++) {
> +               if (pimucfg->pport[i].tf_id == tf_id) {
> +                       portid = i;
> +                       break;
> +               }
> +       }
> +       if (i == pimucfg->m4u_port_nr)
> +               dev_err(pimu->dev, "tf_id find fail, tfid %d\n", tf_id);
> +       return portid;
> +}
> +
> +static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
> +{
> +       struct iommu_domain *domain = dev_id;
> +       struct mtk_iommu_domain *mtkdomain = domain->priv;
> +       struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
> +
> +       if (irq == piommu->irq)
> +               report_iommu_fault(domain, piommu->dev, 0, 0);
> +       else
> +               dev_err(piommu->dev, "irq number:%d\n", irq);

If this isr doesn't handle the irq, return IRQ_NONE, not IRQ_HANDLED.

> +
> +       return IRQ_HANDLED;
> +}
> +

*snip*

Ok, enough for now :-).

Best Regards,
-Dan

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
  2015-03-06 11:30   ` Paul Bolle
  2015-03-09  3:26   ` Yingjoe Chen
@ 2015-03-09 11:03   ` Sascha Hauer
  2 siblings, 0 replies; 55+ messages in thread
From: Sascha Hauer @ 2015-03-09 11:03 UTC (permalink / raw)
  To: yong.wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Daniel Kurtz, Sasha Hauer,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach

On Fri, Mar 06, 2015 at 06:48:16PM +0800, yong.wu@mediatek.com wrote:
> From: Yong Wu <yong.wu@mediatek.com>
> 
>     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> responsible to enable/disable iommu and control the clocks of each
> local arbiter.
> 
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
>  drivers/soc/mediatek/Kconfig      |   7 ++
>  drivers/soc/mediatek/Makefile     |   1 +
>  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
>  include/linux/mtk-smi.h           |  40 +++++++++++

I just posted the power domain driver for prividing the domains this
driver uses. You should base your code on that.

> +#include <linux/mm.h>
> +
> +#define SMI_LARB_MMU_EN                 (0xf00)
> +#define F_SMI_MMU_EN(port)              (1 << (port))
> +
> +struct mtk_smi_larb {
> +	void __iomem *larb_base;
> +	struct clk *larb_clk[3];/* each larb has 3 clk at most */
> +};
> +
> +static const char * const mtk_smi_clk_name[] = {
> +	"larb_sub0", "larb_sub1", "larb_sub2"
> +};
> +
> +static const struct of_device_id mtk_smi_of_ids[] = {
> +	{ .compatible = "mediatek,mt8173-smi-larb",
> +	},

Add a newline after the opening brace.

> +int mtk_smi_config_port(struct platform_device *plarbdev,
> +			unsigned int larbportid)
> +{
> +	struct mtk_smi_larb *larbpriv = dev_get_drvdata(&plarbdev->dev);
> +	int ret;
> +	u32 reg;
> +
> +	ret = mtk_smi_larb_get(plarbdev);
> +	if (ret)
> +		return ret;
> +
> +	reg = readl(larbpriv->larb_base + SMI_LARB_MMU_EN);
> +	reg &= ~F_SMI_MMU_EN(larbportid);
> +	reg |= F_SMI_MMU_EN(larbportid);

This sets the very same bits that are cleared one line above. This is
surely not what you want.

> +	writel(reg, larbpriv->larb_base + SMI_LARB_MMU_EN);
> +
> +	mtk_smi_larb_put(plarbdev);
> +
> +	return 0;
> +}
> +
> +static int mtk_smi_probe(struct platform_device *pdev)
> +{
> +	struct mtk_smi_larb *larbpriv;
> +	struct resource *res;
> +	struct device *dev = &pdev->dev;
> +	unsigned int i;
> +
> +	larbpriv = devm_kzalloc(dev, sizeof(struct mtk_smi_larb), GFP_KERNEL);

sizeof(*larbpriv)

> +	if (!larbpriv)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	larbpriv->larb_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(larbpriv->larb_base)) {
> +		dev_err(dev, "larbbase %p err\n", larbpriv->larb_base);

You can print an error number with %ld and PTR_ERR(larbpriv->larb_base).
Printing the pointer is not that helpful.

> +/*
> + * Enable iommu for each port, it is only for iommu.
> + *
> + * Returns 0 if successfully, others if failed.
> + */
> +int mtk_smi_config_port(struct platform_device *pdev,
> +			unsigned int larbportid);
> +
> +/*
> + * The multimedia module should call the two function below
> + * which help open/close the clock of the larb.
> + * so the client dtsi should add the larb like "larb = <&larb0>"
> + * to get platform_device.
> + *
> + * mtk_smi_larb_get should be called before the multimedia h/w work.
> + * mtk_smi_larb_put should be called after h/w done.
> + *
> + * Returns 0 if successfully, others if failed.
> + */
> +int mtk_smi_larb_get(struct platform_device *plarbdev);
> +void mtk_smi_larb_put(struct platform_device *plarbdev);

The function documentation usually comes with the definition of a
function, not its declaration.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
                     ` (3 preceding siblings ...)
  2015-03-09  8:24   ` Daniel Kurtz
@ 2015-03-09 11:11   ` Tomasz Figa
  2015-03-09 14:46     ` Yingjoe Chen
  2015-03-11 10:53   ` Tomasz Figa
  5 siblings, 1 reply; 55+ messages in thread
From: Tomasz Figa @ 2015-03-09 11:11 UTC (permalink / raw)
  To: Yong Wu (吴勇)
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi,

You can find part 2 of my comments inline.

On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:

[snip]

> +static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
> +{
> +       struct iommu_domain *domain = dev_id;
> +       struct mtk_iommu_domain *mtkdomain = domain->priv;
> +       struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
> +
> +       if (irq == piommu->irq)
> +               report_iommu_fault(domain, piommu->dev, 0, 0);

In addition to my previous comment about how this gets called from
this handler, you need to keep in mind that the function called by
report_iommu_fault() might actually be a different function than
mtk_iommu_fault_handler(), because upper layers can provide their own
handlers. This means that you need to perform any operations on
hardware from this handler and only use the iommu fault handler as a
way to tell an upper layer about the fault (including notifying the
user through kernel log if there is no special handler installed and
the generic fallback is used).

> +       else
> +               dev_err(piommu->dev, "irq number:%d\n", irq);
> +
> +       return IRQ_HANDLED;
> +}

[snip]

> +static int mtk_iommu_fault_handler(struct iommu_domain *imudomain,
> +                                  struct device *dev, unsigned long iova,
> +                                  int m4uindex, void *pimu)
> +{
> +       void __iomem *m4u_base;
> +       u32 int_state, regval;
> +       int m4u_slave_id = 0;
> +       unsigned int layer, write, m4u_port;
> +       unsigned int fault_mva, fault_pa;
> +       struct mtk_iommu_info *piommu = pimu;
> +       struct mtk_iommu_domain *mtkdomain = imudomain->priv;
> +
> +       m4u_base = piommu->m4u_base;
> +       int_state = readl(m4u_base + REG_MMU_MAIN_FAULT_ST);
> +
> +       /* read error info from registers */
> +       fault_mva = readl(m4u_base + REG_MMU_FAULT_VA(m4u_slave_id));
> +       layer = !!(fault_mva & F_MMU_FAULT_VA_LAYER_BIT);
> +       write = !!(fault_mva & F_MMU_FAULT_VA_WRITE_BIT);
> +       fault_mva &= F_MMU_FAULT_VA_MSK;
> +       fault_pa = readl(m4u_base + REG_MMU_INVLD_PA(m4u_slave_id));
> +       regval = readl(m4u_base + REG_MMU_INT_ID(m4u_slave_id));
> +       regval &= F_MMU0_INT_ID_TF_MSK;
> +       m4u_port = mtk_iommu_get_port_by_tfid(piommu, regval);
> +
> +       if (int_state & F_INT_TRANSLATION_FAULT(m4u_slave_id)) {
> +               struct m4u_pte_info_t pte;
> +               unsigned long flags;
> +
> +               spin_lock_irqsave(&mtkdomain->pgtlock, flags);
> +               m4u_get_pte_info(mtkdomain, fault_mva, &pte);
> +               spin_unlock_irqrestore(&mtkdomain->pgtlock, flags);
> +
> +               if (pte.size == MMU_SMALL_PAGE_SIZE ||
> +                   pte.size == MMU_LARGE_PAGE_SIZE) {
> +                       dev_err_ratelimited(
> +                               dev,
> +                               "fault:port=%s iova=0x%x pa=0x%x layer=%d %s;"
> +                               "pgd(0x%x)->pte(0x%x)->pa(%pad)sz(0x%x)Valid(%d)\n",
> +                               mtk_iommu_get_port_name(piommu, m4u_port),
> +                               fault_mva, fault_pa, layer,
> +                               write ? "write" : "read",
> +                               imu_pgd_val(*pte.pgd), imu_pte_val(*pte.pte),
> +                               &pte.pa, pte.size, pte.valid);
> +               } else {
> +                       dev_err_ratelimited(
> +                               dev,
> +                               "fault:port=%s iova=0x%x pa=0x%x layer=%d %s;"
> +                               "pgd(0x%x)->pa(%pad)sz(0x%x)Valid(%d)\n",
> +                               mtk_iommu_get_port_name(piommu, m4u_port),
> +                               fault_mva, fault_pa, layer,
> +                               write ? "write" : "read",
> +                               imu_pgd_val(*pte.pgd),
> +                               &pte.pa, pte.size, pte.valid);
> +               }
> +       }
> +
> +       if (int_state & F_INT_MAIN_MULTI_HIT_FAULT(m4u_slave_id))
> +               dev_err_ratelimited(dev, "multi-hit!port=%s iova=0x%x\n",
> +                                   mtk_iommu_get_port_name(piommu, m4u_port),
> +                                   fault_mva);
> +
> +       if (int_state & F_INT_INVALID_PA_FAULT(m4u_slave_id)) {
> +               if (!(int_state & F_INT_TRANSLATION_FAULT(m4u_slave_id)))
> +                       dev_err_ratelimited(dev, "invalid pa!port=%s iova=0x%x\n",
> +                                           mtk_iommu_get_port_name(piommu,
> +                                                                   m4u_port),
> +                                           fault_mva);
> +       }
> +       if (int_state & F_INT_ENTRY_REPLACEMENT_FAULT(m4u_slave_id))
> +               dev_err_ratelimited(dev, "replace-fault!port=%s iova=0x%x\n",
> +                                   mtk_iommu_get_port_name(piommu, m4u_port),
> +                                   fault_mva);
> +
> +       if (int_state & F_INT_TLB_MISS_FAULT(m4u_slave_id))
> +               dev_err_ratelimited(dev, "tlb miss-fault!port=%s iova=0x%x\n",
> +                                   mtk_iommu_get_port_name(piommu, m4u_port),
> +                                   fault_mva);
> +
> +       mtk_iommu_invalidate_tlb(piommu, 1, 0, 0);
> +
> +       mtk_iommu_clear_intr(m4u_base);

As per my comment above, most of what is happening in this function
should be actually done in interrupt handler, excluding printing of
course.

> +
> +       return 0;
> +}
> +
> +static int mtk_iommu_parse_dt(struct platform_device *pdev,
> +                             struct mtk_iommu_info *piommu)
> +{
> +       struct device *piommudev = &pdev->dev;
> +       struct device_node *ofnode;
> +       struct resource *res;
> +       unsigned int mtk_iommu_cell = 0;
> +       unsigned int i;
> +
> +       ofnode = piommudev->of_node;

You could do this assignment on the same line as declaration.

nit: The usual naming convention for such variables are "dev" for
struct device * and "np" for struct device_node *.

> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       piommu->m4u_base = devm_ioremap_resource(&pdev->dev, res);

nit: There doesn't seem to be any other "bases" involved in this
driver. Could you simply name the field "base", without the obvious
prefix "m4u_"?

> +       if (IS_ERR(piommu->m4u_base)) {
> +               dev_err(piommudev, "m4u_base %p err\n", piommu->m4u_base);
> +               goto iommu_dts_err;
> +       }
> +
> +       piommu->irq = platform_get_irq(pdev, 0);
> +       if (piommu->irq < 0) {
> +               dev_err(piommudev, "irq err %d\n", piommu->irq);

Please keep the messages human readable, e.g. "Failed to get IRQ (%d)\n"

> +               goto iommu_dts_err;
> +       }
> +
> +       piommu->m4u_infra_clk = devm_clk_get(piommudev, "infra_m4u");
> +       if (IS_ERR(piommu->m4u_infra_clk)) {
> +               dev_err(piommudev, "clk err %p\n", piommu->m4u_infra_clk);

"Failed to get clock 'infra_m4u' (%d)\n" (and extract the error code
using PTR_ERR() helper.

> +               goto iommu_dts_err;
> +       }
> +
> +       of_property_read_u32(ofnode, "#iommu-cells", &mtk_iommu_cell);
> +       if (mtk_iommu_cell != 1) {
> +               dev_err(piommudev, "iommu-cell fail:%d\n", mtk_iommu_cell);
> +               goto iommu_dts_err;
> +       }

I don't think you should be checking this here. The function
performing translation from phandle and specifier should check whether
the correct cell count was provided.

> +
> +       for (i = 0; i < piommu->imucfg->larb_nr; i++) {
> +               struct device_node *larbnode;
> +
> +               larbnode = of_parse_phandle(ofnode, "larb", i);
> +               piommu->larbpdev[i] = of_find_device_by_node(larbnode);
> +               of_node_put(larbnode);

I need to take a look at further changes, but this looks like syscon
should be used here instead of using the device directly.

> +               if (!piommu->larbpdev[i]) {
> +                       dev_err(piommudev, "larb pdev fail@larb%d\n", i);
> +                       goto iommu_dts_err;
> +               }
> +       }
> +
> +       return 0;
> +
> +iommu_dts_err:
> +       return -EINVAL;

Please return the return value that actually brought us here.

> +}
> +
> +static int mtk_iommu_hw_init(const struct mtk_iommu_domain *mtkdomain)
> +{
> +       struct mtk_iommu_info *piommu = mtkdomain->piommuinfo;
> +       void __iomem *gm4ubaseaddr = piommu->m4u_base;

Hmm, gm4ubaseaddr is exactly as long as piommu->base (if you follow my
comment to rename this field). In general,

> +       phys_addr_t protectpa;
> +       u32 regval, protectreg;
> +       int ret = 0;
> +
> +       ret = clk_prepare_enable(piommu->m4u_infra_clk);
> +       if (ret) {
> +               dev_err(piommu->dev, "m4u clk enable error\n");
> +               return -ENODEV;
> +       }
> +
> +       writel((u32)mtkdomain->pgd_pa, gm4ubaseaddr + REG_MMUG_PT_BASE);

Why this has to be casted? Is the type of pgd_pa field correct?

> +
> +       regval = F_MMU_CTRL_REROUTE_PFQ_TO_MQ_EN |
> +               F_MMU_CTRL_TF_PROT_VAL(2) |
> +               F_MMU_CTRL_COHERE_EN;
> +       writel(regval, gm4ubaseaddr + REG_MMU_CTRL_REG);
> +
> +       writel(0x6f, gm4ubaseaddr + REG_MMU_INT_L2_CONTROL);
> +       writel(0xffffffff, gm4ubaseaddr + REG_MMU_INT_MAIN_CONTROL);

Please define all the bitfields and use the definitions here instead
of magic numbers.

> +
> +       /* protect memory,HW will write here while translation fault */
> +       protectpa = __virt_to_phys(piommu->protect_va);

Why the underscore variant? virt_to_phys() should be just fine.

> +       protectpa = ALIGN(protectpa, MTK_PROTECT_PA_ALIGN);

Shouldn't protect_va be already aligned?

> +       protectreg = (u32)F_MMU_IVRP_PA_SET(protectpa);

Again, why is this cast needed?

> +       writel(protectreg, gm4ubaseaddr + REG_MMU_IVRP_PADDR);
> +
> +       writel(0, gm4ubaseaddr + REG_MMU_DCM_DIS);
> +       writel(0, gm4ubaseaddr + REG_MMU_STANDARD_AXI_MODE);
> +
> +       return 0;
> +}
> +
> +static inline void mtk_iommu_config_port(struct mtk_iommu_info *piommu,
> +                                        int portid)

Please let the compiler decide whether to inline this function or not.

> +{
> +       int larb, larb_port;
> +
> +       larb = piommu->imucfg->pport[portid].larb_id;
> +       larb_port = piommu->imucfg->pport[portid].port_id;
> +
> +       mtk_smi_config_port(piommu->larbpdev[larb], larb_port);
> +}
> +
> +/*
> + * pimudev is a global var for dma_alloc_coherent.
> + * It is not accepatable, we will delete it if "domain_alloc" is enabled
> + */
> +static struct device *pimudev;

This is indeed not acceptable. Could you replace dma_alloc_coherent()
with something that doesn't require device pointer, e.g.
alloc_pages()? (Although that would require you to handle cache
maintenance in the driver, due to cached memory allocated.) I need to
think about a better solution for this.

OK. Enough for part 2. Stay tuned for part 3.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU
  2015-03-06 11:21   ` Mark Rutland
@ 2015-03-09 11:30     ` Yong Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-09 11:30 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Dear Mark,

     Thanks very much for your review.
     I will fix them in the next verion.

On Fri, 2015-03-06 at 11:21 +0000, Mark Rutland wrote:
> On Fri, Mar 06, 2015 at 10:48:19AM +0000, yong.wu@mediatek.com wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> > 
> > This patch add mediatek iommu dts binding document.
> > 
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > ---
> >  .../devicetree/bindings/iommu/mediatek,iommu.txt   | 41 ++++++++++++++++++++++
> >  1 file changed, 41 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> > new file mode 100644
> > index 0000000..db01c92
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> > @@ -0,0 +1,41 @@
> > +/******************************************************/
> > +/*    Mediatek IOMMU Hardware block diagram           */
> > +/******************************************************/
> > +              EMI (External Memory Interface)
> > +               |
> > +              m4u (Multimedia Memory Management Unit)
> > +               |
> > +              smi (Smart Multimedia Interface)
> > +               |
> > +        +---------------+-------
> > +        |               |
> > +        |               |
> > +    vdec larb       disp larb      ... SoCs have different local arbiter(larb).
> > +        |               |
> > +        |               |
> > +   +----+----+    +-----+-----+
> > +   |    |    |    |     |     |    ...
> > +   |    |    |    |     |     |    ...
> > +   |    |    |    |     |     |    ...
> > +  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... There are different ports in each larb.
> > +
> > +Required properties:
> > +- compatible : must be "mediatek,mt8173-iommu"
> 
> s/iommu/m4u/ -- the name should match what the hardware is called.
> 
> > +- reg : m4u register base
> 
> ... and size
> 
> > +- interrupts : must contain the interrupts from each internal translation unit
> 
> How many "internal translation units" are there?
> 
> How should the interrupts be ordered?
> 
> How do these relate to the larbs?
   There is only one internal translation units in MT8173.(2 units in
MT8135)
   Because this patch is only for mt8173, so I will change it like this:

interrupts : the interrupt of the m4u.
    is it ok?
> 
> > +- clocks : must contain one entry for each clock-name
> > +- clock-name: m4u clock
> 
> This does not match the example.
> 
> s/clock-name/clock-names/
> 
> Please format this like a list, with names quoted, e.g.
> 
> - clock-names: must contain:
>   * "m4u" - The functional clock for the m4u
> 
> > +- larb : must contain the larbes of current platform
> 
> s/larbes/local arbiters/
> 
> How should these be ordered? Surely there's a relationship with
> registers/interrupts/etc in this unit?
> 
> > +- iommu-cells : must be 1. Specifies the client PortID as defined in
> > +dt-binding/iommu/mt**-iommu-port.h
> 
> Give the absolute filename.
> 
> The include file should be added in this patch (it's part of the
> binding). The whole patch should be moved earlier in the series.
> 
> Thanks,
> Mark.
> 
> > +
> > +Example:
> > +		iommu: mmsys_iommu@10205000 {
> > +			compatible = "mediatek,mt8173-iommu";
> > +			reg = <0 0x10205000 0 0x1000>;
> > +			interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
> > +			clocks = <&infrasys INFRA_M4U>;
> > +			clock-names = "infra_m4u";
> > +			larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
> > +			#iommu-cells = <1>;
> > +		};
> > \ No newline at end of file
> > -- 
> > 1.8.1.1.dirty
> > 
> > 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-06 11:30   ` Paul Bolle
@ 2015-03-09 11:57     ` Yong Wu
  2015-03-09 17:59       ` Paul Bolle
  0 siblings, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-03-09 11:57 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Mark Rutland, Catalin Marinas, linux-mediatek, Sasha Hauer,
	srv_heupstream, devicetree, linux-kernel, linux-arm-kernel,
	iommu

Dear Paul,
      Thanks very much for your suggestion.

On Fri, 2015-03-06 at 12:30 +0100, Paul Bolle wrote:
> On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > --- a/drivers/soc/mediatek/Kconfig
> > +++ b/drivers/soc/mediatek/Kconfig
> > @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
> >  	  PMIC wrapper is a proprietary hardware in MT8173 to make
> >  	  communication protocols to access PMIC device.
> >  	  This driver implement access protocols for MT8173.
> > +
> > +config MTK_SMI
> > +        bool
> 
> Nit: make this one tab instead of 8 spaces, please.
> 
> > +	help
> > +	  Smi help enable/disable iommu in mt8173 and control the
> > +	  clock of each local arbiter.
> > +	  It should be true while MTK_IOMMU enable.
> 
> I don't think anyone using the *config tools will ever see this text, as
> there's no prompt. So you might as well make this a comment or drop it
> altogether.
> 
     We could search it in the tool even though we don't see it. In next
version, I will try to make it a comment.
> Is this selected by more than just MTK_IOMMU (see 2/5)? If not, I think
> MTK_SMI will be set and unset in lockstep with MTK_IOMMU. In other
> words, you could as well use one Kconfig symbol.
> 
> Thanks,
    if we disable MTK_IOMMU, the MTK_SMI also should be selected.That is because 
if the multimedia h/w want to work, the clock of the local arbiters always should be opened.
> 
> Paul Bolle
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:58   ` Will Deacon
@ 2015-03-09 12:11     ` Yong Wu
  2015-03-17 15:14       ` Will Deacon
  0 siblings, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-03-09 12:11 UTC (permalink / raw)
  To: Will Deacon
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Daniel Kurtz, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Dear Will,

On Fri, 2015-03-06 at 10:58 +0000, Will Deacon wrote:
> On Fri, Mar 06, 2015 at 10:48:17AM +0000, yong.wu@mediatek.com wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> > 
> > This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> > Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
> 
> [...]
> 
> > diff --git a/drivers/iommu/mtk_iommu_pagetable.c b/drivers/iommu/mtk_iommu_pagetable.c
> > new file mode 100644
> > index 0000000..5fe9640
> > --- /dev/null
> > +++ b/drivers/iommu/mtk_iommu_pagetable.c
> > @@ -0,0 +1,439 @@
> > +/*
> > + * Copyright (c) 2014-2015 MediaTek Inc.
> > + * Author: Yong Wu <yong.wu@mediatek.com>
> > + *
> > + * 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.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + */
> > +#include <linux/err.h>
> > +#include <linux/mm.h>
> > +#include <linux/iommu.h>
> > +#include <linux/errno.h>
> > +#include "asm/cacheflush.h"
> > +
> > +#include "mtk_iommu.h"
> > +#include "mtk_iommu_pagetable.h"
> > +
> > +/* 2 level pagetable: pgd -> pte */
> > +#define F_PTE_TYPE_GET(regval)  (regval & 0x3)
> > +#define F_PTE_TYPE_LARGE         BIT(0)
> > +#define F_PTE_TYPE_SMALL         BIT(1)
> > +#define F_PTE_B_BIT              BIT(2)
> > +#define F_PTE_C_BIT              BIT(3)
> > +#define F_PTE_BIT32_BIT          BIT(9)
> > +#define F_PTE_S_BIT              BIT(10)
> > +#define F_PTE_NG_BIT             BIT(11)
> > +#define F_PTE_PA_LARGE_MSK            (~0UL << 16)
> > +#define F_PTE_PA_LARGE_GET(regval)    ((regval >> 16) & 0xffff)
> > +#define F_PTE_PA_SMALL_MSK            (~0UL << 12)
> > +#define F_PTE_PA_SMALL_GET(regval)    ((regval >> 12) & (~0))
> > +#define F_PTE_TYPE_IS_LARGE_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> > +                                       F_PTE_TYPE_LARGE)
> > +#define F_PTE_TYPE_IS_SMALL_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> > +                                       F_PTE_TYPE_SMALL)
> 
> This looks like the ARM short-descriptor format to me. Could you please
> add a new page table format to the io-pgtable code, so that other IOMMU
> drivers can make use of this? I know there was some interest in using
> short descriptor for the ARM SMMU, for example.
    Currently I not familiar with the io-pgtable,I may need some time
for it and the ARM short-descriptor. 
    And there are some difference between mediatek's pagetable with the
standard short-descriptor, like bit 9. we use it for the dram over 4GB.
Then how should we do if there are some difference. 
> 
> Cheers,
> 
> Will



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 17:15   ` Mitchel Humpherys
@ 2015-03-09 12:16     ` Yong Wu
  2015-03-09 16:57       ` Mitchel Humpherys
  0 siblings, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-03-09 12:16 UTC (permalink / raw)
  To: Mitchel Humpherys
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Daniel Kurtz, Sasha Hauer,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach

Dear Mitchel,
     Thanks very much for your review.

On Fri, 2015-03-06 at 09:15 -0800, Mitchel Humpherys wrote:
> On Fri, Mar 06 2015 at 02:48:17 AM, <yong.wu@mediatek.com> wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> >
> > This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> > Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
> 
> [...]
> 
> > +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
> > +				    int isinvall, unsigned int iova_start,
> > +				    unsigned int iova_end)
> > +{
> > +	void __iomem *m4u_base = piommu->m4u_base;
> > +	u32 val;
> > +	u64 start, end;
> > +
> > +	start = sched_clock();
> > +
> > +	if (!isinvall) {
> > +		iova_start = round_down(iova_start, SZ_4K);
> > +		iova_end = round_up(iova_end, SZ_4K);
> > +	}
> > +
> > +	val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
> > +
> > +	writel(val, m4u_base + REG_INVLID_SEL);
> > +
> > +	if (isinvall) {
> > +		writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> > +	} else {
> > +		writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
> > +		writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
> > +		writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
> > +
> > +		while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
> > +			end = sched_clock();
> > +			if (end - start >= 100000000ULL) {
> > +				dev_warn(piommu->dev, "invalid don't done\n");
> > +				writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> > +			}
> > +		};
> 
> Superfluous `;'.  Also, maybe you should be using readl_poll_timeout?
   Thanks.
   For the "readl_poll_timeout", My base is 3.19-rc7 and robin's patch.
it don't have this interface.  I will try to add it in the next version.
> 
> > +		writel(0, m4u_base + REG_MMU_CPE_DONE);
> > +	}
> > +
> > +	return 0;
> > +}
> 
> 
> 
> -Mitch
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173
  2015-03-07 15:20   ` Daniel Kurtz
@ 2015-03-09 12:18     ` Yong Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-09 12:18 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	open list:OPEN FIRMWARE AND...,
	linux-kernel, linux-arm-kernel, open list:IOMMU DRIVERS

Dear Daniel,

     Thanks very much. I will fix this in next version.

On Sat, 2015-03-07 at 23:20 +0800, Daniel Kurtz wrote:
> Hi Yong,
> 
> On Fri, Mar 6, 2015 at 6:48 PM,  <yong.wu@mediatek.com> wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> >
> > This patch add the iommu/larbs nodes for mt8173
> >
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > ---
> >  arch/arm64/boot/dts/mediatek/mt8173.dtsi      |  60 ++++++++++++
> >  include/dt-bindings/iommu/mt8173-iommu-port.h | 127 ++++++++++++++++++++++++++
> >  2 files changed, 187 insertions(+)
> >  create mode 100644 include/dt-bindings/iommu/mt8173-iommu-port.h
> >
> > diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > index c2a057f..805a7cd 100644
> > --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
> > @@ -16,6 +16,7 @@
> >  #include <dt-bindings/reset-controller/mt8173-resets.h>
> >  #include "mt8173-pinfunc.h"
> >  #include <dt-bindings/clock/mt8173-clk.h>
> > +#include <dt-bindings/iommu/mt8173-iommu-port.h>
> >
> >  / {
> >         compatible = "mediatek,mt8173";
> > @@ -249,6 +250,65 @@
> >                         interrupts = <0 86 8>;
> >                         clocks = <&uart_clk>;
> >                 };
> > +
> > +               iommu: mmsys_iommu@10205000 {
> > +                       compatible = "mediatek,mt8173-iommu";
> > +                       reg = <0 0x10205000 0 0x1000>;
> > +                       interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
> > +                       clocks = <&infrasys INFRA_M4U>;
> > +                       clock-names = "infra_m4u";
> > +                       larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
> > +                       #iommu-cells = <1>;
> > +               };
> > +
> > +               larb0:larb@14021000 {
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x14021000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB0>;
> > +                       clock-names = "larb_sub0", "larb_sub1";
> > +               };
> > +
> > +               larb1:larb@16010000 {
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x16010000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>,
> > +                                       <&vdecsys VDEC_CKEN>,
> > +                                       <&vdecsys VDEC_LARB_CKEN>;
> > +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +               };
> > +
> > +               larb2:larb@16010000 {
> 
> I think this one should be:
>    larb2: larb@15001000 {
> 
> Also, I am not a devicetree expert, but I believe nodes are usually
> arranged in register order.
> If that is the case, the order, as unfortunate as this looks, should be:
> 
>  larb0: larb@14021000
>  larb4: larb@14027000
>  larb2: larb@15001000
>  larb1: larb@16010000
>  larb3: larb@18001000
>  larb5: larb@19001000
> 
> -Dan
> 
> 
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x15001000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>,
> > +                                       <&imgsys IMG_LARB2_SMI>;
> > +                       clock-names = "larb_sub0", "larb_sub1";
> > +               };
> > +
> > +               larb3:larb@18001000 {
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x18001000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>,
> > +                                       <&vencsys VENC_CKE0>,
> > +                                       <&vencsys VENC_CKE1>;
> > +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +               };
> > +
> > +               larb4:larb@14027000 {
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x14027000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>, <&mmsys MM_SMI_LARB4>;
> > +                       clock-names = "larb_sub0", "larb_sub1";
> > +               };
> > +
> > +               larb5:larb@19001000 {
> > +                       compatible = "mediatek,mt8173-smi-larb";
> > +                       reg = <0 0x19001000 0 0x1000>;
> > +                       clocks = <&mmsys MM_SMI_COMMON>,
> > +                                       <&vencltsys VENCLT_CKE0>,
> > +                                       <&vencltsys VENCLT_CKE1>;
> > +                       clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +               };
> >         };
> >
> >  };
> > --
> > 1.8.1.1.dirty



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 14:48   ` Sergei Shtylyov
@ 2015-03-09 12:32     ` Yong Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-09 12:32 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Daniel Kurtz, Sasha Hauer,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach,
	yong.wu

Dear Sergei,
	Thanks very much for suggestion.
        I will fix them in the next version.

On Fri, 2015-03-06 at 17:48 +0300, Sergei Shtylyov wrote:
> Hello.
> 
> On 3/6/2015 1:48 PM, yong.wu@mediatek.com wrote:
> 
> > From: Yong Wu <yong.wu@mediatek.com>
> 
> > This patch add smi binding document.
> 
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > ---
> >   .../devicetree/bindings/soc/mediatek/mediatek,smi.txt   | 17 +++++++++++++++++
> >   1 file changed, 17 insertions(+)
> >   create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> 
> > diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > new file mode 100644
> > index 0000000..0fc9d1a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > @@ -0,0 +1,17 @@
> > +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> > +
> > +Required properties:
> > +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"
> 
>     One "mediatek," is enough. :-)
> 
> > +- reg : the register of each local arbiter
> > +- clocks : the clocks of each local arbiter
> > +- clock-name: larb_sub*(3 clockes at most)
> 
>     clock-names.
> 
> > +
> > +Example:
> > +	larb1:larb@16010000 {
> > +	        compatible = "mediatek,mt8173-smi-larb";
> > +		reg = <0 0x16010000 0 0x1000>;
> > +		clocks = <&mmsys MM_SMI_COMMON>,
> > +		        <&vdecsys VDEC_CKEN>,
> 
>     Please align with the < above.
> 
> > +                        <&vdecsys VDEC_LARB_CKEN>;
> 
>     Use tabs instead of spaces, please.
> 
> > +		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +	};
> 
> WBR, Sergei
> 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 11:13   ` Mark Rutland
@ 2015-03-09 12:55     ` Yong Wu
  2015-04-14  9:07     ` Yong Wu
  1 sibling, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-09 12:55 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu, yong.wu

Dear Mark,
      Thanks very much for you suggestion.

On Fri, 2015-03-06 at 11:13 +0000, Mark Rutland wrote:
> On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> > 
> > This patch add smi binding document.
> 
> Please move binding documents to the start of the series. It makes
> things far easier to review.
> 
> > 
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > ---
> >  .../devicetree/bindings/soc/mediatek/mediatek,smi.txt   | 17 +++++++++++++++++
> >  1 file changed, 17 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > new file mode 100644
> > index 0000000..0fc9d1a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > @@ -0,0 +1,17 @@
> > +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> > +
> > +Required properties:
> > +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"
> 
> Double vendor prefix?
Yes. I will change this.
> 
> What does "larb" mean? It would be nice for the intorductory paragraph
> in this file to explain.
That is local arbiter. I will add a link like this, is it ok?

compatible : must be "mediatek,mt8173-smi-larb", about the "larb",
please check the <bindings/iommu/mediatek,iommu.txt>.

> 
> > +- reg : the register of each local arbiter
> > +- clocks : the clocks of each local arbiter
> > +- clock-name: larb_sub*(3 clockes at most)
> 
> The names required _must_ be specified here, or clock-names is
> pointless.
> 
> The clock names should be from the PoV of _this_ device (i.e. they
> should be the names of the inputs) not from the PoV of the provider
> (i.e. they should not be the names of the outputs from the provider).
    I use larb_sub0, larb_sub1,larb_sub2 for more easily to control the
clocks. if we use the PoV, We should list all the clocks name, it will
has a little code. Anyway I will change this in the next version.
> 
> Mark.
> 
> > +
> > +Example:
> > +	larb1:larb@16010000 {
> > +	        compatible = "mediatek,mt8173-smi-larb";
> > +		reg = <0 0x16010000 0 0x1000>;
> > +		clocks = <&mmsys MM_SMI_COMMON>,
> > +		        <&vdecsys VDEC_CKEN>,
> > +                        <&vdecsys VDEC_LARB_CKEN>;
> > +		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +	};
> > -- 
> > 1.8.1.1.dirty
> > 
> > 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-09 11:11   ` Tomasz Figa
@ 2015-03-09 14:46     ` Yingjoe Chen
  2015-03-09 17:00       ` Tomasz Figa
  0 siblings, 1 reply; 55+ messages in thread
From: Yingjoe Chen @ 2015-03-09 14:46 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Yong Wu (吴勇),
	Mark Rutland, devicetree, srv_heupstream, Catalin Marinas,
	Joerg Roedel, Will Deacon, linux-kernel, iommu, Rob Herring,
	Daniel Kurtz, Sasha Hauer, Matthias Brugger, linux-mediatek,
	Robin Murphy, linux-arm-kernel, Lucas Stach

On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
<...>
> > +/*
> > + * pimudev is a global var for dma_alloc_coherent.
> > + * It is not accepatable, we will delete it if "domain_alloc" is enabled
> > + */
> > +static struct device *pimudev;
> 
> This is indeed not acceptable. Could you replace dma_alloc_coherent()
> with something that doesn't require device pointer, e.g.
> alloc_pages()? (Although that would require you to handle cache
> maintenance in the driver, due to cached memory allocated.) I need to
> think about a better solution for this.

Hi,

For 2nd level page table, we use cached memory now. Currently we are
using __dma_flush_range to flush the cache, which is also unacceptable.

For proper cache management, we'll need to use dma_map_single or
dma_sync_*, which still need a deivce*.

Joe.C



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-09 12:16     ` Yong Wu
@ 2015-03-09 16:57       ` Mitchel Humpherys
  0 siblings, 0 replies; 55+ messages in thread
From: Mitchel Humpherys @ 2015-03-09 16:57 UTC (permalink / raw)
  To: Yong Wu
  Cc: Mark Rutland, devicetree, srv_heupstream, Catalin Marinas,
	Joerg Roedel, Will Deacon, linux-kernel, Tomasz Figa, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, Robin Murphy, linux-arm-kernel, Lucas Stach

On Mon, Mar 09 2015 at 05:16:26 AM, Yong Wu <yong.wu@mediatek.com> wrote:
> Dear Mitchel,
>      Thanks very much for your review.
>
> On Fri, 2015-03-06 at 09:15 -0800, Mitchel Humpherys wrote:
>> On Fri, Mar 06 2015 at 02:48:17 AM, <yong.wu@mediatek.com> wrote:
>> > From: Yong Wu <yong.wu@mediatek.com>
>> >
>> > This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
>> > Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
>> 
>> [...]
>> 
>> > +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
>> > +				    int isinvall, unsigned int iova_start,
>> > +				    unsigned int iova_end)
>> > +{
>> > +	void __iomem *m4u_base = piommu->m4u_base;
>> > +	u32 val;
>> > +	u64 start, end;
>> > +
>> > +	start = sched_clock();
>> > +
>> > +	if (!isinvall) {
>> > +		iova_start = round_down(iova_start, SZ_4K);
>> > +		iova_end = round_up(iova_end, SZ_4K);
>> > +	}
>> > +
>> > +	val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
>> > +
>> > +	writel(val, m4u_base + REG_INVLID_SEL);
>> > +
>> > +	if (isinvall) {
>> > +		writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
>> > +	} else {
>> > +		writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
>> > +		writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
>> > +		writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
>> > +
>> > +		while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
>> > +			end = sched_clock();
>> > +			if (end - start >= 100000000ULL) {
>> > +				dev_warn(piommu->dev, "invalid don't done\n");
>> > +				writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
>> > +			}
>> > +		};
>> 
>> Superfluous `;'.  Also, maybe you should be using readl_poll_timeout?
>    Thanks.
>    For the "readl_poll_timeout", My base is 3.19-rc7 and robin's patch.
> it don't have this interface.  I will try to add it in the next version.

Yeah it was merged in v4.0-rc1.

-Mitch

-- 
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-09 14:46     ` Yingjoe Chen
@ 2015-03-09 17:00       ` Tomasz Figa
  2015-03-10  3:41         ` Yingjoe Chen
  0 siblings, 1 reply; 55+ messages in thread
From: Tomasz Figa @ 2015-03-09 17:00 UTC (permalink / raw)
  To: Yingjoe Chen, Joerg Roedel
  Cc: Yong Wu (吴勇),
	Mark Rutland, devicetree, srv_heupstream, Catalin Marinas,
	Will Deacon, linux-kernel, iommu, Rob Herring, Daniel Kurtz,
	Sasha Hauer, Matthias Brugger, linux-mediatek, Robin Murphy,
	linux-arm-kernel, Lucas Stach

On Mon, Mar 9, 2015 at 11:46 PM, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
> On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
> <...>
>> > +/*
>> > + * pimudev is a global var for dma_alloc_coherent.
>> > + * It is not accepatable, we will delete it if "domain_alloc" is enabled
>> > + */
>> > +static struct device *pimudev;
>>
>> This is indeed not acceptable. Could you replace dma_alloc_coherent()
>> with something that doesn't require device pointer, e.g.
>> alloc_pages()? (Although that would require you to handle cache
>> maintenance in the driver, due to cached memory allocated.) I need to
>> think about a better solution for this.
>
> Hi,
>
> For 2nd level page table, we use cached memory now. Currently we are
> using __dma_flush_range to flush the cache, which is also unacceptable.
>
> For proper cache management, we'll need to use dma_map_single or
> dma_sync_*, which still need a deivce*.

Looking at how already mainlined drivers do this, they either use
dmac_flush_range()
(https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/msm_iommu.c?id=refs/tags/v4.0-rc3#n80)
or directly __cpuc_flush_dcache_area() and outer_flush_range()
(https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/rockchip-iommu.c?id=refs/tags/v4.0-rc3#n93).

Joerg, what's your opinion on this?

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09 11:57     ` Yong Wu
@ 2015-03-09 17:59       ` Paul Bolle
  2015-03-09 21:54         ` Arnd Bergmann
  2015-03-10  6:17         ` Yingjoe Chen
  0 siblings, 2 replies; 55+ messages in thread
From: Paul Bolle @ 2015-03-09 17:59 UTC (permalink / raw)
  To: Yong Wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Mark Rutland, Catalin Marinas, linux-mediatek, Sasha Hauer,
	srv_heupstream, devicetree, linux-kernel, linux-arm-kernel,
	iommu

Hi Yong,

Yong Wu schreef op ma 09-03-2015 om 19:57 [+0800]:
> On Fri, 2015-03-06 at 12:30 +0100, Paul Bolle wrote:
> > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > --- a/drivers/soc/mediatek/Kconfig
> > > +++ b/drivers/soc/mediatek/Kconfig
> > > @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
> > >  	  PMIC wrapper is a proprietary hardware in MT8173 to make
> > >  	  communication protocols to access PMIC device.
> > >  	  This driver implement access protocols for MT8173.
> > > +
> > > +config MTK_SMI
> > > +        bool
> > 
> > Nit: make this one tab instead of 8 spaces, please.
> > 
> > > +	help
> > > +	  Smi help enable/disable iommu in mt8173 and control the
> > > +	  clock of each local arbiter.
> > > +	  It should be true while MTK_IOMMU enable.
> > 
> > I don't think anyone using the *config tools will ever see this text, as
> > there's no prompt. So you might as well make this a comment or drop it
> > altogether.
> > 
>      We could search it in the tool even though we don't see it. In next
> version, I will try to make it a comment.
> > Is this selected by more than just MTK_IOMMU (see 2/5)? If not, I think
> > MTK_SMI will be set and unset in lockstep with MTK_IOMMU. In other
> > words, you could as well use one Kconfig symbol.
> > 
>     if we disable MTK_IOMMU, the MTK_SMI also should be selected.That is because 
> if the multimedia h/w want to work, the clock of the local arbiters always should be opened.

This is a bit confusing, I'm afraid. Do you mean to say that it ought to
be possible for MTK_SMI to be 'y' even if MTK_IOMMU would be 'n'?


Paul Bolle


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09 17:59       ` Paul Bolle
@ 2015-03-09 21:54         ` Arnd Bergmann
  2015-03-10  6:17         ` Yingjoe Chen
  1 sibling, 0 replies; 55+ messages in thread
From: Arnd Bergmann @ 2015-03-09 21:54 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Yong Wu, Rob Herring, Joerg Roedel, Matthias Brugger,
	Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu

On Monday 09 March 2015 18:59:37 Paul Bolle wrote:
> Hi Yong,
> 
> Yong Wu schreef op ma 09-03-2015 om 19:57 [+0800]:
> > On Fri, 2015-03-06 at 12:30 +0100, Paul Bolle wrote:
> > > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > > --- a/drivers/soc/mediatek/Kconfig
> > > > +++ b/drivers/soc/mediatek/Kconfig
> > > > @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
> > > >  	  PMIC wrapper is a proprietary hardware in MT8173 to make
> > > >  	  communication protocols to access PMIC device.
> > > >  	  This driver implement access protocols for MT8173.
> > > > +
> > > > +config MTK_SMI
> > > > +        bool
> > > 
> > > Nit: make this one tab instead of 8 spaces, please.
> > > 
> > > > +	help
> > > > +	  Smi help enable/disable iommu in mt8173 and control the
> > > > +	  clock of each local arbiter.
> > > > +	  It should be true while MTK_IOMMU enable.
> > > 
> > > I don't think anyone using the *config tools will ever see this text, as
> > > there's no prompt. So you might as well make this a comment or drop it
> > > altogether.
> > > 
> >      We could search it in the tool even though we don't see it. In next
> > version, I will try to make it a comment.

No, please leave it the way it was. I prefer having help texts even
for silent options over using comments to do the same.

	Arnd

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09  3:26   ` Yingjoe Chen
@ 2015-03-09 21:56     ` Arnd Bergmann
  2015-03-10  6:27       ` Yingjoe Chen
  2015-03-10  9:24       ` Lucas Stach
  0 siblings, 2 replies; 55+ messages in thread
From: Arnd Bergmann @ 2015-03-09 21:56 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Yingjoe Chen, yong.wu, Matthias Brugger, Mark Rutland,
	devicetree, srv_heupstream, Catalin Marinas, Joerg Roedel,
	Will Deacon, linux-kernel, Tomasz Figa, iommu, Rob Herring,
	Daniel Kurtz, Sasha Hauer, linux-mediatek, Robin Murphy,
	Lucas Stach

On Monday 09 March 2015 11:26:52 Yingjoe Chen wrote:
> On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> > 
> >     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> > responsible to enable/disable iommu and control the clocks of each
> > local arbiter.
> > 
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > ---
> >  drivers/soc/mediatek/Kconfig      |   7 ++
> >  drivers/soc/mediatek/Makefile     |   1 +
> >  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
> >  include/linux/mtk-smi.h           |  40 +++++++++++
> >  4 files changed, 191 insertions(+)
> >  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
> >  create mode 100644 include/linux/mtk-smi.h
> > 
> 
> Hi Arnd, Matthias,
> 
> For the SMI driver, we can't find a better place, so we put it in
> drivers/soc/mediatek now. Please let us know if you have any suggestion
> or concern. Thanks

>From what I understand from your description, I think it would better
fit in drivers/iommu. Another option is drivers/memory, which I think
is where the respective Tegra driver ended up.

	Arnd

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-09 17:00       ` Tomasz Figa
@ 2015-03-10  3:41         ` Yingjoe Chen
  2015-03-10  4:06           ` Tomasz Figa
  0 siblings, 1 reply; 55+ messages in thread
From: Yingjoe Chen @ 2015-03-10  3:41 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Joerg Roedel, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Will Deacon, linux-kernel, iommu, Rob Herring,
	Daniel Kurtz, linux-arm-kernel, Sasha Hauer, Matthias Brugger,
	linux-mediatek, Robin Murphy, Yong Wu (吴勇),
	Lucas Stach

On Tue, 2015-03-10 at 02:00 +0900, Tomasz Figa wrote:
> On Mon, Mar 9, 2015 at 11:46 PM, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
> > On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
> > <...>
> >> > +/*
> >> > + * pimudev is a global var for dma_alloc_coherent.
> >> > + * It is not accepatable, we will delete it if "domain_alloc" is enabled
> >> > + */
> >> > +static struct device *pimudev;
> >>
> >> This is indeed not acceptable. Could you replace dma_alloc_coherent()
> >> with something that doesn't require device pointer, e.g.
> >> alloc_pages()? (Although that would require you to handle cache
> >> maintenance in the driver, due to cached memory allocated.) I need to
> >> think about a better solution for this.
> >
> > Hi,
> >
> > For 2nd level page table, we use cached memory now. Currently we are
> > using __dma_flush_range to flush the cache, which is also unacceptable.
> >
> > For proper cache management, we'll need to use dma_map_single or
> > dma_sync_*, which still need a deivce*.
> 
> Looking at how already mainlined drivers do this, they either use
> dmac_flush_range()
> (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/msm_iommu.c?id=refs/tags/v4.0-rc3#n80)
> or directly __cpuc_flush_dcache_area() and outer_flush_range()
> (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/rockchip-iommu.c?id=refs/tags/v4.0-rc3#n93).

Hi,

These only exist in arch/arm, not arm64. I think we should avoid using
API start with __ in drivers. This driver might be used in both
arm/arm64, I think the only option for us is DMA APIs.

Actually, I'm thinking that we should change to use coherent memory for
2nd level page table as well and totally skip the cache flush. It seems
dma_pool_create is suitable to replace kmem_cache we are using right
now. However it still need a device*, which we have to fix anyway.

Joe.C



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-10  3:41         ` Yingjoe Chen
@ 2015-03-10  4:06           ` Tomasz Figa
  0 siblings, 0 replies; 55+ messages in thread
From: Tomasz Figa @ 2015-03-10  4:06 UTC (permalink / raw)
  To: Yingjoe Chen
  Cc: Joerg Roedel, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Will Deacon, linux-kernel, iommu, Rob Herring,
	Daniel Kurtz, linux-arm-kernel, Sasha Hauer, Matthias Brugger,
	linux-mediatek, Robin Murphy, Yong Wu (吴勇),
	Lucas Stach

On Tue, Mar 10, 2015 at 12:41 PM, Yingjoe Chen
<yingjoe.chen@mediatek.com> wrote:
> On Tue, 2015-03-10 at 02:00 +0900, Tomasz Figa wrote:
>> On Mon, Mar 9, 2015 at 11:46 PM, Yingjoe Chen <yingjoe.chen@mediatek.com> wrote:
>> > On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
>> > <...>
>> >> > +/*
>> >> > + * pimudev is a global var for dma_alloc_coherent.
>> >> > + * It is not accepatable, we will delete it if "domain_alloc" is enabled
>> >> > + */
>> >> > +static struct device *pimudev;
>> >>
>> >> This is indeed not acceptable. Could you replace dma_alloc_coherent()
>> >> with something that doesn't require device pointer, e.g.
>> >> alloc_pages()? (Although that would require you to handle cache
>> >> maintenance in the driver, due to cached memory allocated.) I need to
>> >> think about a better solution for this.
>> >
>> > Hi,
>> >
>> > For 2nd level page table, we use cached memory now. Currently we are
>> > using __dma_flush_range to flush the cache, which is also unacceptable.
>> >
>> > For proper cache management, we'll need to use dma_map_single or
>> > dma_sync_*, which still need a deivce*.
>>
>> Looking at how already mainlined drivers do this, they either use
>> dmac_flush_range()
>> (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/msm_iommu.c?id=refs/tags/v4.0-rc3#n80)
>> or directly __cpuc_flush_dcache_area() and outer_flush_range()
>> (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/rockchip-iommu.c?id=refs/tags/v4.0-rc3#n93).
>
> Hi,
>
> These only exist in arch/arm, not arm64. I think we should avoid using
> API start with __ in drivers. This driver might be used in both
> arm/arm64, I think the only option for us is DMA APIs.
>
> Actually, I'm thinking that we should change to use coherent memory for
> 2nd level page table as well and totally skip the cache flush. It seems
> dma_pool_create is suitable to replace kmem_cache we are using right
> now. However it still need a device*, which we have to fix anyway.

That sounds like a reasonable option, because this is what we have DMA
mapping API for.

Do you expect to have more than one M4U block inside a SoC? Maybe this
static variable actually isn't that bad, with a comment added
explaining that there is always only one such block and that a rework
will be needed if future SoCs will have more.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09 17:59       ` Paul Bolle
  2015-03-09 21:54         ` Arnd Bergmann
@ 2015-03-10  6:17         ` Yingjoe Chen
  1 sibling, 0 replies; 55+ messages in thread
From: Yingjoe Chen @ 2015-03-10  6:17 UTC (permalink / raw)
  To: Paul Bolle
  Cc: Yong Wu, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel,
	Tomasz Figa, iommu, Rob Herring, Daniel Kurtz, Sasha Hauer,
	Matthias Brugger, linux-mediatek, Robin Murphy, linux-arm-kernel,
	Lucas Stach

On Mon, 2015-03-09 at 18:59 +0100, Paul Bolle wrote:
> Hi Yong,
> 
> Yong Wu schreef op ma 09-03-2015 om 19:57 [+0800]:
> > On Fri, 2015-03-06 at 12:30 +0100, Paul Bolle wrote:
> > > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > > --- a/drivers/soc/mediatek/Kconfig
> > > > +++ b/drivers/soc/mediatek/Kconfig
> > > > @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
> > > >  	  PMIC wrapper is a proprietary hardware in MT8173 to make
> > > >  	  communication protocols to access PMIC device.
> > > >  	  This driver implement access protocols for MT8173.
> > > > +
> > > > +config MTK_SMI
> > > > +        bool
> > > 
> > > Nit: make this one tab instead of 8 spaces, please.
> > > 
> > > > +	help
> > > > +	  Smi help enable/disable iommu in mt8173 and control the
> > > > +	  clock of each local arbiter.
> > > > +	  It should be true while MTK_IOMMU enable.
> > > 
> > > I don't think anyone using the *config tools will ever see this text, as
> > > there's no prompt. So you might as well make this a comment or drop it
> > > altogether.
> > > 
> >      We could search it in the tool even though we don't see it. In next
> > version, I will try to make it a comment.
> > > Is this selected by more than just MTK_IOMMU (see 2/5)? If not, I think
> > > MTK_SMI will be set and unset in lockstep with MTK_IOMMU. In other
> > > words, you could as well use one Kconfig symbol.
> > > 
> >     if we disable MTK_IOMMU, the MTK_SMI also should be selected.That is because 
> > if the multimedia h/w want to work, the clock of the local arbiters always should be opened.
> 
> This is a bit confusing, I'm afraid. Do you mean to say that it ought to
> be possible for MTK_SMI to be 'y' even if MTK_IOMMU would be 'n'?

The SMI can be configured to bypass IOMMU and send traffic directly to
memory interface. It is possible to not use IOMMU and have display/MM to
use continuous memory only.

Besides MTK_IOMMU, we expect DRM, VDEC driver to select MTK_SMI as well.

Joe.C


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09 21:56     ` Arnd Bergmann
@ 2015-03-10  6:27       ` Yingjoe Chen
  2015-03-10  9:05         ` Arnd Bergmann
  2015-03-10  9:24       ` Lucas Stach
  1 sibling, 1 reply; 55+ messages in thread
From: Yingjoe Chen @ 2015-03-10  6:27 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Mark Rutland, devicetree, linux-mediatek,
	srv_heupstream, Catalin Marinas, Joerg Roedel, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Rob Herring, Daniel Kurtz,
	Sasha Hauer, Matthias Brugger, Robin Murphy, yong.wu,
	Lucas Stach

On Mon, 2015-03-09 at 22:56 +0100, Arnd Bergmann wrote:
> On Monday 09 March 2015 11:26:52 Yingjoe Chen wrote:
> > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > From: Yong Wu <yong.wu@mediatek.com>
> > > 
> > >     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> > > responsible to enable/disable iommu and control the clocks of each
> > > local arbiter.
> > > 
> > > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > > ---
> > >  drivers/soc/mediatek/Kconfig      |   7 ++
> > >  drivers/soc/mediatek/Makefile     |   1 +
> > >  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
> > >  include/linux/mtk-smi.h           |  40 +++++++++++
> > >  4 files changed, 191 insertions(+)
> > >  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
> > >  create mode 100644 include/linux/mtk-smi.h
> > > 
> > 
> > Hi Arnd, Matthias,
> > 
> > For the SMI driver, we can't find a better place, so we put it in
> > drivers/soc/mediatek now. Please let us know if you have any suggestion
> > or concern. Thanks
> 
> From what I understand from your description, I think it would better
> fit in drivers/iommu. Another option is drivers/memory, which I think
> is where the respective Tegra driver ended up.

Hi Arnd,

The description above only describe what is implemented now. Besides
that, SMI HW also does:

- Prioritize/arbitrate memory requests between different ports & larbs.
- Bandwidth limiter
- Performance monitor

I think drivers/memory make more sense. I can't find info about
drivers/memory in MAINTAINERS. Can this go through ARM SoC tree if we
put SMI driver there?

Joe.C



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-10  6:27       ` Yingjoe Chen
@ 2015-03-10  9:05         ` Arnd Bergmann
  0 siblings, 0 replies; 55+ messages in thread
From: Arnd Bergmann @ 2015-03-10  9:05 UTC (permalink / raw)
  To: Yingjoe Chen
  Cc: linux-arm-kernel, Mark Rutland, devicetree, linux-mediatek,
	srv_heupstream, Catalin Marinas, Joerg Roedel, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Rob Herring, Daniel Kurtz,
	Sasha Hauer, Matthias Brugger, Robin Murphy, yong.wu,
	Lucas Stach, thierry.reding

On Tuesday 10 March 2015 14:27:04 Yingjoe Chen wrote:
> On Mon, 2015-03-09 at 22:56 +0100, Arnd Bergmann wrote:
> > On Monday 09 March 2015 11:26:52 Yingjoe Chen wrote:
> > > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > > From: Yong Wu <yong.wu@mediatek.com>
> > > > 
> > > >     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> > > > responsible to enable/disable iommu and control the clocks of each
> > > > local arbiter.
> > > > 
> > > > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > > > ---
> > > >  drivers/soc/mediatek/Kconfig      |   7 ++
> > > >  drivers/soc/mediatek/Makefile     |   1 +
> > > >  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
> > > >  include/linux/mtk-smi.h           |  40 +++++++++++
> > > >  4 files changed, 191 insertions(+)
> > > >  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
> > > >  create mode 100644 include/linux/mtk-smi.h
> > > > 
> > > 
> > > Hi Arnd, Matthias,
> > > 
> > > For the SMI driver, we can't find a better place, so we put it in
> > > drivers/soc/mediatek now. Please let us know if you have any suggestion
> > > or concern. Thanks
> > 
> > From what I understand from your description, I think it would better
> > fit in drivers/iommu. Another option is drivers/memory, which I think
> > is where the respective Tegra driver ended up.
> 
> Hi Arnd,
> 
> The description above only describe what is implemented now. Besides
> that, SMI HW also does:
> 
> - Prioritize/arbitrate memory requests between different ports & larbs.
> - Bandwidth limiter
> - Performance monitor
> 
> I think drivers/memory make more sense. I can't find info about
> drivers/memory in MAINTAINERS. Can this go through ARM SoC tree if we
> put SMI driver there?
> 

Yes, that works for me. I'd like to see a review from Thierry Reding
though, since he wrote the Tegra driver that is used for very similar
hardware, and I want to make sure you two are on the same page with
the internal APIs.

	Arnd

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 1/5] soc: mediatek: Add SMI driver
  2015-03-09 21:56     ` Arnd Bergmann
  2015-03-10  6:27       ` Yingjoe Chen
@ 2015-03-10  9:24       ` Lucas Stach
  1 sibling, 0 replies; 55+ messages in thread
From: Lucas Stach @ 2015-03-10  9:24 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Mark Rutland, devicetree, linux-mediatek,
	srv_heupstream, Catalin Marinas, Joerg Roedel, Will Deacon,
	linux-kernel, Tomasz Figa, iommu, Rob Herring, Daniel Kurtz,
	Sasha Hauer, Matthias Brugger, Yingjoe Chen, Robin Murphy,
	yong.wu

Hi Arnd,

Am Montag, den 09.03.2015, 22:56 +0100 schrieb Arnd Bergmann:
> On Monday 09 March 2015 11:26:52 Yingjoe Chen wrote:
> > On Fri, 2015-03-06 at 18:48 +0800, yong.wu@mediatek.com wrote:
> > > From: Yong Wu <yong.wu@mediatek.com>
> > > 
> > >     This patch add SMI(Smart Multimedia Interface) driver. This driver is
> > > responsible to enable/disable iommu and control the clocks of each
> > > local arbiter.
> > > 
> > > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > > ---
> > >  drivers/soc/mediatek/Kconfig      |   7 ++
> > >  drivers/soc/mediatek/Makefile     |   1 +
> > >  drivers/soc/mediatek/mt8173-smi.c | 143 ++++++++++++++++++++++++++++++++++++++
> > >  include/linux/mtk-smi.h           |  40 +++++++++++
> > >  4 files changed, 191 insertions(+)
> > >  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
> > >  create mode 100644 include/linux/mtk-smi.h
> > > 
> > 
> > Hi Arnd, Matthias,
> > 
> > For the SMI driver, we can't find a better place, so we put it in
> > drivers/soc/mediatek now. Please let us know if you have any suggestion
> > or concern. Thanks
> 
> From what I understand from your description, I think it would better
> fit in drivers/iommu. Another option is drivers/memory, which I think
> is where the respective Tegra driver ended up.
> 
Note that this is not the IOMMU driver. M4U is the IOMMU unit. The SMI
unit is more of a bridge control for the internal buses where you can
control various properties for the masters on the bus.

One notable property (and why this driver is part of the IOMMU series)
is the control weather a master should go through the M4U unit for
translation or bypass it and talk directly to external memory
controller.

Regards,
Lucas

-- 
Pengutronix e.K.             | Lucas Stach                 |
Industrial Linux Solutions   | http://www.pengutronix.de/  |


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
                     ` (4 preceding siblings ...)
  2015-03-09 11:11   ` Tomasz Figa
@ 2015-03-11 10:53   ` Tomasz Figa
  2015-03-18 11:22     ` Yong Wu
  5 siblings, 1 reply; 55+ messages in thread
From: Tomasz Figa @ 2015-03-11 10:53 UTC (permalink / raw)
  To: Yong Wu (吴勇)
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi,

Please find next part of my comments inline.

On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:

[snip]

> +/*
> + * pimudev is a global var for dma_alloc_coherent.
> + * It is not accepatable, we will delete it if "domain_alloc" is enabled

It looks like we indeed need to use dma_alloc_coherent() and we don't
have a good way to pass the device pointer to domain_init callback.

If you don't expect SoCs in the nearest future to have multiple M4U
blocks, then I guess this global variable could stay, after changing
the comment into an explanation why it's correct. Also it should be
moved to the top of the file, below #include directives, as this is
where usually global variables are located.

> + */
> +static struct device *pimudev;
> +
> +static int mtk_iommu_domain_init(struct iommu_domain *domain)
> +{
> +       struct mtk_iommu_domain *priv;
> +
> +       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->pgd = dma_alloc_coherent(pimudev, M4U_PGD_SIZE, &priv->pgd_pa,
> +                                      GFP_KERNEL);
> +       if (!priv->pgd) {
> +               pr_err("dma_alloc_coherent pagetable fail\n");
> +               goto err_pgtable;

ret = -ENOMEM;
goto err_free_priv;

> +       }
> +
> +       if (!IS_ALIGNED(priv->pgd_pa, M4U_PGD_SIZE)) {
> +               pr_err("pagetable not aligned pa 0x%pad-0x%p align 0x%x\n",
> +                      &priv->pgd_pa, priv->pgd, M4U_PGD_SIZE);
> +               goto err_pgtable;

ret = -ENOMEM;
goto err_dmafree;

> +       }
> +
> +       memset(priv->pgd, 0, M4U_PGD_SIZE);
> +
> +       spin_lock_init(&priv->pgtlock);
> +       spin_lock_init(&priv->portlock);
> +       domain->priv = priv;
> +
> +       domain->geometry.aperture_start = 0;
> +       domain->geometry.aperture_end   = (unsigned int)~0;

Please replace the cast with ~0U and fix multiple spaces between =.

> +       domain->geometry.force_aperture = true;
> +
> +       return 0;
> +
> +err_pgtable:

err_dma_free:

> +       if (priv->pgd)

Remove this check.

> +               dma_free_coherent(pimudev, M4U_PGD_SIZE, priv->pgd,
> +                                 priv->pgd_pa);

err_free_priv:

> +       kfree(priv);
> +       return -ENOMEM;

return ret;

> +}
> +
> +static void mtk_iommu_domain_destroy(struct iommu_domain *domain)
> +{
> +       struct mtk_iommu_domain *priv = domain->priv;
> +
> +       dma_free_coherent(priv->piommuinfo->dev, M4U_PGD_SIZE,
> +                         priv->pgd, priv->pgd_pa);
> +       kfree(domain->priv);
> +       domain->priv = NULL;
> +}
> +
> +static int mtk_iommu_attach_device(struct iommu_domain *domain,
> +                                  struct device *dev)
> +{
> +       unsigned long flags;
> +       struct mtk_iommu_domain *priv = domain->priv;
> +       struct mtk_iommu_info *piommu = priv->piommuinfo;
> +       struct of_phandle_args out_args = {0};
> +       struct device *imudev;
> +       unsigned int i = 0;
> +
> +       if (!piommu)

Could you explain when this can happen?

> +               goto imudev;

return 0;

> +       else

No else needed.

> +               imudev = piommu->dev;
> +
> +       spin_lock_irqsave(&priv->portlock, flags);

What is protected by this spinlock?

> +
> +       while (!of_parse_phandle_with_args(dev->of_node, "iommus",
> +                                          "#iommu-cells", i, &out_args)) {
> +               if (1 == out_args.args_count) {

Can we be sure that this is actually referring to our IOMMU?

Maybe this should be rewritten to

if (out_args.np != imudev->of_node)
        continue;
if (out_args.args_count != 1) {
        dev_err(imudev, "invalid #iommu-cells property for IOMMU %s\n",

}

> +                       unsigned int portid = out_args.args[0];
> +
> +                       dev_dbg(dev, "iommu add port:%d\n", portid);

imudev should be used here instead of dev.

> +
> +                       mtk_iommu_config_port(piommu, portid);
> +
> +                       if (i == 0)
> +                               dev->archdata.dma_ops =
> +                                       piommu->dev->archdata.dma_ops;

Shouldn't this be set automatically by IOMMU or DMA mapping core?

> +               }
> +               i++;
> +       }
> +
> +       spin_unlock_irqrestore(&priv->portlock, flags);
> +
> +imudev:
> +       return 0;
> +}
> +
> +static void mtk_iommu_detach_device(struct iommu_domain *domain,
> +                                   struct device *dev)
> +{

No hardware (de)configuration or clean-up necessary?

> +}
> +
> +static int mtk_iommu_map(struct iommu_domain *domain, unsigned long iova,
> +                        phys_addr_t paddr, size_t size, int prot)
> +{
> +       struct mtk_iommu_domain *priv = domain->priv;
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&priv->pgtlock, flags);
> +       ret = m4u_map(priv, (unsigned int)iova, paddr, size, prot);
> +       mtk_iommu_invalidate_tlb(priv->piommuinfo, 0,
> +                                iova, iova + size - 1);
> +       spin_unlock_irqrestore(&priv->pgtlock, flags);
> +
> +       return ret;
> +}
> +
> +static size_t mtk_iommu_unmap(struct iommu_domain *domain,
> +                             unsigned long iova, size_t size)
> +{
> +       struct mtk_iommu_domain *priv = domain->priv;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&priv->pgtlock, flags);
> +       m4u_unmap(priv, (unsigned int)iova, size);
> +       mtk_iommu_invalidate_tlb(priv->piommuinfo, 0,
> +                                iova, iova + size - 1);
> +       spin_unlock_irqrestore(&priv->pgtlock, flags);
> +
> +       return size;
> +}
> +
> +static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
> +                                         dma_addr_t iova)
> +{
> +       struct mtk_iommu_domain *priv = domain->priv;
> +       unsigned long flags;
> +       struct m4u_pte_info_t pte;
> +
> +       spin_lock_irqsave(&priv->pgtlock, flags);
> +       m4u_get_pte_info(priv, (unsigned int)iova, &pte);
> +       spin_unlock_irqrestore(&priv->pgtlock, flags);
> +
> +       return pte.pa;
> +}
> +
> +static struct iommu_ops mtk_iommu_ops = {
> +       .domain_init = mtk_iommu_domain_init,
> +       .domain_destroy = mtk_iommu_domain_destroy,
> +       .attach_dev = mtk_iommu_attach_device,
> +       .detach_dev = mtk_iommu_detach_device,
> +       .map = mtk_iommu_map,
> +       .unmap = mtk_iommu_unmap,
> +       .map_sg = default_iommu_map_sg,
> +       .iova_to_phys = mtk_iommu_iova_to_phys,
> +       .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
> +};
> +
> +static const struct of_device_id mtk_iommu_of_ids[] = {
> +       { .compatible = "mediatek,mt8173-iommu",
> +         .data = &mtk_iommu_mt8173_cfg,
> +       },
> +       {}
> +};
> +
> +static int mtk_iommu_probe(struct platform_device *pdev)
> +{
> +       int ret;
> +       struct iommu_domain *domain;
> +       struct mtk_iommu_domain *mtk_domain;
> +       struct mtk_iommu_info *piommu;
> +       struct iommu_dma_domain  *dom;
> +       const struct of_device_id *of_id;
> +
> +       piommu = devm_kzalloc(&pdev->dev, sizeof(struct mtk_iommu_info),

sizeof(*piommu)

> +                             GFP_KERNEL);
> +       if (!piommu)
> +               return -ENOMEM;
> +
> +       pimudev = &pdev->dev;
> +       piommu->dev = &pdev->dev;
> +
> +       of_id = of_match_node(mtk_iommu_of_ids, pdev->dev.of_node);
> +       if (!of_id)
> +               return -ENODEV;

Please print an error message.

> +
> +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,

style: Operators like * should have space on both sides.

> +                                         GFP_KERNEL);

Shouldn't dma_alloc_coherent() be used for this?

> +       if (!piommu->protect_va)
> +               goto protect_err;

Please return -ENOMEM here directly, as there is nothing to clean up
in this case.

> +       memset(piommu->protect_va, 0x55, MTK_PROTECT_PA_ALIGN*2);
> +
> +       piommu->imucfg = (const struct mtk_iommu_cfg *)of_id->data;

Why this cast is needed? Since of_id->data is const void * it should
be fine without a cast.

> +
> +       ret = mtk_iommu_parse_dt(pdev, piommu);
> +       if (ret) {
> +               dev_err(piommu->dev, "iommu dt parse fail\n");
> +               goto protect_err;

Still nothing to clean-up, so you can safely just return ret;

> +       }
> +
> +       /* alloc memcache for level-2 pgt */
> +       piommu->m4u_pte_kmem = kmem_cache_create("m4u_pte", IMU_BYTES_PER_PTE,
> +                                                IMU_BYTES_PER_PTE, 0, NULL);
> +
> +       if (IS_ERR_OR_NULL(piommu->m4u_pte_kmem)) {

Looks like the convention used by kmem_cache_create() is valid ptr or
NULL, no ERR_PTR()s.

> +               dev_err(piommu->dev, "pte cached create fail %p\n",
> +                       piommu->m4u_pte_kmem);
> +               goto protect_err;

Still nothing to clean-up.

> +       }
> +
> +       arch_setup_dma_ops(piommu->dev, 0, (1ULL<<32) - 1, &mtk_iommu_ops, 0);

style: Missing spaces around << operator.

> +
> +       dom = get_dma_domain(piommu->dev);
> +       domain = iommu_dma_raw_domain(dom);
> +
> +       mtk_domain = domain->priv;

domain is already dereferenced here, but NULL pointer check is two lines below.

> +       mtk_domain->piommuinfo = piommu;
> +
> +       if (!domain)
> +               goto pte_err;

Please print error message.

> +
> +       ret = mtk_iommu_hw_init(mtk_domain);
> +       if (ret < 0)
> +               goto hw_err;

Please print error message.

> +
> +       if (devm_request_irq(piommu->dev, piommu->irq,
> +                            mtk_iommu_isr, IRQF_TRIGGER_NONE,
> +                            "mtkiommu", (void *)domain)) {

Please align wrapped lines using tabs only.

Also, what do you mean by IRQF_TRIGGER_NONE? If you don't need any
special flags then 0 is enough.

Also, usually dev_name() is used for interrupt name.

Also, unnecessary cast of domain to void *.

> +               dev_err(piommu->dev, "IRQ request %d failed\n",
> +                       piommu->irq);
> +               goto hw_err;
> +       }
> +
> +       iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);

I don't see any other drivers doing this. Isn't this for upper layers,
so that they can set their own generic fault handlers?

> +
> +       dev_set_drvdata(piommu->dev, piommu);

This should be set before allowing the interrupt to fire. In other
words, the driver should be fully set up at the time of enabling the
IRQ.

> +
> +       return 0;

style: Missing blank line.

> +hw_err:
> +       arch_teardown_dma_ops(piommu->dev);
> +pte_err:
> +       kmem_cache_destroy(piommu->m4u_pte_kmem);
> +protect_err:
> +       dev_err(piommu->dev, "probe error\n");

Please replace this with specific messages for all errors (in case the
called function doesn't already print one like kmalloc and friends).

> +       return 0;

Returning 0, which means success, doesn't look like a good idea for
signalling a failure. Please return the correct error code as received
from function that errors out if possible.

End of part 3.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-08  4:12   ` Tomasz Figa
@ 2015-03-12 14:16     ` Yong Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-12 14:16 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu, yong.wu,
	yingjoe.chen

Dear Tomasz,

      Thanks very much for review so detail!

      Please check my reply below. Others I will fix it in the next
version.
       
      And I have got your comment of [2/5]. Do you have plan for the
other patch?

On Sun, 2015-03-08 at 13:12 +0900, Tomasz Figa wrote:
> Hi Yong Wu,
> 
> Thanks for this series. Please see my comments inline.
> 
> On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> >
> > This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> > Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
> 
[snip]
> > +static const struct mtk_iommu_port mtk_iommu_mt8173_port[] = {
> > +       /* port name                m4uid slaveid larbid portid tfid */
> > +       /* larb0 */
> > +       {"M4U_PORT_DISP_OVL0",          0,  0,    0,  0, MTK_TFID(0, 0)},
> > +       {"M4U_PORT_DISP_RDMA0",         0,  0,    0,  1, MTK_TFID(0, 1)},
> > +       {"M4U_PORT_DISP_WDMA0",         0,  0,    0,  2, MTK_TFID(0, 2)},
> > +       {"M4U_PORT_DISP_OD_R",          0,  0,    0,  3, MTK_TFID(0, 3)},
> > +       {"M4U_PORT_DISP_OD_W",          0,  0,    0,  4, MTK_TFID(0, 4)},
> > +       {"M4U_PORT_MDP_RDMA0",          0,  0,    0,  5, MTK_TFID(0, 5)},
> > +       {"M4U_PORT_MDP_WDMA",           0,  0,    0,  6, MTK_TFID(0, 6)},
> > +       {"M4U_PORT_MDP_WROT0",          0,  0,    0,  7, MTK_TFID(0, 7)},
> 
> [snip]
> 
> > +       {"M4U_PORT_HSIC_MAS",              1,  0,    6,  12, 0x11},
> > +       {"M4U_PORT_HSIC_DEV",              1,  0,    6,  13, 0x19},
> > +       {"M4U_PORT_AP_DMA",                1,  0,    6,  14, 0x18},
> > +       {"M4U_PORT_HSIC_DMA",              1,  0,    6,  15, 0xc8},
> > +       {"M4U_PORT_MSDC0",                 1,  0,    6,  16, 0x0},
> > +       {"M4U_PORT_MSDC3",                 1,  0,    6,  17, 0x20},
> > +       {"M4U_PORT_UNKNOWN",               1,  0,    6,  18, 0xf},
> 
> Why the MTK_TFID() macro is not used for perisys iommu?
> 
       The perisys iommu don't connected with SMI and Local arbiter.
it's translation fault id is not MTK_TFID(x, y).it is special.
       For this perisys iommu , it is different with multimedia iommu,
we don't support it in this version, We have plan to delete perisys
iommu port next time.

> > +};
> > +
> 
> Anyway, is it really necessary to hardcode the SoC specific topology
> data in this driver? Is there really any use besides of printing port
> name? If not, you could just print the values in a way letting you
> quickly look up in the datasheet, without hardcoding this. Or even
> better, you could print which devices are attached to the port.
> 
a) Printing the port name is for debug. We could not request every iommu
user to understand smi&local arbiter. When there is irq, they have to
look up the iommu's datasheet to find out which port error. if we print
it directly, It may be more easily to debug.

b) In mtk_iommu_config_port, according to this hardcode we can be easily
to get out which local arbiter and which port we prepare to config.

c) If we support different SOCs, we could change this arrays easily.

> > +static const struct mtk_iommu_cfg mtk_iommu_mt8173_cfg = {
> > +       .larb_nr = 6,
> > +       .m4u_port_nr = ARRAY_SIZE(mtk_iommu_mt8173_port),
> > +       .pport = mtk_iommu_mt8173_port,
> > +};
> > +
> > +static const char *mtk_iommu_get_port_name(const struct mtk_iommu_info *piommu,
> > +                                          unsigned int portid)
> > +{
> > +       const struct mtk_iommu_port *pcurport = NULL;
> > +
> > +       pcurport = piommu->imucfg->pport + portid;
> > +       if (portid < piommu->imucfg->m4u_port_nr && pcurport)
> > +               return pcurport->port_name;
> > +       else
> > +               return "UNKNOWN_PORT";
> > +}
> 
> This function seems to be used just for printing the hardcoded port names.
> 
> > +
> > +static int mtk_iommu_get_port_by_tfid(const struct mtk_iommu_info *pimu,
> > +                                     int tf_id)
> > +{
> > +       const struct mtk_iommu_cfg *pimucfg = pimu->imucfg;
> > +       int i;
> > +       unsigned int portid = pimucfg->m4u_port_nr;
> > +
> > +       for (i = 0; i < pimucfg->m4u_port_nr; i++) {
> > +               if (pimucfg->pport[i].tf_id == tf_id) {
> > +                       portid = i;
> > +                       break;
> > +               }
> > +       }
> > +       if (i == pimucfg->m4u_port_nr)
> > +               dev_err(pimu->dev, "tf_id find fail, tfid %d\n", tf_id);
> > +       return portid;
> > +}
> 
> This function seems to be used just for finding an index into the
> array of hardcoded port names for printing purposes.
   Yes. "mtk_iommu_get_port_name" and "mtk_iommu_get_port_by_tfid" is
only for find out the right port to print for improve debug.
> 
[snip]
> > +
> > +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
> > +                                   int isinvall, unsigned int iova_start,
> > +                                   unsigned int iova_end)
> > +{
> > +       void __iomem *m4u_base = piommu->m4u_base;
> > +       u32 val;
> > +       u64 start, end;
> > +
> > +       start = sched_clock();
> 
> I don't think this is the preferred way of checking time in kernel
> drivers, especially after seeing this comment:
> http://lxr.free-electrons.com/source/include/linux/sched.h#L2134
> 
> You should use ktime_get() and other ktime_ helpers.
> 
   I will try to replace this with readl_polling_timeout from Mitchel.
Is it ok?

> > +
> > +       if (!isinvall) {
> > +               iova_start = round_down(iova_start, SZ_4K);
> > +               iova_end = round_up(iova_end, SZ_4K);
> > +       }
> > +
> > +       val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
> > +
> > +       writel(val, m4u_base + REG_INVLID_SEL);
> > +
> > +       if (isinvall) {
> > +               writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> 
> Please move invalidate all into separate function and just call it
> wherever the code currently passes true as invall argument. You will
> get rid of two of the ifs in this function.
> 
> > +       } else {
> > +               writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
> > +               writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
> > +               writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
> > +
> > +               while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
> > +                       end = sched_clock();
> > +                       if (end - start >= 100000000ULL) {
> 
> Looks like a very interesting magic number. Please define a macro and
> use normal time units along with ktime_to_<unit>() helpers.
> 
> > +                               dev_warn(piommu->dev, "invalid don't done\n");
> > +                               writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
> 
> By following my comment above, you could just call the new invalidate
> all function here instead of duplicating the same register write.
[snip]
> Best regards,
> Tomasz



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-09 12:11     ` Yong Wu
@ 2015-03-17 15:14       ` Will Deacon
  0 siblings, 0 replies; 55+ messages in thread
From: Will Deacon @ 2015-03-17 15:14 UTC (permalink / raw)
  To: Yong Wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Daniel Kurtz, Tomasz Figa, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

On Mon, Mar 09, 2015 at 12:11:43PM +0000, Yong Wu wrote:
> On Fri, 2015-03-06 at 10:58 +0000, Will Deacon wrote:
> > On Fri, Mar 06, 2015 at 10:48:17AM +0000, yong.wu@mediatek.com wrote:
> > > From: Yong Wu <yong.wu@mediatek.com>
> > > 
> > > This patch adds support for mediatek m4u (MultiMedia Memory Management Unit).
> > > Currently this only supports m4u gen 2 with 2 levels of page table on mt8173.
> > 
> > [...]
> > 
> > > +/* 2 level pagetable: pgd -> pte */
> > > +#define F_PTE_TYPE_GET(regval)  (regval & 0x3)
> > > +#define F_PTE_TYPE_LARGE         BIT(0)
> > > +#define F_PTE_TYPE_SMALL         BIT(1)
> > > +#define F_PTE_B_BIT              BIT(2)
> > > +#define F_PTE_C_BIT              BIT(3)
> > > +#define F_PTE_BIT32_BIT          BIT(9)
> > > +#define F_PTE_S_BIT              BIT(10)
> > > +#define F_PTE_NG_BIT             BIT(11)
> > > +#define F_PTE_PA_LARGE_MSK            (~0UL << 16)
> > > +#define F_PTE_PA_LARGE_GET(regval)    ((regval >> 16) & 0xffff)
> > > +#define F_PTE_PA_SMALL_MSK            (~0UL << 12)
> > > +#define F_PTE_PA_SMALL_GET(regval)    ((regval >> 12) & (~0))
> > > +#define F_PTE_TYPE_IS_LARGE_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> > > +                                       F_PTE_TYPE_LARGE)
> > > +#define F_PTE_TYPE_IS_SMALL_PAGE(pte) ((imu_pte_val(pte) & 0x3) == \
> > > +                                       F_PTE_TYPE_SMALL)
> > 
> > This looks like the ARM short-descriptor format to me. Could you please
> > add a new page table format to the io-pgtable code, so that other IOMMU
> > drivers can make use of this? I know there was some interest in using
> > short descriptor for the ARM SMMU, for example.
>     Currently I not familiar with the io-pgtable,I may need some time
> for it and the ARM short-descriptor. 

Well, you can read the LPAE version I wrote in io-pgtable-arm.c for some
inspiration (it's used by arm-smmu.c and ipmmu-vmsa.c).

>     And there are some difference between mediatek's pagetable with the
> standard short-descriptor, like bit 9. we use it for the dram over 4GB.
> Then how should we do if there are some difference. 

That can easily be handled using a quirk (see, for example,
IO_PGTABLE_QUIRK_ARM_NS).

Will

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-11 10:53   ` Tomasz Figa
@ 2015-03-18 11:22     ` Yong Wu
  2015-03-20 19:14       ` Robin Murphy
  2015-03-27  9:41       ` Tomasz Figa
  0 siblings, 2 replies; 55+ messages in thread
From: Yong Wu @ 2015-03-18 11:22 UTC (permalink / raw)
  To: Tomasz Figa, Robin Murphy
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Will Deacon,
	Daniel Kurtz, Lucas Stach, Mark Rutland, Catalin Marinas,
	linux-mediatek, Sasha Hauer, srv_heupstream, devicetree,
	linux-kernel, linux-arm-kernel, iommu, yong.wu

Hi Tomasz,
   Thanks very much for your review. please help check below.
The others I will fix in the next version.

Hi Robin,
   There are some place I would like you can have a look and give me
some suggestion.

On Wed, 2015-03-11 at 19:53 +0900, Tomasz Figa wrote:
> Hi,
> 
> Please find next part of my comments inline.
> 
> On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:
> 
> [snip]
> 
> > +/*
> > + * pimudev is a global var for dma_alloc_coherent.
> > + * It is not accepatable, we will delete it if "domain_alloc" is enabled
> 
> It looks like we indeed need to use dma_alloc_coherent() and we don't
> have a good way to pass the device pointer to domain_init callback.
> 
> If you don't expect SoCs in the nearest future to have multiple M4U
> blocks, then I guess this global variable could stay, after changing
> the comment into an explanation why it's correct. Also it should be
> moved to the top of the file, below #include directives, as this is
> where usually global variables are located.
@Robin,
     We have merged this patch[0] in order to delete the global var, But
it seems that your patch of "arm64:IOMMU" isn't based on it right row.
it will build fail.

[0]:http://lists.linuxfoundation.org/pipermail/iommu/2015-January/011939.html

> > + */
> > +static struct device *pimudev;
> > +
[snip]
> > +
> > +static int mtk_iommu_attach_device(struct iommu_domain *domain,
> > +                                  struct device *dev)
> > +{
> > +       unsigned long flags;
> > +       struct mtk_iommu_domain *priv = domain->priv;
> > +       struct mtk_iommu_info *piommu = priv->piommuinfo;
> > +       struct of_phandle_args out_args = {0};
> > +       struct device *imudev;
> > +       unsigned int i = 0;
> > +
> > +       if (!piommu)
> 
> Could you explain when this can happen?
	If we call arch_setup_dma_ops to create a iommu domain,
it will enter iommu_dma_attach_device, then enter here. At that time, we
don't add the private data to this "struct iommu_domain *".
@Robin, Could this be improved?
> 
> > +               goto imudev;
> 
> return 0;
> 
> > +       else
> 
> No else needed.
> 
> > +               imudev = piommu->dev;
> > +
> > +       spin_lock_irqsave(&priv->portlock, flags);
> 
> What is protected by this spinlock?
	We will write a register of the local arbiter while config port. If
some modules are in the same local arbiter, it may be overwrite. so I
add it here.
> 
> > +
> > +       while (!of_parse_phandle_with_args(dev->of_node, "iommus",
> > +                                          "#iommu-cells", i, &out_args)) {
> > +               if (1 == out_args.args_count) {
> 
> Can we be sure that this is actually referring to our IOMMU?
> 
> Maybe this should be rewritten to
> 
> if (out_args.np != imudev->of_node)
>         continue;
> if (out_args.args_count != 1) {
>         dev_err(imudev, "invalid #iommu-cells property for IOMMU %s\n",
> 
> }
> 
> > +                       unsigned int portid = out_args.args[0];
> > +
> > +                       dev_dbg(dev, "iommu add port:%d\n", portid);
> 
> imudev should be used here instead of dev.
> 
> > +
> > +                       mtk_iommu_config_port(piommu, portid);
> > +
> > +                       if (i == 0)
> > +                               dev->archdata.dma_ops =
> > +                                       piommu->dev->archdata.dma_ops;
> 
> Shouldn't this be set automatically by IOMMU or DMA mapping core?
@Robin, 
     In the original "arm_iommu_attach_device" of arm/mm, it will call
set_dma_ops to add iommu_ops for each iommu device.
But iommu_dma_attach_device don't help this, so I have to add it here.
Could this be improved?
> 
> > +               }
> > +               i++;
> > +       }
> > +
> > +       spin_unlock_irqrestore(&priv->portlock, flags);
> > +
> > +imudev:
> > +       return 0;
> > +}
> > +
> > +static void mtk_iommu_detach_device(struct iommu_domain *domain,
> > +                                   struct device *dev)
> > +{
> 
> No hardware (de)configuration or clean-up necessary?
I will add it. Actually we design like this:If a device have attached to
iommu domain, it won't detach from it.
> 
> > +}
> > +
[snip]
> 
> > +
> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
> 
> style: Operators like * should have space on both sides.
> 
> > +                                         GFP_KERNEL);
> 
> Shouldn't dma_alloc_coherent() be used for this?
     We don't care the data in it. I think they are the same. Could you
help tell me why dma_alloc_coherent may be better.
> 
> > +       if (!piommu->protect_va)
> > +               goto protect_err;
> 
> Please return -ENOMEM here directly, as there is nothing to clean up
> in this case.
> 
[snip]
> 
> > +               dev_err(piommu->dev, "IRQ request %d failed\n",
> > +                       piommu->irq);
> > +               goto hw_err;
> > +       }
> > +
> > +       iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);
> 
> I don't see any other drivers doing this. Isn't this for upper layers,
> so that they can set their own generic fault handlers?
     I think that this function is related with the iommu domain, we
have only one multimedia iommu domain. so I add it after the iommu
domain are created.
> 
> > +
> > +       dev_set_drvdata(piommu->dev, piommu);
> 
> This should be set before allowing the interrupt to fire. In other
> words, the driver should be fully set up at the time of enabling the
> IRQ.
> 
> > +
> > +       return 0;
> 
> style: Missing blank line.
> 
> > +hw_err:
> > +       arch_teardown_dma_ops(piommu->dev);
> > +pte_err:
> > +       kmem_cache_destroy(piommu->m4u_pte_kmem);
> > +protect_err:
> > +       dev_err(piommu->dev, "probe error\n");
> 
> Please replace this with specific messages for all errors (in case the
> called function doesn't already print one like kmalloc and friends).
> 
> > +       return 0;
> 
> Returning 0, which means success, doesn't look like a good idea for
> signalling a failure. Please return the correct error code as received
> from function that errors out if possible.
> 
> End of part 3.
> 
> Best regards,
> Tomasz



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-18 11:22     ` Yong Wu
@ 2015-03-20 19:14       ` Robin Murphy
  2015-04-14  6:50         ` Yong Wu
  2015-03-27  9:41       ` Tomasz Figa
  1 sibling, 1 reply; 55+ messages in thread
From: Robin Murphy @ 2015-03-20 19:14 UTC (permalink / raw)
  To: Yong Wu, Tomasz Figa
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Will Deacon,
	Daniel Kurtz, Lucas Stach, Mark Rutland, Catalin Marinas,
	linux-mediatek, Sasha Hauer, srv_heupstream, devicetree,
	linux-kernel, linux-arm-kernel, iommu

On 18/03/15 11:22, Yong Wu wrote:
> Hi Tomasz,
>     Thanks very much for your review. please help check below.
> The others I will fix in the next version.
>
> Hi Robin,
>     There are some place I would like you can have a look and give me
> some suggestion.
>
> On Wed, 2015-03-11 at 19:53 +0900, Tomasz Figa wrote:
>> Hi,
>>
>> Please find next part of my comments inline.
>>
>> On Fri, Mar 6, 2015 at 7:48 PM,  <yong.wu@mediatek.com> wrote:
>>
>> [snip]
>>
>>> +/*
>>> + * pimudev is a global var for dma_alloc_coherent.
>>> + * It is not accepatable, we will delete it if "domain_alloc" is enabled
>>
>> It looks like we indeed need to use dma_alloc_coherent() and we don't
>> have a good way to pass the device pointer to domain_init callback.
>>
>> If you don't expect SoCs in the nearest future to have multiple M4U
>> blocks, then I guess this global variable could stay, after changing
>> the comment into an explanation why it's correct. Also it should be
>> moved to the top of the file, below #include directives, as this is
>> where usually global variables are located.
> @Robin,
>       We have merged this patch[0] in order to delete the global var, But
> it seems that your patch of "arm64:IOMMU" isn't based on it right row.
> it will build fail.

Yeah, I've not yet managed to try pulling in that series (much as I 
approve of it), partly as I know doing so is going to lean towards a 
not-insignificant rework and I'd rather avoid picking up more unmerged 
dependencies to block getting _something_ in for arm64 (which we can 
then improve).

>
> [0]:http://lists.linuxfoundation.org/pipermail/iommu/2015-January/011939.html
>
>>> + */
>>> +static struct device *pimudev;
>>> +
> [snip]
>>> +
>>> +static int mtk_iommu_attach_device(struct iommu_domain *domain,
>>> +                                  struct device *dev)
>>> +{
>>> +       unsigned long flags;
>>> +       struct mtk_iommu_domain *priv = domain->priv;
>>> +       struct mtk_iommu_info *piommu = priv->piommuinfo;
>>> +       struct of_phandle_args out_args = {0};
>>> +       struct device *imudev;
>>> +       unsigned int i = 0;
>>> +
>>> +       if (!piommu)
>>
>> Could you explain when this can happen?
> 	If we call arch_setup_dma_ops to create a iommu domain,
> it will enter iommu_dma_attach_device, then enter here. At that time, we
> don't add the private data to this "struct iommu_domain *".
> @Robin, Could this be improved?

Calling arch_setup_dma_ops() from the driver looks plain wrong, 
especially given that you apparently attach the IOMMU to itself - if you 
want your own domain you should use iommu_dma_create_domain(). I admit 
that still leaves you having to dance around a bit in order to tear down 
the automatic domains for now, but hopefully we'll get the core code 
sorted out sooner rather than later.

>>
>>> +               goto imudev;
>>
>> return 0;
>>
>>> +       else
>>
>> No else needed.
>>
>>> +               imudev = piommu->dev;
>>> +
>>> +       spin_lock_irqsave(&priv->portlock, flags);
>>
>> What is protected by this spinlock?
> 	We will write a register of the local arbiter while config port. If
> some modules are in the same local arbiter, it may be overwrite. so I
> add it here.
>>
>>> +
>>> +       while (!of_parse_phandle_with_args(dev->of_node, "iommus",
>>> +                                          "#iommu-cells", i, &out_args)) {
>>> +               if (1 == out_args.args_count) {
>>
>> Can we be sure that this is actually referring to our IOMMU?
>>
>> Maybe this should be rewritten to
>>
>> if (out_args.np != imudev->of_node)
>>          continue;
>> if (out_args.args_count != 1) {
>>          dev_err(imudev, "invalid #iommu-cells property for IOMMU %s\n",
>>
>> }
>>
>>> +                       unsigned int portid = out_args.args[0];
>>> +
>>> +                       dev_dbg(dev, "iommu add port:%d\n", portid);
>>
>> imudev should be used here instead of dev.
>>
>>> +
>>> +                       mtk_iommu_config_port(piommu, portid);
>>> +
>>> +                       if (i == 0)
>>> +                               dev->archdata.dma_ops =
>>> +                                       piommu->dev->archdata.dma_ops;
>>
>> Shouldn't this be set automatically by IOMMU or DMA mapping core?
> @Robin,
>       In the original "arm_iommu_attach_device" of arm/mm, it will call
> set_dma_ops to add iommu_ops for each iommu device.
> But iommu_dma_attach_device don't help this, so I have to add it here.
> Could this be improved?

If you implemented a simple of_xlate callback so that the core code 
handles the dma_ops as intended, I think the simplest cheat would be to 
check the client device's domain, either on attachment or when they 
start mapping/unmapping, and move them to your own domain if necessary. 
I'm putting together a v3 of the DMA mapping series, so I'll have a look 
to see if I can squeeze in a way to make that a bit less painful until 
we solve it properly.


Robin.

>>
>>> +               }
>>> +               i++;
>>> +       }
>>> +
>>> +       spin_unlock_irqrestore(&priv->portlock, flags);
>>> +
>>> +imudev:
>>> +       return 0;
>>> +}
>>> +
>>> +static void mtk_iommu_detach_device(struct iommu_domain *domain,
>>> +                                   struct device *dev)
>>> +{
>>
>> No hardware (de)configuration or clean-up necessary?
> I will add it. Actually we design like this:If a device have attached to
> iommu domain, it won't detach from it.
>>
>>> +}
>>> +
> [snip]
>>
>>> +
>>> +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
>>
>> style: Operators like * should have space on both sides.
>>
>>> +                                         GFP_KERNEL);
>>
>> Shouldn't dma_alloc_coherent() be used for this?
>       We don't care the data in it. I think they are the same. Could you
> help tell me why dma_alloc_coherent may be better.
>>
>>> +       if (!piommu->protect_va)
>>> +               goto protect_err;
>>
>> Please return -ENOMEM here directly, as there is nothing to clean up
>> in this case.
>>
> [snip]
>>
>>> +               dev_err(piommu->dev, "IRQ request %d failed\n",
>>> +                       piommu->irq);
>>> +               goto hw_err;
>>> +       }
>>> +
>>> +       iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);
>>
>> I don't see any other drivers doing this. Isn't this for upper layers,
>> so that they can set their own generic fault handlers?
>       I think that this function is related with the iommu domain, we
> have only one multimedia iommu domain. so I add it after the iommu
> domain are created.
>>
>>> +
>>> +       dev_set_drvdata(piommu->dev, piommu);
>>
>> This should be set before allowing the interrupt to fire. In other
>> words, the driver should be fully set up at the time of enabling the
>> IRQ.
>>
>>> +
>>> +       return 0;
>>
>> style: Missing blank line.
>>
>>> +hw_err:
>>> +       arch_teardown_dma_ops(piommu->dev);
>>> +pte_err:
>>> +       kmem_cache_destroy(piommu->m4u_pte_kmem);
>>> +protect_err:
>>> +       dev_err(piommu->dev, "probe error\n");
>>
>> Please replace this with specific messages for all errors (in case the
>> called function doesn't already print one like kmalloc and friends).
>>
>>> +       return 0;
>>
>> Returning 0, which means success, doesn't look like a good idea for
>> signalling a failure. Please return the correct error code as received
>> from function that errors out if possible.
>>
>> End of part 3.
>>
>> Best regards,
>> Tomasz
>
>
>



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-18 11:22     ` Yong Wu
  2015-03-20 19:14       ` Robin Murphy
@ 2015-03-27  9:41       ` Tomasz Figa
  2015-04-14  6:31         ` Yong Wu
  2015-04-29  6:23         ` Yong Wu
  1 sibling, 2 replies; 55+ messages in thread
From: Tomasz Figa @ 2015-03-27  9:41 UTC (permalink / raw)
  To: Yong Wu
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

Hi Yong Wu,

Sorry for long delay, I had to figure out some time to look at this again.

On Wed, Mar 18, 2015 at 8:22 PM, Yong Wu <yong.wu@mediatek.com> wrote:
>>
>> > +               imudev = piommu->dev;
>> > +
>> > +       spin_lock_irqsave(&priv->portlock, flags);
>>
>> What is protected by this spinlock?
>         We will write a register of the local arbiter while config port. If
> some modules are in the same local arbiter, it may be overwrite. so I
> add it here.
>>

OK. Maybe it could be called larb_lock then? It would be good to have
structures or code that should be running under this spinlock
annotated with proper comments. And purpose of the lock documented in
a comment as well (probably in a kerneldoc-style documentation of
priv).

>> > +static void mtk_iommu_detach_device(struct iommu_domain *domain,
>> > +                                   struct device *dev)
>> > +{
>>
>> No hardware (de)configuration or clean-up necessary?
> I will add it. Actually we design like this:If a device have attached to
> iommu domain, it won't detach from it.

Isn't proper clean-up required for module removal? Some drivers might
be required to be loadable modules, which should be unloadable.

>>
>> > +
>> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
>>
>> style: Operators like * should have space on both sides.
>>
>> > +                                         GFP_KERNEL);
>>
>> Shouldn't dma_alloc_coherent() be used for this?
>      We don't care the data in it. I think they are the same. Could you
> help tell me why dma_alloc_coherent may be better.

Can you guarantee that at the time you allocate the memory using
devm_kmalloc() the memory is not dirty (i.e. some write back data are
stored in CPU cache) and is not going to be written back in some time,
overwriting data put there by IOMMU hardware?

>> > +
>> > +       iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);
>>
>> I don't see any other drivers doing this. Isn't this for upper layers,
>> so that they can set their own generic fault handlers?
>      I think that this function is related with the iommu domain, we
> have only one multimedia iommu domain. so I add it after the iommu
> domain are created.

No, this function is for drivers of IOMMU clients (i.e. master IP
blocks) which want to subscribe to page fault to do things like paging
on demand and so on. It shouldn't be called by IOMMU driver. Please
see other IOMMU drivers, for example rockchip-iommmu.c.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-27  9:41       ` Tomasz Figa
@ 2015-04-14  6:31         ` Yong Wu
  2015-04-15  2:20           ` Tomasz Figa
  2015-04-29  6:23         ` Yong Wu
  1 sibling, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-04-14  6:31 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

Hi Tomasz,

     Thanks very much for you suggestion and explain so detail.
     please help check below.

On Fri, 2015-03-27 at 18:41 +0900, Tomasz Figa wrote:
> Hi Yong Wu,
> 
> Sorry for long delay, I had to figure out some time to look at this again.
> 
> On Wed, Mar 18, 2015 at 8:22 PM, Yong Wu <yong.wu@mediatek.com> wrote:
> >>
> >> > +               imudev = piommu->dev;
> >> > +
> >> > +       spin_lock_irqsave(&priv->portlock, flags);
> >>
> >> What is protected by this spinlock?
> >         We will write a register of the local arbiter while config port. If
> > some modules are in the same local arbiter, it may be overwrite. so I
> > add it here.
> >>
> 
> OK. Maybe it could be called larb_lock then? It would be good to have
> structures or code that should be running under this spinlock
> annotated with proper comments. And purpose of the lock documented in
> a comment as well (probably in a kerneldoc-style documentation of
> priv).
   Thanks. I have move the spinlock into the smi driver, it will lock
for writing the local arbiter regsiter only.
> 
> >> > +static void mtk_iommu_detach_device(struct iommu_domain *domain,
> >> > +                                   struct device *dev)
> >> > +{
> >>
> >> No hardware (de)configuration or clean-up necessary?
> > I will add it. Actually we design like this:If a device have attached to
> > iommu domain, it won't detach from it.
> 
> Isn't proper clean-up required for module removal? Some drivers might
> be required to be loadable modules, which should be unloadable.
> 
> >>
> >> > +
> >> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
> >>
> >> style: Operators like * should have space on both sides.
> >>
> >> > +                                         GFP_KERNEL);
> >>
> >> Shouldn't dma_alloc_coherent() be used for this?
> >      We don't care the data in it. I think they are the same. Could you
> > help tell me why dma_alloc_coherent may be better.
> 
> Can you guarantee that at the time you allocate the memory using
> devm_kmalloc() the memory is not dirty (i.e. some write back data are
> stored in CPU cache) and is not going to be written back in some time,
> overwriting data put there by IOMMU hardware?
> 
As I noted in the function "mtk_iommu_hw_init":

       /* protect memory,HW will write here while translation fault */
       protectpa = __virt_to_phys(piommu->protect_va);

     We don’t care the content of this buffer, It is ok even though its
data is dirty.
    It seem to be a the protect memory. While a translation fault
happened, The iommu HW will overwrite here instead of writing to the
fault physical address which may be 0 or some random address.

> >> > +
> >> > +       iommu_set_fault_handler(domain, mtk_iommu_fault_handler, piommu);
> >>
> >> I don't see any other drivers doing this. Isn't this for upper layers,
> >> so that they can set their own generic fault handlers?
> >      I think that this function is related with the iommu domain, we
> > have only one multimedia iommu domain. so I add it after the iommu
> > domain are created.
> 
> No, this function is for drivers of IOMMU clients (i.e. master IP
> blocks) which want to subscribe to page fault to do things like paging
> on demand and so on. It shouldn't be called by IOMMU driver. Please
> see other IOMMU drivers, for example rockchip-iommmu.c.
     Thanks. I have read it. I will delete it and print the error info
in the ISR. Also call the report_iommu_fault in the ISR.

> Best regards,
> Tomasz



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-20 19:14       ` Robin Murphy
@ 2015-04-14  6:50         ` Yong Wu
  0 siblings, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-04-14  6:50 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Tomasz Figa, Rob Herring, Joerg Roedel, Matthias Brugger,
	Will Deacon, Daniel Kurtz, Lucas Stach, Mark Rutland,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi Robin,
      Thanks very much for your confirm.
      About the v3 of the DMA-mapping, I have some question below.

On Fri, 2015-03-20 at 19:14 +0000, Robin Murphy wrote:
> On 18/03/15 11:22, Yong Wu wrote:
> > Hi Tomasz,
> >     Thanks very much for your review. please help check below.
> > The others I will fix in the next version.
> >
> > Hi Robin,
> >     There are some place I would like you can have a look and give me
> > some suggestion.
> >
> > On Wed, 2015-03-11 at 19:53 +0900, Tomasz Figa wrote:
> >> Hi,
> >>
> >> Please find next part of my comments inline.
> >>
> >>> +/*
> >>> + * pimudev is a global var for dma_alloc_coherent.
> >>> + * It is not accepatable, we will delete it if "domain_alloc" is enabled
> >>
> >> It looks like we indeed need to use dma_alloc_coherent() and we don't
> >> have a good way to pass the device pointer to domain_init callback.
> >>
> >> If you don't expect SoCs in the nearest future to have multiple M4U
> >> blocks, then I guess this global variable could stay, after changing
> >> the comment into an explanation why it's correct. Also it should be
> >> moved to the top of the file, below #include directives, as this is
> >> where usually global variables are located.
> > @Robin,
> >       We have merged this patch[0] in order to delete the global var, But
> > it seems that your patch of "arm64:IOMMU" isn't based on it right row.
> > it will build fail.
> 
> Yeah, I've not yet managed to try pulling in that series (much as I 
> approve of it), partly as I know doing so is going to lean towards a 
> not-insignificant rework and I'd rather avoid picking up more unmerged 
> dependencies to block getting _something_ in for arm64 (which we can 
> then improve).
> 
> >
> > [0]:http://lists.linuxfoundation.org/pipermail/iommu/2015-January/011939.html
> >
[snip]
> 
> Calling arch_setup_dma_ops() from the driver looks plain wrong, 
> especially given that you apparently attach the IOMMU to itself - if you 
> want your own domain you should use iommu_dma_create_domain(). I admit 
> that still leaves you having to dance around a bit in order to tear down 
> the automatic domains for now, but hopefully we'll get the core code 
> sorted out sooner rather than later.
> >>> +
> >>> +                       mtk_iommu_config_port(piommu, portid);
> >>> +
> >>> +                       if (i == 0)
> >>> +                               dev->archdata.dma_ops =
> >>> +                                       piommu->dev->archdata.dma_ops;
> >>
> >> Shouldn't this be set automatically by IOMMU or DMA mapping core?
> > @Robin,
> >       In the original "arm_iommu_attach_device" of arm/mm, it will call
> > set_dma_ops to add iommu_ops for each iommu device.
> > But iommu_dma_attach_device don't help this, so I have to add it here.
> > Could this be improved?
> 
> If you implemented a simple of_xlate callback so that the core code 
> handles the dma_ops as intended, I think the simplest cheat would be to 
> check the client device's domain, either on attachment or when they 
> start mapping/unmapping, and move them to your own domain if necessary. 
> I'm putting together a v3 of the DMA mapping series, so I'll have a look 
> to see if I can squeeze in a way to make that a bit less painful until 
> we solve it properly.
> 
> 
> Robin.
> 
      I have implemented a simple of_xlate, but I can’t get the standard
struct dma_map_ops “iommu_dma_ops” to assigned it to the client device.
So the v3 of dma mapping will improve this issue?  

      And Is the v3 of the DMA-mapping based on 4.0-rc1? because we
expect it could contain will’s io-pagetable.

      And when the v3 will be ready?
> >>
> >>> +               }
> >>> +               i++;
> >>> +       }
> >>> +
> >>> +       spin_unlock_irqrestore(&priv->portlock, flags);
> >>> +
> >>> +imudev:
> >>> +       return 0;
> >>> +}
> >>> +
> >>> +static void mtk_iommu_detach_device(struct iommu_domain *domain,
> >>> +                                   struct device *dev)
> >>> +{
> >>
> >> No hardware (de)configuration or clean-up necessary?
> > I will add it. Actually we design like this:If a device have attached to
> > iommu domain, it won't detach from it.
> >>
> >>> +}
> >>> +
> > [snip]



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-03-06 11:13   ` Mark Rutland
  2015-03-09 12:55     ` Yong Wu
@ 2015-04-14  9:07     ` Yong Wu
  2015-04-14 10:06       ` Mark Rutland
  1 sibling, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-04-14  9:07 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi Mark,
    Thanks very much for review. 
    About the clock name should be the PoV of _this_ device. Could you
help check below?

On Fri, 2015-03-06 at 11:13 +0000, Mark Rutland wrote:
> On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> > From: Yong Wu <yong.wu@mediatek.com>
> > 
> > This patch add smi binding document.
> 
> Please move binding documents to the start of the series. It makes
> things far easier to review.
> 
> > 
> > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > @@ -0,0 +1,17 @@
> > +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> > +
> > +Required properties:
> > +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"
> 
> Double vendor prefix?
> 
> What does "larb" mean? It would be nice for the intorductory paragraph
> in this file to explain.
> 
> > +- reg : the register of each local arbiter
> > +- clocks : the clocks of each local arbiter
> > +- clock-name: larb_sub*(3 clockes at most)
> 
> The names required _must_ be specified here, or clock-names is
> pointless.
> 
> The clock names should be from the PoV of _this_ device (i.e. they
> should be the names of the inputs) not from the PoV of the provider
> (i.e. they should not be the names of the outputs from the provider).
> 
> Mark.
> 
     After we check with our SMI Designer. Every SMI local arbiter need
two clocks, which is called  APB clocks and SMI clock.
     APB clock : Advanced Peripheral Bus Clock. It is the clock for
setting the register of local arbiter.
     SMI clock : Smart Multimedia Interface Clock, It is the clock for
transfering the data and command. 

     And all the local arbiters need the smi common clock, so we
separate it. 

     Then I prepare to design the smi the dtsi like this: 

      smi_common:smi@14022000 {
                 compatible = “mediate, mt8173-smi”;
                 reg = <0 0x14022000 0 0x1000>;
                 clocks = <&mmsys MM_SMI_COMMON>;
                 clocks-names = “smi_common”;
      };

      larb0: larb@14021000 {
                 compatible = “mediate, mt8173-smi-larb”;
                 reg = <0 0x14021000 0 0x1000>;
                 smi = <&smi_common>;
                 clocks = <&mmsys MM_SMI_LARB0>, 
		 	<&mmsys MM_SMI_LARB0>;
                 clocks-names = “apb_clk”, “smi_clk”;
     };

     larb1: larb@16010000 {
                 compatible = “mediate, mt8173-smi-larb”;
                 reg = <0 0x16010000 0 0x1000>;
                 smi = <&smi_common>;
                 clocks = <&vdecsys VDEC_CKEN>, 
			 <&mmsys VDEC_LARB_CKEN>;
                 clocks-names = “apb_clk”, “smi_clk”;
      };
      … 
     In some local arbiter, the source clock of the APB clock and the
SMI clock may be the same, like larb0. so the two clocks are the same.
And they may be different in other local arbiteres, like larb1.      

     If it is designed like this, is it ok?

> > +
> > +Example:
> > +	larb1:larb@16010000 {
> > +	        compatible = "mediatek,mt8173-smi-larb";
> > +		reg = <0 0x16010000 0 0x1000>;
> > +		clocks = <&mmsys MM_SMI_COMMON>,
> > +		        <&vdecsys VDEC_CKEN>,
> > +                        <&vdecsys VDEC_LARB_CKEN>;
> > +		clock-names = "larb_sub0", "larb_sub1", "larb_sub2";
> > +	};
> > -- 
> > 1.8.1.1.dirty
> > 
> > 



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-04-14  9:07     ` Yong Wu
@ 2015-04-14 10:06       ` Mark Rutland
  2015-04-14 13:49         ` Yong Wu
  0 siblings, 1 reply; 55+ messages in thread
From: Mark Rutland @ 2015-04-14 10:06 UTC (permalink / raw)
  To: Yong Wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

On Tue, Apr 14, 2015 at 10:07:54AM +0100, Yong Wu wrote:
> Hi Mark,
>     Thanks very much for review. 
>     About the clock name should be the PoV of _this_ device. Could you
> help check below?
> 
> On Fri, 2015-03-06 at 11:13 +0000, Mark Rutland wrote:
> > On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> > > From: Yong Wu <yong.wu@mediatek.com>
> > > 
> > > This patch add smi binding document.
> > 
> > Please move binding documents to the start of the series. It makes
> > things far easier to review.
> > 
> > > 
> > > Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > > +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
> > > @@ -0,0 +1,17 @@
> > > +SMI hardware block diagram please help check <bindings/iommu/mediatek,iommu.txt>
> > > +
> > > +Required properties:
> > > +- compatible : must be "mediatek,mediatek,mt8173-smi-larb"
> > 
> > Double vendor prefix?
> > 
> > What does "larb" mean? It would be nice for the intorductory paragraph
> > in this file to explain.
> > 
> > > +- reg : the register of each local arbiter
> > > +- clocks : the clocks of each local arbiter
> > > +- clock-name: larb_sub*(3 clockes at most)
> > 
> > The names required _must_ be specified here, or clock-names is
> > pointless.
> > 
> > The clock names should be from the PoV of _this_ device (i.e. they
> > should be the names of the inputs) not from the PoV of the provider
> > (i.e. they should not be the names of the outputs from the provider).
> > 
> > Mark.
> > 
>      After we check with our SMI Designer. Every SMI local arbiter need
> two clocks, which is called  APB clocks and SMI clock.
>      APB clock : Advanced Peripheral Bus Clock. It is the clock for
> setting the register of local arbiter.
>      SMI clock : Smart Multimedia Interface Clock, It is the clock for
> transfering the data and command. 
> 
>      And all the local arbiters need the smi common clock, so we
> separate it. 
> 
>      Then I prepare to design the smi the dtsi like this: 
> 
>       smi_common:smi@14022000 {
>                  compatible = “mediate, mt8173-smi”;
>                  reg = <0 0x14022000 0 0x1000>;
>                  clocks = <&mmsys MM_SMI_COMMON>;
>                  clocks-names = “smi_common”;
>       };
> 
>       larb0: larb@14021000 {
>                  compatible = “mediate, mt8173-smi-larb”;
>                  reg = <0 0x14021000 0 0x1000>;
>                  smi = <&smi_common>;
>                  clocks = <&mmsys MM_SMI_LARB0>, 
> 		 	<&mmsys MM_SMI_LARB0>;
>                  clocks-names = “apb_clk”, “smi_clk”;
>      };
> 
>      larb1: larb@16010000 {
>                  compatible = “mediate, mt8173-smi-larb”;
>                  reg = <0 0x16010000 0 0x1000>;
>                  smi = <&smi_common>;
>                  clocks = <&vdecsys VDEC_CKEN>, 
> 			 <&mmsys VDEC_LARB_CKEN>;
>                  clocks-names = “apb_clk”, “smi_clk”;
>       };
>       … 
>      In some local arbiter, the source clock of the APB clock and the
> SMI clock may be the same, like larb0. so the two clocks are the same.
> And they may be different in other local arbiteres, like larb1.      
> 
>      If it is designed like this, is it ok?

That looks pretty good; the clocks and names on the larb nodes seem
sensible.

The naming of the "smi_common" clock on the smi_common node looks a bit
odd though. Is that really what the clock input is called?

Mark.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-04-14 10:06       ` Mark Rutland
@ 2015-04-14 13:49         ` Yong Wu
  2015-04-14 13:55           ` Yong Wu
  2015-04-14 13:56           ` Mark Rutland
  0 siblings, 2 replies; 55+ messages in thread
From: Yong Wu @ 2015-04-14 13:49 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

Hi Mark,

On Tue, 2015-04-14 at 11:06 +0100, Mark Rutland wrote:
> On Tue, Apr 14, 2015 at 10:07:54AM +0100, Yong Wu wrote:
> > Hi Mark,
> >     Thanks very much for review. 
> >     About the clock name should be the PoV of _this_ device. Could you
> > help check below?
> > 
> > On Fri, 2015-03-06 at 11:13 +0000, Mark Rutland wrote:
> > > On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> > > > From: Yong Wu <yong.wu@mediatek.com>
> > > > 
> > > > This patch add smi binding document.
> > > 
> > > Please move binding documents to the start of the series. It makes
> > > things far easier to review.
> > >  
> > > What does "larb" mean? It would be nice for the intorductory paragraph
> > > in this file to explain.
> > > 
> > > > +- reg : the register of each local arbiter
> > > > +- clocks : the clocks of each local arbiter
> > > > +- clock-name: larb_sub*(3 clockes at most)
> > > 
> > > The names required _must_ be specified here, or clock-names is
> > > pointless.
> > > 
> > > The clock names should be from the PoV of _this_ device (i.e. they
> > > should be the names of the inputs) not from the PoV of the provider
> > > (i.e. they should not be the names of the outputs from the provider).
> > > 
> > > Mark.
> > > 
> >      After we check with our SMI Designer. Every SMI local arbiter need
> > two clocks, which is called  APB clocks and SMI clock.
> >      APB clock : Advanced Peripheral Bus Clock. It is the clock for
> > setting the register of local arbiter.
> >      SMI clock : Smart Multimedia Interface Clock, It is the clock for
> > transfering the data and command. 
> > 
> >      And all the local arbiters need the smi common clock, so we
> > separate it. 
> > 
> >      Then I prepare to design the smi the dtsi like this: 
> > 
> >       smi_common:smi@14022000 {
> >                  compatible = “mediate, mt8173-smi”;
> >                  reg = <0 0x14022000 0 0x1000>;
> >                  clocks = <&mmsys MM_SMI_COMMON>;
> >                  clocks-names = “smi_common”;
> >       };
> > 
> >       larb0: larb@14021000 {
> >                  compatible = “mediate, mt8173-smi-larb”;
> >                  reg = <0 0x14021000 0 0x1000>;
> >                  smi = <&smi_common>;
> >                  clocks = <&mmsys MM_SMI_LARB0>, 
> > 		 	<&mmsys MM_SMI_LARB0>;
> >                  clocks-names = “apb_clk”, “smi_clk”;
> >      };
> > 
> >      larb1: larb@16010000 {
> >                  compatible = “mediate, mt8173-smi-larb”;
> >                  reg = <0 0x16010000 0 0x1000>;
> >                  smi = <&smi_common>;
> >                  clocks = <&vdecsys VDEC_CKEN>, 
> > 			 <&mmsys VDEC_LARB_CKEN>;
> >                  clocks-names = “apb_clk”, “smi_clk”;
> >       };
> >       … 
> >      In some local arbiter, the source clock of the APB clock and the
> > SMI clock may be the same, like larb0. so the two clocks are the same.
> > And they may be different in other local arbiteres, like larb1.      
> > 
> >      If it is designed like this, is it ok?
> 
> That looks pretty good; the clocks and names on the larb nodes seem
> sensible.
> 
> The naming of the "smi_common" clock on the smi_common node looks a bit
> odd though. Is that really what the clock input is called?
> 
> Mark.
     After check with DE, the smi_common clock also have its APB clock
and the smi clock(they have the same clock source).
    And I prepare to delete "_clk" in all the clock-names.
    So it may be like this:
         smi_common:smi@14022000 {
                 compatible = “mediate, mt8173-smi”;
                    reg = <0 0x14022000 0 0x1000>;
                  clocks = <&mmsys MM_SMI_COMMON>, 
			   <&mmsys MM_SMI_COMMON>;
                  clocks-names = “apk”,"smi";
        };
     How about this?
   





^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-04-14 13:49         ` Yong Wu
@ 2015-04-14 13:55           ` Yong Wu
  2015-04-14 13:56           ` Mark Rutland
  1 sibling, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-04-14 13:55 UTC (permalink / raw)
  To: Mark Rutland
  Cc: devicetree, srv_heupstream, Catalin Marinas, Joerg Roedel,
	Will Deacon, linux-kernel, Tomasz Figa, iommu, Rob Herring,
	Daniel Kurtz, Sasha Hauer, Matthias Brugger, linux-mediatek,
	Robin Murphy, linux-arm-kernel, Lucas Stach

On Tue, 2015-04-14 at 21:49 +0800, Yong Wu wrote:
> Hi Mark,
> 
> On Tue, 2015-04-14 at 11:06 +0100, Mark Rutland wrote:
> > On Tue, Apr 14, 2015 at 10:07:54AM +0100, Yong Wu wrote:
> > > Hi Mark,
> > >     Thanks very much for review. 
> > >     About the clock name should be the PoV of _this_ device. Could you
> > > help check below?
> > > 
> > > On Fri, 2015-03-06 at 11:13 +0000, Mark Rutland wrote:
> > > > On Fri, Mar 06, 2015 at 10:48:18AM +0000, yong.wu@mediatek.com wrote:
> > > > > From: Yong Wu <yong.wu@mediatek.com>
> > > > > 
> > > > > This patch add smi binding document.
> > > > 
> > > > Please move binding documents to the start of the series. It makes
> > > > things far easier to review.
> > > >  
> > > > What does "larb" mean? It would be nice for the intorductory paragraph
> > > > in this file to explain.
> > > > 
> > > > > +- reg : the register of each local arbiter
> > > > > +- clocks : the clocks of each local arbiter
> > > > > +- clock-name: larb_sub*(3 clockes at most)
> > > > 
> > > > The names required _must_ be specified here, or clock-names is
> > > > pointless.
> > > > 
> > > > The clock names should be from the PoV of _this_ device (i.e. they
> > > > should be the names of the inputs) not from the PoV of the provider
> > > > (i.e. they should not be the names of the outputs from the provider).
> > > > 
> > > > Mark.
> > > > 
> > >      After we check with our SMI Designer. Every SMI local arbiter need
> > > two clocks, which is called  APB clocks and SMI clock.
> > >      APB clock : Advanced Peripheral Bus Clock. It is the clock for
> > > setting the register of local arbiter.
> > >      SMI clock : Smart Multimedia Interface Clock, It is the clock for
> > > transfering the data and command. 
> > > 
> > >      And all the local arbiters need the smi common clock, so we
> > > separate it. 
> > > 
> > >      Then I prepare to design the smi the dtsi like this: 
> > > 
> > >       smi_common:smi@14022000 {
> > >                  compatible = “mediate, mt8173-smi”;
> > >                  reg = <0 0x14022000 0 0x1000>;
> > >                  clocks = <&mmsys MM_SMI_COMMON>;
> > >                  clocks-names = “smi_common”;
> > >       };
> > > 
> > >       larb0: larb@14021000 {
> > >                  compatible = “mediate, mt8173-smi-larb”;
> > >                  reg = <0 0x14021000 0 0x1000>;
> > >                  smi = <&smi_common>;
> > >                  clocks = <&mmsys MM_SMI_LARB0>, 
> > > 		 	<&mmsys MM_SMI_LARB0>;
> > >                  clocks-names = “apb_clk”, “smi_clk”;
> > >      };
> > > 
> > >      larb1: larb@16010000 {
> > >                  compatible = “mediate, mt8173-smi-larb”;
> > >                  reg = <0 0x16010000 0 0x1000>;
> > >                  smi = <&smi_common>;
> > >                  clocks = <&vdecsys VDEC_CKEN>, 
> > > 			 <&mmsys VDEC_LARB_CKEN>;
> > >                  clocks-names = “apb_clk”, “smi_clk”;
> > >       };
> > >       … 
> > >      In some local arbiter, the source clock of the APB clock and the
> > > SMI clock may be the same, like larb0. so the two clocks are the same.
> > > And they may be different in other local arbiteres, like larb1.      
> > > 
> > >      If it is designed like this, is it ok?
> > 
> > That looks pretty good; the clocks and names on the larb nodes seem
> > sensible.
> > 
> > The naming of the "smi_common" clock on the smi_common node looks a bit
> > odd though. Is that really what the clock input is called?
> > 
> > Mark.
>      After check with DE, the smi_common clock also have its APB clock
> and the smi clock(they have the same clock source).
>     And I prepare to delete "_clk" in all the clock-names.
>     So it may be like this:
>          smi_common:smi@14022000 {
>                  compatible = “mediate, mt8173-smi”;
>                   reg = <0 0x14022000 0 0x1000>;
>                   clocks = <&mmsys MM_SMI_COMMON>, 
> 			   <&mmsys MM_SMI_COMMON>;
>                   clocks-names = “apk”,"smi";
>         };
>      How about this?
      Sorry, I wrote wrong, it should be 
      clock-names = “apb”,"smi";
> 
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding
  2015-04-14 13:49         ` Yong Wu
  2015-04-14 13:55           ` Yong Wu
@ 2015-04-14 13:56           ` Mark Rutland
  1 sibling, 0 replies; 55+ messages in thread
From: Mark Rutland @ 2015-04-14 13:56 UTC (permalink / raw)
  To: Yong Wu
  Cc: Rob Herring, Joerg Roedel, Matthias Brugger, Robin Murphy,
	Will Deacon, Daniel Kurtz, Tomasz Figa, Lucas Stach,
	Catalin Marinas, linux-mediatek, Sasha Hauer, srv_heupstream,
	devicetree, linux-kernel, linux-arm-kernel, iommu

> > >       smi_common:smi@14022000 {
> > >                  compatible = “mediate, mt8173-smi”;
> > >                  reg = <0 0x14022000 0 0x1000>;
> > >                  clocks = <&mmsys MM_SMI_COMMON>;
> > >                  clocks-names = “smi_common”;
> > >       };
> > > 
> > >       larb0: larb@14021000 {
> > >                  compatible = “mediate, mt8173-smi-larb”;
> > >                  reg = <0 0x14021000 0 0x1000>;
> > >                  smi = <&smi_common>;
> > >                  clocks = <&mmsys MM_SMI_LARB0>, 
> > > 		 	<&mmsys MM_SMI_LARB0>;
> > >                  clocks-names = “apb_clk”, “smi_clk”;
> > >      };
> > > 
> > >      larb1: larb@16010000 {
> > >                  compatible = “mediate, mt8173-smi-larb”;
> > >                  reg = <0 0x16010000 0 0x1000>;
> > >                  smi = <&smi_common>;
> > >                  clocks = <&vdecsys VDEC_CKEN>, 
> > > 			 <&mmsys VDEC_LARB_CKEN>;
> > >                  clocks-names = “apb_clk”, “smi_clk”;
> > >       };
> > >       … 
> > >      In some local arbiter, the source clock of the APB clock and the
> > > SMI clock may be the same, like larb0. so the two clocks are the same.
> > > And they may be different in other local arbiteres, like larb1.      
> > > 
> > >      If it is designed like this, is it ok?
> > 
> > That looks pretty good; the clocks and names on the larb nodes seem
> > sensible.
> > 
> > The naming of the "smi_common" clock on the smi_common node looks a bit
> > odd though. Is that really what the clock input is called?
> > 
> > Mark.
>      After check with DE, the smi_common clock also have its APB clock
> and the smi clock(they have the same clock source).
>     And I prepare to delete "_clk" in all the clock-names.
>     So it may be like this:
>          smi_common:smi@14022000 {
>                  compatible = “mediate, mt8173-smi”;
>                     reg = <0 0x14022000 0 0x1000>;
>                   clocks = <&mmsys MM_SMI_COMMON>, 
> 			   <&mmsys MM_SMI_COMMON>;
>                   clocks-names = “apk”,"smi";
>         };
>      How about this?

That looks fine to me. I assume "apk" should be "apb" in the last
example.

Mark.

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-04-14  6:31         ` Yong Wu
@ 2015-04-15  2:20           ` Tomasz Figa
  2015-04-15  7:06             ` Yong Wu
  0 siblings, 1 reply; 55+ messages in thread
From: Tomasz Figa @ 2015-04-15  2:20 UTC (permalink / raw)
  To: Yong Wu
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

On Tue, Apr 14, 2015 at 3:31 PM, Yong Wu <yong.wu@mediatek.com> wrote:
>> >>
>> >> > +
>> >> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
>> >>
>> >> style: Operators like * should have space on both sides.
>> >>
>> >> > +                                         GFP_KERNEL);
>> >>
>> >> Shouldn't dma_alloc_coherent() be used for this?
>> >      We don't care the data in it. I think they are the same. Could you
>> > help tell me why dma_alloc_coherent may be better.
>>
>> Can you guarantee that at the time you allocate the memory using
>> devm_kmalloc() the memory is not dirty (i.e. some write back data are
>> stored in CPU cache) and is not going to be written back in some time,
>> overwriting data put there by IOMMU hardware?
>>
> As I noted in the function "mtk_iommu_hw_init":
>
>        /* protect memory,HW will write here while translation fault */
>        protectpa = __virt_to_phys(piommu->protect_va);
>
>      We don’t care the content of this buffer, It is ok even though its
> data is dirty.
>     It seem to be a the protect memory. While a translation fault
> happened, The iommu HW will overwrite here instead of writing to the
> fault physical address which may be 0 or some random address.
>

Do you mean that it's just a dummy page for hardware behind the IOMMU
to access when the mapping is not available? How would that work with
potential on demand paging when the hardware needs to be blocked until
the mapping is created?

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-04-15  2:20           ` Tomasz Figa
@ 2015-04-15  7:06             ` Yong Wu
  2015-04-15  7:41               ` Tomasz Figa
  0 siblings, 1 reply; 55+ messages in thread
From: Yong Wu @ 2015-04-15  7:06 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

On Wed, 2015-04-15 at 11:20 +0900, Tomasz Figa wrote:
> On Tue, Apr 14, 2015 at 3:31 PM, Yong Wu <yong.wu@mediatek.com> wrote:
> >> >>
> >> >> > +
> >> >> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
> >> >>
> >> >> style: Operators like * should have space on both sides.
> >> >>
> >> >> > +                                         GFP_KERNEL);
> >> >>
> >> >> Shouldn't dma_alloc_coherent() be used for this?
> >> >      We don't care the data in it. I think they are the same. Could you
> >> > help tell me why dma_alloc_coherent may be better.
> >>
> >> Can you guarantee that at the time you allocate the memory using
> >> devm_kmalloc() the memory is not dirty (i.e. some write back data are
> >> stored in CPU cache) and is not going to be written back in some time,
> >> overwriting data put there by IOMMU hardware?
> >>
> > As I noted in the function "mtk_iommu_hw_init":
> >
> >        /* protect memory,HW will write here while translation fault */
> >        protectpa = __virt_to_phys(piommu->protect_va);
> >
> >      We don’t care the content of this buffer, It is ok even though its
> > data is dirty.
> >     It seem to be a the protect memory. While a translation fault
> > happened, The iommu HW will overwrite here instead of writing to the
> > fault physical address which may be 0 or some random address.
> >
> 
> Do you mean that it's just a dummy page for hardware behind the IOMMU
> to access when the mapping is not available? How would that work with
> potential on demand paging when the hardware needs to be blocked until
> the mapping is created?
> 
> Best regards,
> Tomasz
 1. YES
 2. Sorry. Our iommu HW can not support this right now. The HW can not
be blocked until the mapping is created.
    If the page is not ready, we can not get the physical address, then
How to fill the pagetable for that memory. I think the dma&iommu may
guaranty it?



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-04-15  7:06             ` Yong Wu
@ 2015-04-15  7:41               ` Tomasz Figa
  0 siblings, 0 replies; 55+ messages in thread
From: Tomasz Figa @ 2015-04-15  7:41 UTC (permalink / raw)
  To: Yong Wu
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

On Wed, Apr 15, 2015 at 4:06 PM, Yong Wu <yong.wu@mediatek.com> wrote:
> On Wed, 2015-04-15 at 11:20 +0900, Tomasz Figa wrote:
>> On Tue, Apr 14, 2015 at 3:31 PM, Yong Wu <yong.wu@mediatek.com> wrote:
>> >> >>
>> >> >> > +
>> >> >> > +       piommu->protect_va = devm_kmalloc(piommu->dev, MTK_PROTECT_PA_ALIGN*2,
>> >> >>
>> >> >> style: Operators like * should have space on both sides.
>> >> >>
>> >> >> > +                                         GFP_KERNEL);
>> >> >>
>> >> >> Shouldn't dma_alloc_coherent() be used for this?
>> >> >      We don't care the data in it. I think they are the same. Could you
>> >> > help tell me why dma_alloc_coherent may be better.
>> >>
>> >> Can you guarantee that at the time you allocate the memory using
>> >> devm_kmalloc() the memory is not dirty (i.e. some write back data are
>> >> stored in CPU cache) and is not going to be written back in some time,
>> >> overwriting data put there by IOMMU hardware?
>> >>
>> > As I noted in the function "mtk_iommu_hw_init":
>> >
>> >        /* protect memory,HW will write here while translation fault */
>> >        protectpa = __virt_to_phys(piommu->protect_va);
>> >
>> >      We don’t care the content of this buffer, It is ok even though its
>> > data is dirty.
>> >     It seem to be a the protect memory. While a translation fault
>> > happened, The iommu HW will overwrite here instead of writing to the
>> > fault physical address which may be 0 or some random address.
>> >
>>
>> Do you mean that it's just a dummy page for hardware behind the IOMMU
>> to access when the mapping is not available? How would that work with
>> potential on demand paging when the hardware needs to be blocked until
>> the mapping is created?
>>
>> Best regards,
>> Tomasz
>  1. YES
>  2. Sorry. Our iommu HW can not support this right now. The HW can not
> be blocked until the mapping is created.

OK, that explains it. Well, then I guess this is necessary and
contents of that memory don't matter that much. (Although, this might
be a minor security issue, because the faulting hardware would get
access to some data previously stored by kernel code. Not sure how
much of a threat would that be, though.)

>     If the page is not ready, we can not get the physical address, then
> How to fill the pagetable for that memory. I think the dma&iommu may
> guaranty it?

If your hardware can't block until the mapping is created then what
you do currently seems to be the only option. (+/- the missing cache
maintenance at initialization)

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver
  2015-03-27  9:41       ` Tomasz Figa
  2015-04-14  6:31         ` Yong Wu
@ 2015-04-29  6:23         ` Yong Wu
  1 sibling, 0 replies; 55+ messages in thread
From: Yong Wu @ 2015-04-29  6:23 UTC (permalink / raw)
  To: Tomasz Figa, Mark Rutland
  Cc: Robin Murphy, Mark Rutland, devicetree, srv_heupstream,
	Catalin Marinas, Joerg Roedel, Will Deacon, linux-kernel, iommu,
	Rob Herring, Daniel Kurtz, Sasha Hauer, Matthias Brugger,
	linux-mediatek, linux-arm-kernel, Lucas Stach

Dear Tomasz,
     About a hardcode your comment, please help check below.

Dear Mark,
      I would like to add a item in the dtsi of mtk-iommu. Please also
help have a look.


> > > +static const struct mtk_iommu_port mtk_iommu_mt8173_port[] = {
> > > +       /* port name                m4uid slaveid larbid portid
tfid */
> > > +       /* larb0 */
> > > +       {"M4U_PORT_DISP_OVL0",          0,  0,    0,  0,
MTK_TFID(0, 0)},
> > > +       {"M4U_PORT_DISP_RDMA0",         0,  0,    0,  1,
MTK_TFID(0, 1)},
> > > +       {"M4U_PORT_DISP_WDMA0",         0,  0,    0,  2,
MTK_TFID(0, 2)},
> > > +       {"M4U_PORT_DISP_OD_R",          0,  0,    0,  3,
MTK_TFID(0, 3)},
> > > +       {"M4U_PORT_DISP_OD_W",          0,  0,    0,  4,
MTK_TFID(0, 4)},
> > > +       {"M4U_PORT_MDP_RDMA0",          0,  0,    0,  5,
MTK_TFID(0, 5)},
> > > +       {"M4U_PORT_MDP_WDMA",           0,  0,    0,  6,
MTK_TFID(0, 6)},
> > > +       {"M4U_PORT_MDP_WROT0",          0,  0,    0,  7,
MTK_TFID(0, 7)},
[...]
> 
> > > +};
> > > +
> > 
> > Anyway, is it really necessary to hardcode the SoC specific topology
> > data in this driver? Is there really any use besides of printing
port
> > name? If not, you could just print the values in a way letting you
> > quickly look up in the datasheet, without hardcoding this. Or even
> > better, you could print which devices are attached to the port.
> > 
> a) Printing the port name is for debug. We could not request every
iommu
> user to understand smi&local arbiter. When there is irq, they have to
> look up the iommu's datasheet to find out which port error. if we
print
> it directly, It may be more easily to debug.
> 
> b) In mtk_iommu_config_port, according to this hardcode we can be
easily
> to get out which local arbiter and which port we prepare to config.
> 
> c) If we support different SOCs, we could change this arrays easily.
> 
> > 
     There is no similar code in the others iommu, so I prepare to
delete it, But we really need know which local arbiter and which port we
are going to config(which port will enable iommu)
        so we prepare add a item in the dtsi like this:

	iommu: mmsys_iommu@10205000 {
			compatible = "mediatek,mt8173-iommu";
			<...>
+			larb-portes-nr = <M4U_LARB0_PORT_NR
+					 M4U_LARB1_PORT_NR
+					 M4U_LARB2_PORT_NR
+					 M4U_LARB3_PORT_NR
+					 M4U_LARB4_PORT_NR
+					 M4U_LARB5_PORT_NR>;
			larb = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
			#iommu-cells = <1>;
		};
	larb-portes-nr : the number of the portes in each local arbiter.
        
	If we have this item, we can get which larb and which port from the
portid in the dtsi of the iommu user.

        And while there is isr, I will print the larb-id and the port-id
instead of the string of the port name.

	The M4U_LARB0_PORT_NR/... will be added in
dt-bindings/iommu/mt8173-iommu-port.h[0]

Dear Mark, 
      As above, if I add this item in the dtsi of iommu, is it ok?


[0]:http://lists.linuxfoundation.org/pipermail/iommu/2015-March/012450.html
 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* [RFC PATCH 0/5] MT8173 IOMMU support
@ 2015-03-06 10:37 yong.wu
  0 siblings, 0 replies; 55+ messages in thread
From: yong.wu @ 2015-03-06 10:37 UTC (permalink / raw)
  To: Rob Herring, Joerg Roedel, Matthias Brugger
  Cc: Robin Murphy, Will Deacon, Daniel Kurtz, Tomasz Figa,
	Lucas Stach, Mark Rutland, Catalin Marinas, linux-mediatek,
	Sasha Hauer, srv_heupstream, devicetree, linux-kernel,
	linux-arm-kernel, iommu

  This is based on Robin Murphy's arm64: IOMMU-backed DMA mapping[1]. 
This patch adds support for m4u(Multimedia Memory Management Unit),
Currently it only support the m4u with 2 levels of page table on mt8173.

  Please check the hardware block diagram of Mediatek IOMMU.

              EMI (External Memory Interface)
               |
              m4u (Multimedia Memory Management Unit)
               |
              smi (Smart Multimedia Interface)
               |
        +---------------+-------
        |               |
        |               |
    vdec larb       disp larb      ... SoCs have different local arbiter(larb).
        |               |
        |               |
   +----+----+    +-----+-----+
   |    |    |    |     |     |    ...
   |    |    |    |     |     |    ...
   |    |    |    |     |     |    ...
  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... 
  
  Normally we specify a local arbiter(larb) for each multimedia hardware like
display, video decode, video encode and camera. And there are different ports in
each larb. Take a example, there are some ports like MC, PP, UFO, VLD, AVC_MV,
PRED_RD, PRED_WR in video larb, all the ports are according to the video hardware.

	From the diagram, all the multimedia module connect with m4u via smi.
SMI is responsible to enable/disable iommu and control the clocks of each local
arbiter. If we should enable the iommu of video decode, it should config the 
video's ports. And if the video hardware work wether enable/disable iommu, 
it should enable the clock of its larb's clock. So we add a special driver for smi.

[1] http://lists.linuxfoundation.org/pipermail/iommu/2015-February/012236.html

Yong Wu (5):
  soc: mediatek: Add SMI driver
  iommu/mediatek: Add mt8173 IOMMU driver
  dt-bindings: mediatek: Add smi dts binding
  dt-bindings: iommu: Add binding for mediatek IOMMU
  dts: mt8173: Add iommu/smi nodes for mt8173

 .../devicetree/bindings/iommu/mediatek,iommu.txt   |  41 ++
 .../bindings/soc/mediatek/mediatek,smi.txt         |  17 +
 arch/arm64/boot/dts/mediatek/mt8173.dtsi           |  60 ++
 drivers/iommu/Kconfig                              |  11 +
 drivers/iommu/Makefile                             |   1 +
 drivers/iommu/mtk_iommu.c                          | 754 +++++++++++++++++++++
 drivers/iommu/mtk_iommu.h                          |  73 ++
 drivers/iommu/mtk_iommu_pagetable.c                | 439 ++++++++++++
 drivers/iommu/mtk_iommu_pagetable.h                |  49 ++
 drivers/soc/mediatek/Kconfig                       |   7 +
 drivers/soc/mediatek/Makefile                      |   1 +
 drivers/soc/mediatek/mt8173-smi.c                  | 143 ++++
 include/dt-bindings/iommu/mt8173-iommu-port.h      | 127 ++++
 include/linux/mtk-smi.h                            |  40 ++
 14 files changed, 1763 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
 create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,smi.txt
 create mode 100644 drivers/iommu/mtk_iommu.c
 create mode 100644 drivers/iommu/mtk_iommu.h
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.c
 create mode 100644 drivers/iommu/mtk_iommu_pagetable.h
 create mode 100644 drivers/soc/mediatek/mt8173-smi.c
 create mode 100644 include/dt-bindings/iommu/mt8173-iommu-port.h
 create mode 100644 include/linux/mtk-smi.h

-- 
1.8.1.1.dirty

G:IT: [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173

^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2015-04-29  6:23 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-06 10:48 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu
2015-03-06 10:48 ` [PATCH 1/5] soc: mediatek: Add SMI driver yong.wu
2015-03-06 11:30   ` Paul Bolle
2015-03-09 11:57     ` Yong Wu
2015-03-09 17:59       ` Paul Bolle
2015-03-09 21:54         ` Arnd Bergmann
2015-03-10  6:17         ` Yingjoe Chen
2015-03-09  3:26   ` Yingjoe Chen
2015-03-09 21:56     ` Arnd Bergmann
2015-03-10  6:27       ` Yingjoe Chen
2015-03-10  9:05         ` Arnd Bergmann
2015-03-10  9:24       ` Lucas Stach
2015-03-09 11:03   ` Sascha Hauer
2015-03-06 10:48 ` [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver yong.wu
2015-03-06 10:58   ` Will Deacon
2015-03-09 12:11     ` Yong Wu
2015-03-17 15:14       ` Will Deacon
2015-03-06 17:15   ` Mitchel Humpherys
2015-03-09 12:16     ` Yong Wu
2015-03-09 16:57       ` Mitchel Humpherys
2015-03-08  4:12   ` Tomasz Figa
2015-03-12 14:16     ` Yong Wu
2015-03-09  8:24   ` Daniel Kurtz
2015-03-09 11:11   ` Tomasz Figa
2015-03-09 14:46     ` Yingjoe Chen
2015-03-09 17:00       ` Tomasz Figa
2015-03-10  3:41         ` Yingjoe Chen
2015-03-10  4:06           ` Tomasz Figa
2015-03-11 10:53   ` Tomasz Figa
2015-03-18 11:22     ` Yong Wu
2015-03-20 19:14       ` Robin Murphy
2015-04-14  6:50         ` Yong Wu
2015-03-27  9:41       ` Tomasz Figa
2015-04-14  6:31         ` Yong Wu
2015-04-15  2:20           ` Tomasz Figa
2015-04-15  7:06             ` Yong Wu
2015-04-15  7:41               ` Tomasz Figa
2015-04-29  6:23         ` Yong Wu
2015-03-06 10:48 ` [PATCH 3/5] dt-bindings: mediatek: Add smi dts binding yong.wu
2015-03-06 11:13   ` Mark Rutland
2015-03-09 12:55     ` Yong Wu
2015-04-14  9:07     ` Yong Wu
2015-04-14 10:06       ` Mark Rutland
2015-04-14 13:49         ` Yong Wu
2015-04-14 13:55           ` Yong Wu
2015-04-14 13:56           ` Mark Rutland
2015-03-06 14:48   ` Sergei Shtylyov
2015-03-09 12:32     ` Yong Wu
2015-03-06 10:48 ` [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU yong.wu
2015-03-06 11:21   ` Mark Rutland
2015-03-09 11:30     ` Yong Wu
2015-03-06 10:48 ` [PATCH 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 yong.wu
2015-03-07 15:20   ` Daniel Kurtz
2015-03-09 12:18     ` Yong Wu
  -- strict thread matches above, loose matches on Subject: below --
2015-03-06 10:37 [RFC PATCH 0/5] MT8173 IOMMU support yong.wu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).