* [PATCH v8 1/5] dt-bindings: iommu: Add binding for mediatek IOMMU
2016-01-26 4:12 [PATCH v8 0/5] MT8173 IOMMU SUPPORT Yong Wu
@ 2016-01-26 4:12 ` Yong Wu
2016-01-26 4:12 ` [PATCH v8 2/5] dt-bindings: mediatek: Add smi dts binding Yong Wu
` (3 subsequent siblings)
4 siblings, 0 replies; 22+ messages in thread
From: Yong Wu @ 2016-01-26 4:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch add mediatek iommu dts binding document.
Signed-off-by: Yong Wu <yong.wu@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/iommu/mediatek,iommu.txt | 68 ++++++++++++++++++++++
1 file changed, 68 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..cd1b1cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
@@ -0,0 +1,68 @@
+* Mediatek IOMMU Architecture Implementation
+
+ Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U) which
+uses the ARM Short-Descriptor translation table format for address translation.
+
+ About the M4U Hardware Block Diagram, please check below:
+
+ EMI (External Memory Interface)
+ |
+ m4u (Multimedia Memory Management Unit)
+ |
+ SMI Common(Smart Multimedia Interface Common)
+ |
+ +----------------+-------
+ | |
+ | |
+ SMI larb0 SMI larb1 ... SoCs have several SMI local arbiter(larb).
+ (display) (vdec)
+ | |
+ | |
+ +-----+-----+ +----+----+
+ | | | | | |
+ | | |... | | | ... There are different ports in each larb.
+ | | | | | |
+OVL0 RDMA0 WDMA0 MC PP VLD
+
+ As above, The Multimedia HW will go through SMI and M4U while it
+access EMI. SMI is a bridge between m4u and the Multimedia HW. It contain
+smi local arbiter and smi common. It will control whether the Multimedia
+HW should go though the m4u for translation or bypass it and talk
+directly with EMI. And also SMI help control the power domain and clocks for
+each local arbiter.
+ Normally we specify a local arbiter(larb) for each multimedia HW
+like display, video decode, and camera. And there are different ports
+in each larb. Take a example, There are many ports like MC, PP, VLD in the
+video decode local arbiter, all these ports are according to the video HW.
+
+Required properties:
+- compatible : must be "mediatek,mt8173-m4u".
+- reg : m4u register base and size.
+- interrupts : the interrupt of m4u.
+- clocks : must contain one entry for each clock-names.
+- clock-names : must be "bclk", It is the block clock of m4u.
+- mediatek,larbs : List of phandle to the local arbiters in the current Socs.
+ Refer to bindings/memory-controllers/mediatek,smi-larb.txt. It must sort
+ according to the local arbiter index, like larb0, larb1, larb2...
+- iommu-cells : must be 1. This is the mtk_m4u_id according to the HW.
+ Specifies the mtk_m4u_id as defined in
+ dt-binding/memory/mt8173-larb-port.h.
+
+Example:
+ iommu: iommu at 10205000 {
+ compatible = "mediatek,mt8173-m4u";
+ reg = <0 0x10205000 0 0x1000>;
+ interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_M4U>;
+ clock-names = "bclk";
+ mediatek,larbs = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>;
+ #iommu-cells = <1>;
+ };
+
+Example for a client device:
+ display {
+ compatible = "mediatek,mt8173-disp";
+ iommus = <&iommu M4U_PORT_DISP_OVL0>,
+ <&iommu M4U_PORT_DISP_RDMA0>;
+ ...
+ };
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v8 2/5] dt-bindings: mediatek: Add smi dts binding
2016-01-26 4:12 [PATCH v8 0/5] MT8173 IOMMU SUPPORT Yong Wu
2016-01-26 4:12 ` [PATCH v8 1/5] dt-bindings: iommu: Add binding for mediatek IOMMU Yong Wu
@ 2016-01-26 4:12 ` Yong Wu
2016-01-26 22:00 ` Rob Herring
2016-01-26 4:12 ` [PATCH v8 3/5] memory: mediatek: Add SMI driver Yong Wu
` (2 subsequent siblings)
4 siblings, 1 reply; 22+ messages in thread
From: Yong Wu @ 2016-01-26 4:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch add smi binding document and smi local arbiter header file.
Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
.../memory-controllers/mediatek,smi-common.txt | 24 +++++
.../memory-controllers/mediatek,smi-larb.txt | 25 +++++
include/dt-bindings/memory/mt8173-larb-port.h | 111 +++++++++++++++++++++
3 files changed, 160 insertions(+)
create mode 100644 Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
create mode 100644 Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
create mode 100644 include/dt-bindings/memory/mt8173-larb-port.h
diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
new file mode 100644
index 0000000..06a83ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
@@ -0,0 +1,24 @@
+SMI (Smart Multimedia Interface) Common
+
+The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
+
+Required properties:
+- compatible : must be "mediatek,mt8173-smi-common"
+- reg : the register and size of the SMI block.
+- power-domains : a phandle to the power domain of this local arbiter.
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : must contain 2 entries, as follows:
+ - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
+ the register.
+ - "smi" : It's the clock for transfer data and command.
+ They may be the same if both source clocks are the same.
+
+Example:
+ smi_common: smi at 14022000 {
+ compatible = "mediatek,mt8173-smi-common";
+ reg = <0 0x14022000 0 0x1000>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+ clocks = <&mmsys CLK_MM_SMI_COMMON>,
+ <&mmsys CLK_MM_SMI_COMMON>;
+ clock-names = "apb", "smi";
+ };
diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
new file mode 100644
index 0000000..55ff3b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
@@ -0,0 +1,25 @@
+SMI (Smart Multimedia Interface) Local Arbiter
+
+The hardware block diagram please check bindings/iommu/mediatek,iommu.txt
+
+Required properties:
+- compatible : must be "mediatek,mt8173-smi-larb"
+- reg : the register and size of this local arbiter.
+- mediatek,smi : a phandle to the smi_common node.
+- power-domains : a phandle to the power domain of this local arbiter.
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names: must contain 2 entries, as follows:
+ - "apb" : Advanced Peripheral Bus clock, It's the clock for setting
+ the register.
+ - "smi" : It's the clock for transfer data and command.
+
+Example:
+ larb1: larb at 16010000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x16010000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
+ clocks = <&vdecsys CLK_VDEC_CKEN>,
+ <&vdecsys CLK_VDEC_LARB_CKEN>;
+ clock-names = "apb", "smi";
+ };
diff --git a/include/dt-bindings/memory/mt8173-larb-port.h b/include/dt-bindings/memory/mt8173-larb-port.h
new file mode 100644
index 0000000..5fef5d1
--- /dev/null
+++ b/include/dt-bindings/memory/mt8173-larb-port.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015-2016 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 MTK_M4U_ID(larb, port) (((larb) << 5) | (port))
+/* Local arbiter ID */
+#define MTK_M4U_TO_LARB(id) (((id) >> 5) & 0x7)
+/* PortID within the local arbiter */
+#define MTK_M4U_TO_PORT(id) ((id) & 0x1f)
+
+#define M4U_LARB0_ID 0
+#define M4U_LARB1_ID 1
+#define M4U_LARB2_ID 2
+#define M4U_LARB3_ID 3
+#define M4U_LARB4_ID 4
+#define M4U_LARB5_ID 5
+
+/* larb0 */
+#define M4U_PORT_DISP_OVL0 MTK_M4U_ID(M4U_LARB0_ID, 0)
+#define M4U_PORT_DISP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 1)
+#define M4U_PORT_DISP_WDMA0 MTK_M4U_ID(M4U_LARB0_ID, 2)
+#define M4U_PORT_DISP_OD_R MTK_M4U_ID(M4U_LARB0_ID, 3)
+#define M4U_PORT_DISP_OD_W MTK_M4U_ID(M4U_LARB0_ID, 4)
+#define M4U_PORT_MDP_RDMA0 MTK_M4U_ID(M4U_LARB0_ID, 5)
+#define M4U_PORT_MDP_WDMA MTK_M4U_ID(M4U_LARB0_ID, 6)
+#define M4U_PORT_MDP_WROT0 MTK_M4U_ID(M4U_LARB0_ID, 7)
+
+/* larb1 */
+#define M4U_PORT_HW_VDEC_MC_EXT MTK_M4U_ID(M4U_LARB1_ID, 0)
+#define M4U_PORT_HW_VDEC_PP_EXT MTK_M4U_ID(M4U_LARB1_ID, 1)
+#define M4U_PORT_HW_VDEC_UFO_EXT MTK_M4U_ID(M4U_LARB1_ID, 2)
+#define M4U_PORT_HW_VDEC_VLD_EXT MTK_M4U_ID(M4U_LARB1_ID, 3)
+#define M4U_PORT_HW_VDEC_VLD2_EXT MTK_M4U_ID(M4U_LARB1_ID, 4)
+#define M4U_PORT_HW_VDEC_AVC_MV_EXT MTK_M4U_ID(M4U_LARB1_ID, 5)
+#define M4U_PORT_HW_VDEC_PRED_RD_EXT MTK_M4U_ID(M4U_LARB1_ID, 6)
+#define M4U_PORT_HW_VDEC_PRED_WR_EXT MTK_M4U_ID(M4U_LARB1_ID, 7)
+#define M4U_PORT_HW_VDEC_PPWRAP_EXT MTK_M4U_ID(M4U_LARB1_ID, 8)
+#define M4U_PORT_HW_VDEC_TILE MTK_M4U_ID(M4U_LARB1_ID, 9)
+
+/* larb2 */
+#define M4U_PORT_IMGO MTK_M4U_ID(M4U_LARB2_ID, 0)
+#define M4U_PORT_RRZO MTK_M4U_ID(M4U_LARB2_ID, 1)
+#define M4U_PORT_AAO MTK_M4U_ID(M4U_LARB2_ID, 2)
+#define M4U_PORT_LCSO MTK_M4U_ID(M4U_LARB2_ID, 3)
+#define M4U_PORT_ESFKO MTK_M4U_ID(M4U_LARB2_ID, 4)
+#define M4U_PORT_IMGO_D MTK_M4U_ID(M4U_LARB2_ID, 5)
+#define M4U_PORT_LSCI MTK_M4U_ID(M4U_LARB2_ID, 6)
+#define M4U_PORT_LSCI_D MTK_M4U_ID(M4U_LARB2_ID, 7)
+#define M4U_PORT_BPCI MTK_M4U_ID(M4U_LARB2_ID, 8)
+#define M4U_PORT_BPCI_D MTK_M4U_ID(M4U_LARB2_ID, 9)
+#define M4U_PORT_UFDI MTK_M4U_ID(M4U_LARB2_ID, 10)
+#define M4U_PORT_IMGI MTK_M4U_ID(M4U_LARB2_ID, 11)
+#define M4U_PORT_IMG2O MTK_M4U_ID(M4U_LARB2_ID, 12)
+#define M4U_PORT_IMG3O MTK_M4U_ID(M4U_LARB2_ID, 13)
+#define M4U_PORT_VIPI MTK_M4U_ID(M4U_LARB2_ID, 14)
+#define M4U_PORT_VIP2I MTK_M4U_ID(M4U_LARB2_ID, 15)
+#define M4U_PORT_VIP3I MTK_M4U_ID(M4U_LARB2_ID, 16)
+#define M4U_PORT_LCEI MTK_M4U_ID(M4U_LARB2_ID, 17)
+#define M4U_PORT_RB MTK_M4U_ID(M4U_LARB2_ID, 18)
+#define M4U_PORT_RP MTK_M4U_ID(M4U_LARB2_ID, 19)
+#define M4U_PORT_WR MTK_M4U_ID(M4U_LARB2_ID, 20)
+
+/* larb3 */
+#define M4U_PORT_VENC_RCPU MTK_M4U_ID(M4U_LARB3_ID, 0)
+#define M4U_PORT_VENC_REC MTK_M4U_ID(M4U_LARB3_ID, 1)
+#define M4U_PORT_VENC_BSDMA MTK_M4U_ID(M4U_LARB3_ID, 2)
+#define M4U_PORT_VENC_SV_COMV MTK_M4U_ID(M4U_LARB3_ID, 3)
+#define M4U_PORT_VENC_RD_COMV MTK_M4U_ID(M4U_LARB3_ID, 4)
+#define M4U_PORT_JPGENC_RDMA MTK_M4U_ID(M4U_LARB3_ID, 5)
+#define M4U_PORT_JPGENC_BSDMA MTK_M4U_ID(M4U_LARB3_ID, 6)
+#define M4U_PORT_JPGDEC_WDMA MTK_M4U_ID(M4U_LARB3_ID, 7)
+#define M4U_PORT_JPGDEC_BSDMA MTK_M4U_ID(M4U_LARB3_ID, 8)
+#define M4U_PORT_VENC_CUR_LUMA MTK_M4U_ID(M4U_LARB3_ID, 9)
+#define M4U_PORT_VENC_CUR_CHROMA MTK_M4U_ID(M4U_LARB3_ID, 10)
+#define M4U_PORT_VENC_REF_LUMA MTK_M4U_ID(M4U_LARB3_ID, 11)
+#define M4U_PORT_VENC_REF_CHROMA MTK_M4U_ID(M4U_LARB3_ID, 12)
+#define M4U_PORT_VENC_NBM_RDMA MTK_M4U_ID(M4U_LARB3_ID, 13)
+#define M4U_PORT_VENC_NBM_WDMA MTK_M4U_ID(M4U_LARB3_ID, 14)
+
+/* larb4 */
+#define M4U_PORT_DISP_OVL1 MTK_M4U_ID(M4U_LARB4_ID, 0)
+#define M4U_PORT_DISP_RDMA1 MTK_M4U_ID(M4U_LARB4_ID, 1)
+#define M4U_PORT_DISP_RDMA2 MTK_M4U_ID(M4U_LARB4_ID, 2)
+#define M4U_PORT_DISP_WDMA1 MTK_M4U_ID(M4U_LARB4_ID, 3)
+#define M4U_PORT_MDP_RDMA1 MTK_M4U_ID(M4U_LARB4_ID, 4)
+#define M4U_PORT_MDP_WROT1 MTK_M4U_ID(M4U_LARB4_ID, 5)
+
+/* larb5 */
+#define M4U_PORT_VENC_RCPU_SET2 MTK_M4U_ID(M4U_LARB5_ID, 0)
+#define M4U_PORT_VENC_REC_FRM_SET2 MTK_M4U_ID(M4U_LARB5_ID, 1)
+#define M4U_PORT_VENC_REF_LUMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 2)
+#define M4U_PORT_VENC_REC_CHROMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 3)
+#define M4U_PORT_VENC_BSDMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 4)
+#define M4U_PORT_VENC_CUR_LUMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 5)
+#define M4U_PORT_VENC_CUR_CHROMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 6)
+#define M4U_PORT_VENC_RD_COMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 7)
+#define M4U_PORT_VENC_SV_COMA_SET2 MTK_M4U_ID(M4U_LARB5_ID, 8)
+
+#endif
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v8 2/5] dt-bindings: mediatek: Add smi dts binding
2016-01-26 4:12 ` [PATCH v8 2/5] dt-bindings: mediatek: Add smi dts binding Yong Wu
@ 2016-01-26 22:00 ` Rob Herring
0 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2016-01-26 22:00 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 26, 2016 at 12:12:39PM +0800, Yong Wu wrote:
> This patch add smi binding document and smi local arbiter header file.
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
> .../memory-controllers/mediatek,smi-common.txt | 24 +++++
> .../memory-controllers/mediatek,smi-larb.txt | 25 +++++
> include/dt-bindings/memory/mt8173-larb-port.h | 111 +++++++++++++++++++++
> 3 files changed, 160 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.txt
> create mode 100644 Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
> create mode 100644 include/dt-bindings/memory/mt8173-larb-port.h
Acked-by: Rob Herring <robh@kernel.org>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-01-26 4:12 [PATCH v8 0/5] MT8173 IOMMU SUPPORT Yong Wu
2016-01-26 4:12 ` [PATCH v8 1/5] dt-bindings: iommu: Add binding for mediatek IOMMU Yong Wu
2016-01-26 4:12 ` [PATCH v8 2/5] dt-bindings: mediatek: Add smi dts binding Yong Wu
@ 2016-01-26 4:12 ` Yong Wu
2016-01-28 12:34 ` Daniel Kurtz
2016-01-31 11:00 ` Matthias Brugger
2016-01-26 4:12 ` [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
2016-01-26 4:12 ` [PATCH v8 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 Yong Wu
4 siblings, 2 replies; 22+ messages in thread
From: Yong Wu @ 2016-01-26 4:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch add SMI(Smart Multimedia Interface) driver. This driver
is responsible to enable/disable iommu and control the power domain
and clocks of each local arbiter.
Signed-off-by: Yong Wu <yong.wu@mediatek.com>
Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
---
drivers/memory/Kconfig | 8 ++
drivers/memory/Makefile | 1 +
drivers/memory/mtk-smi.c | 272 +++++++++++++++++++++++++++++++++++++++++++++
include/soc/mediatek/smi.h | 58 ++++++++++
4 files changed, 339 insertions(+)
create mode 100644 drivers/memory/mtk-smi.c
create mode 100644 include/soc/mediatek/smi.h
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 6f31546..51d5cd2 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -114,6 +114,14 @@ config JZ4780_NEMC
the Ingenic JZ4780. This controller is used to handle external
memory devices such as NAND and SRAM.
+config MTK_SMI
+ bool
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ help
+ This driver is for the Memory Controller module in MediaTek SoCs,
+ mainly help enable/disable iommu and control the power domain and
+ clocks for each local arbiter.
+
source "drivers/memory/tegra/Kconfig"
endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 1c46af5..890bdf4 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o
+obj-$(CONFIG_MTK_SMI) += mtk-smi.o
obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c
new file mode 100644
index 0000000..702f0d2
--- /dev/null
+++ b/drivers/memory/mtk-smi.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2015-2016 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/clk.h>
+#include <linux/component.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <soc/mediatek/smi.h>
+
+#define SMI_LARB_MMU_EN 0xf00
+
+struct mtk_smi {
+ struct device *dev;
+ struct clk *clk_apb, *clk_smi;
+};
+
+struct mtk_smi_larb { /* larb: local arbiter */
+ struct mtk_smi smi;
+ void __iomem *base;
+ struct device *smi_common_dev;
+ u32 *mmu;
+};
+
+static int mtk_smi_enable(const struct mtk_smi *smi)
+{
+ int ret;
+
+ ret = pm_runtime_get_sync(smi->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(smi->clk_apb);
+ if (ret)
+ goto err_put_pm;
+
+ ret = clk_prepare_enable(smi->clk_smi);
+ if (ret)
+ goto err_disable_apb;
+
+ return 0;
+
+err_disable_apb:
+ clk_disable_unprepare(smi->clk_apb);
+err_put_pm:
+ pm_runtime_put_sync(smi->dev);
+ return ret;
+}
+
+static void mtk_smi_disable(const struct mtk_smi *smi)
+{
+ clk_disable_unprepare(smi->clk_smi);
+ clk_disable_unprepare(smi->clk_apb);
+ pm_runtime_put_sync(smi->dev);
+}
+
+int mtk_smi_larb_get(struct device *larbdev)
+{
+ struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+ struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
+ int ret;
+
+ /* Enable the smi-common's power and clocks */
+ ret = mtk_smi_enable(common);
+ if (ret)
+ return ret;
+
+ /* Enable the larb's power and clocks */
+ ret = mtk_smi_enable(&larb->smi);
+ if (ret) {
+ mtk_smi_disable(common);
+ return ret;
+ }
+
+ /* Configure the iommu info for this larb */
+ writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN);
+
+ return 0;
+}
+
+void mtk_smi_larb_put(struct device *larbdev)
+{
+ struct mtk_smi_larb *larb = dev_get_drvdata(larbdev);
+ struct mtk_smi *common = dev_get_drvdata(larb->smi_common_dev);
+
+ /*
+ * Don't de-configure the iommu info for this larb since there may be
+ * several modules in this larb.
+ * The iommu info will be reset after power off.
+ */
+
+ mtk_smi_disable(&larb->smi);
+ mtk_smi_disable(common);
+}
+
+static int
+mtk_smi_larb_bind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_smi_larb *larb = dev_get_drvdata(dev);
+ struct mtk_smi_iommu *smi_iommu = data;
+ unsigned int i;
+
+ for (i = 0; i < smi_iommu->larb_nr; i++) {
+ if (dev == smi_iommu->larb_imu[i].dev) {
+ /* The 'mmu' may be updated in iommu-attach/detach. */
+ larb->mmu = &smi_iommu->larb_imu[i].mmu;
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
+static void
+mtk_smi_larb_unbind(struct device *dev, struct device *master, void *data)
+{
+ /* Do nothing as the iommu is always enabled. */
+}
+
+static const struct component_ops mtk_smi_larb_component_ops = {
+ .bind = mtk_smi_larb_bind,
+ .unbind = mtk_smi_larb_unbind,
+};
+
+static int mtk_smi_larb_probe(struct platform_device *pdev)
+{
+ struct mtk_smi_larb *larb;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct device_node *smi_node;
+ struct platform_device *smi_pdev;
+
+ if (!dev->pm_domain)
+ return -EPROBE_DEFER;
+
+ larb = devm_kzalloc(dev, sizeof(*larb), GFP_KERNEL);
+ if (!larb)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ larb->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(larb->base))
+ return PTR_ERR(larb->base);
+
+ larb->smi.clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(larb->smi.clk_apb))
+ return PTR_ERR(larb->smi.clk_apb);
+
+ larb->smi.clk_smi = devm_clk_get(dev, "smi");
+ if (IS_ERR(larb->smi.clk_smi))
+ return PTR_ERR(larb->smi.clk_smi);
+ larb->smi.dev = dev;
+
+ smi_node = of_parse_phandle(dev->of_node, "mediatek,smi", 0);
+ if (!smi_node)
+ return -EINVAL;
+
+ smi_pdev = of_find_device_by_node(smi_node);
+ of_node_put(smi_node);
+ if (smi_pdev) {
+ larb->smi_common_dev = &smi_pdev->dev;
+ } else {
+ dev_err(dev, "Failed to get the smi_common device\n");
+ return -EINVAL;
+ }
+
+ pm_runtime_enable(dev);
+ platform_set_drvdata(pdev, larb);
+ return component_add(dev, &mtk_smi_larb_component_ops);
+}
+
+static int mtk_smi_larb_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ component_del(&pdev->dev, &mtk_smi_larb_component_ops);
+ return 0;
+}
+
+static const struct of_device_id mtk_smi_larb_of_ids[] = {
+ { .compatible = "mediatek,mt8173-smi-larb",},
+ {}
+};
+
+static struct platform_driver mtk_smi_larb_driver = {
+ .probe = mtk_smi_larb_probe,
+ .remove = mtk_smi_larb_remove,
+ .driver = {
+ .name = "mtk-smi-larb",
+ .of_match_table = mtk_smi_larb_of_ids,
+ }
+};
+
+static int mtk_smi_common_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_smi *common;
+
+ if (!dev->pm_domain)
+ return -EPROBE_DEFER;
+
+ common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
+ if (!common)
+ return -ENOMEM;
+ common->dev = dev;
+
+ common->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(common->clk_apb))
+ return PTR_ERR(common->clk_apb);
+
+ common->clk_smi = devm_clk_get(dev, "smi");
+ if (IS_ERR(common->clk_smi))
+ return PTR_ERR(common->clk_smi);
+
+ pm_runtime_enable(dev);
+ platform_set_drvdata(pdev, common);
+ return 0;
+}
+
+static int mtk_smi_common_remove(struct platform_device *pdev)
+{
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id mtk_smi_common_of_ids[] = {
+ { .compatible = "mediatek,mt8173-smi-common", },
+ {}
+};
+
+static struct platform_driver mtk_smi_common_driver = {
+ .probe = mtk_smi_common_probe,
+ .remove = mtk_smi_common_remove,
+ .driver = {
+ .name = "mtk-smi-common",
+ .of_match_table = mtk_smi_common_of_ids,
+ }
+};
+
+static int __init mtk_smi_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&mtk_smi_common_driver);
+ if (ret != 0) {
+ pr_err("Failed to register SMI driver\n");
+ return ret;
+ }
+
+ ret = platform_driver_register(&mtk_smi_larb_driver);
+ if (ret != 0) {
+ pr_err("Failed to register SMI-LARB driver\n");
+ goto err_unreg_smi;
+ }
+ return ret;
+
+err_unreg_smi:
+ platform_driver_unregister(&mtk_smi_common_driver);
+ return ret;
+}
+subsys_initcall(mtk_smi_init);
diff --git a/include/soc/mediatek/smi.h b/include/soc/mediatek/smi.h
new file mode 100644
index 0000000..8893c5e
--- /dev/null
+++ b/include/soc/mediatek/smi.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2016 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/bitops.h>
+#include <linux/device.h>
+
+#ifdef CONFIG_MTK_SMI
+
+#define MTK_LARB_NR_MAX 8
+
+#define MTK_SMI_MMU_EN(port) BIT(port)
+
+struct mtk_smi_larb_iommu {
+ struct device *dev;
+ unsigned int mmu;
+};
+
+struct mtk_smi_iommu {
+ unsigned int larb_nr;
+ struct mtk_smi_larb_iommu larb_imu[MTK_LARB_NR_MAX];
+};
+
+/*
+ * mtk_smi_larb_get: Enable the power domain and clocks for this local arbiter.
+ * It also initialize some basic setting(like iommu).
+ * mtk_smi_larb_put: Disable the power domain and clocks for this local arbiter.
+ * Both should be called in non-atomic context.
+ *
+ * Returns 0 if successful, negative on failure.
+ */
+int mtk_smi_larb_get(struct device *larbdev);
+void mtk_smi_larb_put(struct device *larbdev);
+
+#else
+
+static inline int mtk_smi_larb_get(struct device *larbdev)
+{
+ return 0;
+}
+
+static inline void mtk_smi_larb_put(struct device *larbdev) { }
+
+#endif
+
+#endif
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-01-26 4:12 ` [PATCH v8 3/5] memory: mediatek: Add SMI driver Yong Wu
@ 2016-01-28 12:34 ` Daniel Kurtz
2016-01-31 11:00 ` Matthias Brugger
1 sibling, 0 replies; 22+ messages in thread
From: Daniel Kurtz @ 2016-01-28 12:34 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Jan 26, 2016 at 12:12 PM, Yong Wu <yong.wu@mediatek.com> wrote:
> This patch add SMI(Smart Multimedia Interface) driver. This driver
> is responsible to enable/disable iommu and control the power domain
> and clocks of each local arbiter.
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Daniel Kurtz <djkurtz@chromium.org>
Tested-by: Daniel Kurtz <djkurtz@chromium.org>
Thanks!
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-01-26 4:12 ` [PATCH v8 3/5] memory: mediatek: Add SMI driver Yong Wu
2016-01-28 12:34 ` Daniel Kurtz
@ 2016-01-31 11:00 ` Matthias Brugger
2016-01-31 15:40 ` Philipp Zabel
2016-02-16 14:11 ` Joerg Roedel
1 sibling, 2 replies; 22+ messages in thread
From: Matthias Brugger @ 2016-01-31 11:00 UTC (permalink / raw)
To: linux-arm-kernel
On 26/01/16 05:12, Yong Wu wrote:
> This patch add SMI(Smart Multimedia Interface) driver. This driver
> is responsible to enable/disable iommu and control the power domain
> and clocks of each local arbiter.
>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
Joerg would you mind to take this through your branch?
Thanks,
Matthias
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-01-31 11:00 ` Matthias Brugger
@ 2016-01-31 15:40 ` Philipp Zabel
2016-02-16 14:11 ` Joerg Roedel
1 sibling, 0 replies; 22+ messages in thread
From: Philipp Zabel @ 2016-01-31 15:40 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
>
>
> On 26/01/16 05:12, Yong Wu wrote:
> >This patch add SMI(Smart Multimedia Interface) driver. This driver
> >is responsible to enable/disable iommu and control the power domain
> >and clocks of each local arbiter.
> >
> >Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> >Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> >---
>
> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
>
> Joerg would you mind to take this through your branch?
Could you put it on a separate branch that I may also merge into the DRM
driver pull request?
regards
Philipp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-01-31 11:00 ` Matthias Brugger
2016-01-31 15:40 ` Philipp Zabel
@ 2016-02-16 14:11 ` Joerg Roedel
2016-02-16 15:32 ` Robin Murphy
2016-02-17 17:52 ` Yong Wu
1 sibling, 2 replies; 22+ messages in thread
From: Joerg Roedel @ 2016-02-16 14:11 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
>
>
> On 26/01/16 05:12, Yong Wu wrote:
> >This patch add SMI(Smart Multimedia Interface) driver. This driver
> >is responsible to enable/disable iommu and control the power domain
> >and clocks of each local arbiter.
> >
> >Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> >Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> >---
>
> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
>
> Joerg would you mind to take this through your branch?
Hmm, I somehow missed the patch-set, at least I can't find the v8
patches in my inbox.
Yong, can you please re-send with all Acks and other tags added?
Thanks,
Joerg
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 14:11 ` Joerg Roedel
@ 2016-02-16 15:32 ` Robin Murphy
2016-02-16 16:10 ` Joerg Roedel
2016-02-17 17:52 ` Yong Wu
1 sibling, 1 reply; 22+ messages in thread
From: Robin Murphy @ 2016-02-16 15:32 UTC (permalink / raw)
To: linux-arm-kernel
Hi Joerg,
On 16/02/16 14:11, Joerg Roedel wrote:
> On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
>>
>>
>> On 26/01/16 05:12, Yong Wu wrote:
>>> This patch add SMI(Smart Multimedia Interface) driver. This driver
>>> is responsible to enable/disable iommu and control the power domain
>>> and clocks of each local arbiter.
>>>
>>> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
>>> Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
>>> ---
>>
>> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
>>
>> Joerg would you mind to take this through your branch?
>
> Hmm, I somehow missed the patch-set, at least I can't find the v8
> patches in my inbox.
>
> Yong, can you please re-send with all Acks and other tags added?
Just to note patch 4 of this series also depends on the v3 io-pgtable
short-descriptor series posted separately[1] - is that on your radar
already or would you like that resent as well?
Robin.
[1]:http://thread.gmane.org/gmane.linux.kernel.iommu/12007
>
>
> Thanks,
>
> Joerg
>
> _______________________________________________
> iommu mailing list
> iommu at lists.linux-foundation.org
> https://lists.linuxfoundation.org/mailman/listinfo/iommu
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 15:32 ` Robin Murphy
@ 2016-02-16 16:10 ` Joerg Roedel
2016-02-16 16:20 ` Will Deacon
0 siblings, 1 reply; 22+ messages in thread
From: Joerg Roedel @ 2016-02-16 16:10 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 16, 2016 at 03:32:11PM +0000, Robin Murphy wrote:
> Hi Joerg,
>
> On 16/02/16 14:11, Joerg Roedel wrote:
> >On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
> >>
> >>
> >>On 26/01/16 05:12, Yong Wu wrote:
> >>>This patch add SMI(Smart Multimedia Interface) driver. This driver
> >>>is responsible to enable/disable iommu and control the power domain
> >>>and clocks of each local arbiter.
> >>>
> >>>Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> >>>Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> >>>---
> >>
> >>Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> >>
> >>Joerg would you mind to take this through your branch?
> >
> >Hmm, I somehow missed the patch-set, at least I can't find the v8
> >patches in my inbox.
> >
> >Yong, can you please re-send with all Acks and other tags added?
>
> Just to note patch 4 of this series also depends on the v3
> io-pgtable short-descriptor series posted separately[1] - is that on
> your radar already or would you like that resent as well?
No, that was not on my radar, I somehow expected Will to handle this
series :)
So please resend that as well.
Thanks,
Joerg
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 16:10 ` Joerg Roedel
@ 2016-02-16 16:20 ` Will Deacon
2016-02-16 16:26 ` Joerg Roedel
0 siblings, 1 reply; 22+ messages in thread
From: Will Deacon @ 2016-02-16 16:20 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 16, 2016 at 05:10:09PM +0100, Joerg Roedel wrote:
> On Tue, Feb 16, 2016 at 03:32:11PM +0000, Robin Murphy wrote:
> > On 16/02/16 14:11, Joerg Roedel wrote:
> > >On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
> > >>On 26/01/16 05:12, Yong Wu wrote:
> > >>>This patch add SMI(Smart Multimedia Interface) driver. This driver
> > >>>is responsible to enable/disable iommu and control the power domain
> > >>>and clocks of each local arbiter.
> > >>>
> > >>>Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > >>>Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> > >>>---
> > >>
> > >>Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> > >>
> > >>Joerg would you mind to take this through your branch?
> > >
> > >Hmm, I somehow missed the patch-set, at least I can't find the v8
> > >patches in my inbox.
> > >
> > >Yong, can you please re-send with all Acks and other tags added?
> >
> > Just to note patch 4 of this series also depends on the v3
> > io-pgtable short-descriptor series posted separately[1] - is that on
> > your radar already or would you like that resent as well?
>
> No, that was not on my radar, I somehow expected Will to handle this
> series :)
I'm more than happy to bake a branch containing all the page table stuff,
but Yong's stuff depends on it so I'll work with whatever is easiest for
you.
Will
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 16:20 ` Will Deacon
@ 2016-02-16 16:26 ` Joerg Roedel
2016-02-16 16:28 ` Will Deacon
2016-02-18 16:50 ` Philipp Zabel
0 siblings, 2 replies; 22+ messages in thread
From: Joerg Roedel @ 2016-02-16 16:26 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 16, 2016 at 04:20:00PM +0000, Will Deacon wrote:
> I'm more than happy to bake a branch containing all the page table stuff,
> but Yong's stuff depends on it so I'll work with whatever is easiest for
> you.
Okay, to the best is if you would collect all the page table patches and
send me a pull-request. I pull that into my tree then and put Yong's
stuff on-top.
Joerg
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 16:26 ` Joerg Roedel
@ 2016-02-16 16:28 ` Will Deacon
2016-02-18 16:50 ` Philipp Zabel
1 sibling, 0 replies; 22+ messages in thread
From: Will Deacon @ 2016-02-16 16:28 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 16, 2016 at 05:26:41PM +0100, Joerg Roedel wrote:
> On Tue, Feb 16, 2016 at 04:20:00PM +0000, Will Deacon wrote:
> > I'm more than happy to bake a branch containing all the page table stuff,
> > but Yong's stuff depends on it so I'll work with whatever is easiest for
> > you.
>
> Okay, to the best is if you would collect all the page table patches and
> send me a pull-request. I pull that into my tree then and put Yong's
> stuff on-top.
Okey doke, I'll put something together this week.
Cheers,
Will
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 16:26 ` Joerg Roedel
2016-02-16 16:28 ` Will Deacon
@ 2016-02-18 16:50 ` Philipp Zabel
1 sibling, 0 replies; 22+ messages in thread
From: Philipp Zabel @ 2016-02-18 16:50 UTC (permalink / raw)
To: linux-arm-kernel
Hi Joerg,
Am Dienstag, den 16.02.2016, 17:26 +0100 schrieb Joerg Roedel:
> On Tue, Feb 16, 2016 at 04:20:00PM +0000, Will Deacon wrote:
> > I'm more than happy to bake a branch containing all the page table stuff,
> > but Yong's stuff depends on it so I'll work with whatever is easiest for
> > you.
>
> Okay, to the best is if you would collect all the page table patches and
> send me a pull-request. I pull that into my tree then and put Yong's
> stuff on-top.
could you provide a branch that I may then pull in, stack the
mediatek-drm driver patches (that depend on the SMI driver) on top and
have them merged via drm-next?
regards
Philipp
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 3/5] memory: mediatek: Add SMI driver
2016-02-16 14:11 ` Joerg Roedel
2016-02-16 15:32 ` Robin Murphy
@ 2016-02-17 17:52 ` Yong Wu
1 sibling, 0 replies; 22+ messages in thread
From: Yong Wu @ 2016-02-17 17:52 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, 2016-02-16 at 15:11 +0100, Joerg Roedel wrote:
> On Sun, Jan 31, 2016 at 12:00:41PM +0100, Matthias Brugger wrote:
> >
> >
> > On 26/01/16 05:12, Yong Wu wrote:
> > >This patch add SMI(Smart Multimedia Interface) driver. This driver
> > >is responsible to enable/disable iommu and control the power domain
> > >and clocks of each local arbiter.
> > >
> > >Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> > >Tested-by: Philipp Zabel <p.zabel@pengutronix.de>
> > >---
> >
> > Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> >
> > Joerg would you mind to take this through your branch?
>
> Hmm, I somehow missed the patch-set, at least I can't find the v8
> patches in my inbox.
>
> Yong, can you please re-send with all Acks and other tags added?
Hi Joerg,
I have re-sent v9[1] which has added all the tags yesterday.
Could you find them in your inbox? If not again, please tell me.
Thanks.
[1]:http://lists.linuxfoundation.org/pipermail/iommu/2016-February/015713.html
>
>
> Thanks,
>
> Joerg
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver
2016-01-26 4:12 [PATCH v8 0/5] MT8173 IOMMU SUPPORT Yong Wu
` (2 preceding siblings ...)
2016-01-26 4:12 ` [PATCH v8 3/5] memory: mediatek: Add SMI driver Yong Wu
@ 2016-01-26 4:12 ` Yong Wu
2016-01-26 15:29 ` kbuild test robot
` (2 more replies)
2016-01-26 4:12 ` [PATCH v8 5/5] dts: mt8173: Add iommu/smi nodes for mt8173 Yong Wu
4 siblings, 3 replies; 22+ messages in thread
From: Yong Wu @ 2016-01-26 4:12 UTC (permalink / raw)
To: linux-arm-kernel
This patch adds support for mediatek m4u (MultiMedia Memory Management
Unit).
Signed-off-by: Yong Wu <yong.wu@mediatek.com>
---
drivers/iommu/Kconfig | 16 +
drivers/iommu/Makefile | 1 +
drivers/iommu/mtk_iommu.c | 732 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 749 insertions(+)
create mode 100644 drivers/iommu/mtk_iommu.c
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index a1e75cb..4922aa8 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -318,4 +318,20 @@ config S390_IOMMU
help
Support for the IOMMU API for s390 PCI devices.
+config MTK_IOMMU
+ bool "MTK IOMMU Support"
+ depends on ARM || ARM64
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select IOMMU_API
+ select IOMMU_DMA
+ select IOMMU_IO_PGTABLE_ARMV7S
+ select MEMORY
+ select MTK_SMI
+ help
+ Support for the M4U on certain Mediatek SOCs. M4U is MultiMedia
+ Memory Management Unit. This option enables remapping of DMA memory
+ accesses for the multimedia subsystem.
+
+ If unsure, say N here.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 42fc0c2..44ae2e0 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o
obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
+obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
new file mode 100644
index 0000000..60fe97b
--- /dev/null
+++ b/drivers/iommu/mtk_iommu.c
@@ -0,0 +1,732 @@
+/*
+ * Copyright (c) 2015-2016 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/clk.h>
+#include <linux/component.h>
+#include <linux/dma-iommu.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_iommu.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <soc/mediatek/smi.h>
+#include <dt-bindings/memory/mt8173-larb-port.h>
+
+#include "io-pgtable.h"
+
+#define REG_MMU_PT_BASE_ADDR 0x000
+
+#define REG_MMU_INVALIDATE 0x020
+#define F_ALL_INVLD 0x2
+#define F_MMU_INV_RANGE 0x1
+
+#define REG_MMU_INVLD_START_A 0x024
+#define REG_MMU_INVLD_END_A 0x028
+
+#define REG_MMU_INV_SEL 0x038
+#define F_INVLD_EN0 BIT(0)
+#define F_INVLD_EN1 BIT(1)
+
+#define REG_MMU_STANDARD_AXI_MODE 0x048
+#define REG_MMU_DCM_DIS 0x050
+
+#define REG_MMU_CTRL_REG 0x110
+#define F_MMU_PREFETCH_RT_REPLACE_MOD BIT(4)
+#define F_MMU_TF_PROTECT_SEL(prot) (((prot) & 0x3) << 5)
+
+#define REG_MMU_IVRP_PADDR 0x114
+#define F_MMU_IVRP_PA_SET(pa) ((pa) >> 1)
+
+#define REG_MMU_INT_CONTROL0 0x120
+#define F_L2_MULIT_HIT_EN BIT(0)
+#define F_TABLE_WALK_FAULT_INT_EN BIT(1)
+#define F_PREETCH_FIFO_OVERFLOW_INT_EN BIT(2)
+#define F_MISS_FIFO_OVERFLOW_INT_EN BIT(3)
+#define F_PREFETCH_FIFO_ERR_INT_EN BIT(5)
+#define F_MISS_FIFO_ERR_INT_EN BIT(6)
+#define F_INT_CLR_BIT BIT(12)
+
+#define REG_MMU_INT_MAIN_CONTROL 0x124
+#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_MISS_TRANSACTION_FIFO_FAULT BIT(5)
+#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT BIT(6)
+
+#define REG_MMU_CPE_DONE 0x12C
+
+#define REG_MMU_FAULT_ST1 0x134
+
+#define REG_MMU_FAULT_VA 0x13c
+#define F_MMU_FAULT_VA_MSK 0xfffff000
+#define F_MMU_FAULT_VA_WRITE_BIT BIT(1)
+#define F_MMU_FAULT_VA_LAYER_BIT BIT(0)
+
+#define REG_MMU_INVLD_PA 0x140
+#define REG_MMU_INT_ID 0x150
+#define F_MMU0_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7)
+#define F_MMU0_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f)
+
+#define MTK_PROTECT_PA_ALIGN 128
+
+struct mtk_iommu_suspend_reg {
+ u32 standard_axi_mode;
+ u32 dcm_dis;
+ u32 ctrl_reg;
+ u32 int_control0;
+ u32 int_main_control;
+};
+
+struct mtk_iommu_client_priv {
+ struct list_head client;
+ unsigned int mtk_m4u_id;
+ struct device *m4udev;
+};
+
+struct mtk_iommu_domain {
+ spinlock_t pgtlock; /* lock for page table */
+
+ struct io_pgtable_cfg cfg;
+ struct io_pgtable_ops *iop;
+
+ struct iommu_domain domain;
+};
+
+struct mtk_iommu_data {
+ void __iomem *base;
+ int irq;
+ struct device *dev;
+ struct clk *bclk;
+ phys_addr_t protect_base; /* protect memory base */
+ struct mtk_iommu_suspend_reg reg;
+ struct mtk_iommu_domain *m4u_dom;
+ struct iommu_group *m4u_group;
+ struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */
+};
+
+static struct iommu_ops mtk_iommu_ops;
+
+static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
+{
+ return container_of(dom, struct mtk_iommu_domain, domain);
+}
+
+static void mtk_iommu_tlb_flush_all(void *cookie)
+{
+ struct mtk_iommu_data *data = cookie;
+
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, data->base + REG_MMU_INV_SEL);
+ writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
+ wmb(); /* Make sure the tlb flush all done */
+}
+
+static void mtk_iommu_tlb_add_flush_nosync(unsigned long iova, size_t size,
+ size_t granule, bool leaf,
+ void *cookie)
+{
+ struct mtk_iommu_data *data = cookie;
+
+ writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, data->base + REG_MMU_INV_SEL);
+
+ writel_relaxed(iova, data->base + REG_MMU_INVLD_START_A);
+ writel_relaxed(iova + size - 1, data->base + REG_MMU_INVLD_END_A);
+ writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
+}
+
+static void mtk_iommu_tlb_sync(void *cookie)
+{
+ struct mtk_iommu_data *data = cookie;
+ int ret;
+ u32 tmp;
+
+ ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE, tmp,
+ tmp != 0, 10, 100000);
+ if (ret) {
+ dev_warn(data->dev,
+ "Partial TLB flush timed out, falling back to full flush\n");
+ mtk_iommu_tlb_flush_all(cookie);
+ }
+ /* Clear the CPE status */
+ writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
+}
+
+static const struct iommu_gather_ops mtk_iommu_gather_ops = {
+ .tlb_flush_all = mtk_iommu_tlb_flush_all,
+ .tlb_add_flush = mtk_iommu_tlb_add_flush_nosync,
+ .tlb_sync = mtk_iommu_tlb_sync,
+};
+
+static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
+{
+ struct mtk_iommu_data *data = dev_id;
+ struct mtk_iommu_domain *dom = data->m4u_dom;
+ u32 int_state, regval, fault_iova, fault_pa;
+ unsigned int fault_larb, fault_port;
+ bool layer, write;
+
+ /* Read error info from registers */
+ int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1);
+ fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
+ layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT;
+ write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
+ fault_iova &= F_MMU_FAULT_VA_MSK;
+ fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
+ regval = readl_relaxed(data->base + REG_MMU_INT_ID);
+ fault_larb = F_MMU0_INT_ID_LARB_ID(regval);
+ fault_port = F_MMU0_INT_ID_PORT_ID(regval);
+
+ if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
+ write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
+ dev_err_ratelimited(
+ data->dev,
+ "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d layer=%d %s\n",
+ int_state, fault_iova, fault_pa, fault_larb, fault_port,
+ layer, write ? "write" : "read");
+ }
+
+ /* Interrupt clear */
+ regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL0);
+ regval |= F_INT_CLR_BIT;
+ writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
+
+ mtk_iommu_tlb_flush_all(data);
+
+ return IRQ_HANDLED;
+}
+
+static void mtk_iommu_config(struct mtk_iommu_data *data,
+ struct device *dev, bool enable)
+{
+ struct mtk_iommu_client_priv *head, *cur, *next;
+ struct mtk_smi_larb_iommu *larb_mmu;
+ unsigned int larbid, portid;
+
+ head = dev->archdata.iommu;
+ list_for_each_entry_safe(cur, next, &head->client, client) {
+ larbid = MTK_M4U_TO_LARB(cur->mtk_m4u_id);
+ portid = MTK_M4U_TO_PORT(cur->mtk_m4u_id);
+ larb_mmu = &data->smi_imu.larb_imu[larbid];
+
+ dev_dbg(dev, "%s iommu port: %d\n",
+ enable ? "enable" : "disable", portid);
+
+ if (enable)
+ larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
+ else
+ larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
+ }
+}
+
+static int mtk_iommu_domain_finalise(struct mtk_iommu_data *data)
+{
+ struct mtk_iommu_domain *dom = data->m4u_dom;
+
+ spin_lock_init(&dom->pgtlock);
+
+ dom->cfg = (struct io_pgtable_cfg) {
+ .quirks = IO_PGTABLE_QUIRK_ARM_NS |
+ IO_PGTABLE_QUIRK_NO_PERMS |
+ IO_PGTABLE_QUIRK_TLBI_ON_MAP,
+ .pgsize_bitmap = mtk_iommu_ops.pgsize_bitmap,
+ .ias = 32,
+ .oas = 32,
+ .tlb = &mtk_iommu_gather_ops,
+ .iommu_dev = data->dev,
+ };
+
+ dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
+ if (!dom->iop) {
+ dev_err(data->dev, "Failed to alloc io pgtable\n");
+ return -EINVAL;
+ }
+
+ /* Update our support page sizes bitmap */
+ mtk_iommu_ops.pgsize_bitmap = dom->cfg.pgsize_bitmap;
+
+ writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
+ data->base + REG_MMU_PT_BASE_ADDR);
+ return 0;
+}
+
+static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type)
+{
+ struct mtk_iommu_domain *dom;
+
+ if (type != IOMMU_DOMAIN_DMA)
+ return NULL;
+
+ dom = kzalloc(sizeof(*dom), GFP_KERNEL);
+ if (!dom)
+ return NULL;
+
+ if (iommu_get_dma_cookie(&dom->domain)) {
+ kfree(dom);
+ return NULL;
+ }
+
+ dom->domain.geometry.aperture_start = 0;
+ dom->domain.geometry.aperture_end = DMA_BIT_MASK(32);
+ dom->domain.geometry.force_aperture = true;
+
+ return &dom->domain;
+}
+
+static void mtk_iommu_domain_free(struct iommu_domain *domain)
+{
+ iommu_put_dma_cookie(domain);
+ kfree(to_mtk_domain(domain));
+}
+
+static int mtk_iommu_attach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct mtk_iommu_domain *dom = to_mtk_domain(domain);
+ struct mtk_iommu_client_priv *priv = dev->archdata.iommu;
+ struct mtk_iommu_data *data;
+ int ret;
+
+ if (!priv)
+ return -ENODEV;
+
+ data = dev_get_drvdata(priv->m4udev);
+ if (!data->m4u_dom) {
+ data->m4u_dom = dom;
+ ret = mtk_iommu_domain_finalise(data);
+ if (ret) {
+ data->m4u_dom = NULL;
+ return ret;
+ }
+ } else if (data->m4u_dom != dom) {
+ /* All the client devices should be in the same m4u domain */
+ dev_err(dev, "try to attach into the error iommu domain\n");
+ return -EPERM;
+ }
+
+ mtk_iommu_config(data, dev, true);
+ return 0;
+}
+
+static void mtk_iommu_detach_device(struct iommu_domain *domain,
+ struct device *dev)
+{
+ struct mtk_iommu_client_priv *priv = dev->archdata.iommu;
+ struct mtk_iommu_data *data;
+
+ if (!priv)
+ return;
+
+ data = dev_get_drvdata(priv->m4udev);
+ mtk_iommu_config(data, dev, false);
+}
+
+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 *dom = to_mtk_domain(domain);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&dom->pgtlock, flags);
+ ret = dom->iop->map(dom->iop, iova, paddr, size, prot);
+ spin_unlock_irqrestore(&dom->pgtlock, flags);
+
+ return ret;
+}
+
+static size_t mtk_iommu_unmap(struct iommu_domain *domain,
+ unsigned long iova, size_t size)
+{
+ struct mtk_iommu_domain *dom = to_mtk_domain(domain);
+ unsigned long flags;
+ size_t unmapsz;
+
+ spin_lock_irqsave(&dom->pgtlock, flags);
+ unmapsz = dom->iop->unmap(dom->iop, iova, size);
+ spin_unlock_irqrestore(&dom->pgtlock, flags);
+
+ return unmapsz;
+}
+
+static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ struct mtk_iommu_domain *dom = to_mtk_domain(domain);
+ unsigned long flags;
+ phys_addr_t pa;
+
+ spin_lock_irqsave(&dom->pgtlock, flags);
+ pa = dom->iop->iova_to_phys(dom->iop, iova);
+ spin_unlock_irqrestore(&dom->pgtlock, flags);
+
+ return pa;
+}
+
+static int mtk_iommu_add_device(struct device *dev)
+{
+ struct iommu_group *group;
+
+ if (!dev->archdata.iommu) /* Not a iommu client device */
+ return -ENODEV;
+
+ group = iommu_group_get_for_dev(dev);
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+
+ iommu_group_put(group);
+ return 0;
+}
+
+static void mtk_iommu_remove_device(struct device *dev)
+{
+ struct mtk_iommu_client_priv *head, *cur, *next;
+
+ head = dev->archdata.iommu;
+ if (!head)
+ return;
+
+ list_for_each_entry_safe(cur, next, &head->client, client) {
+ list_del(&cur->client);
+ kfree(cur);
+ }
+ kfree(head);
+ dev->archdata.iommu = NULL;
+
+ iommu_group_remove_device(dev);
+}
+
+static struct iommu_group *mtk_iommu_device_group(struct device *dev)
+{
+ struct mtk_iommu_data *data;
+ struct mtk_iommu_client_priv *priv;
+
+ priv = dev->archdata.iommu;
+ if (!priv)
+ return ERR_PTR(-ENODEV);
+
+ /* All the client devices are in the same m4u iommu-group */
+ data = dev_get_drvdata(priv->m4udev);
+ if (!data->m4u_group) {
+ data->m4u_group = iommu_group_alloc();
+ if (IS_ERR(data->m4u_group))
+ dev_err(dev, "Failed to allocate M4U IOMMU group\n");
+ }
+ return data->m4u_group;
+}
+
+static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+ struct mtk_iommu_client_priv *head, *priv, *next;
+ struct platform_device *m4updev;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid #iommu-cells(%d) property for IOMMU\n",
+ args->args_count);
+ return -EINVAL;
+ }
+
+ if (!dev->archdata.iommu) {
+ /* Get the m4u device */
+ m4updev = of_find_device_by_node(args->np);
+ of_node_put(args->np);
+ if (WARN_ON(!m4updev))
+ return -EINVAL;
+
+ head = kzalloc(sizeof(*head), GFP_KERNEL);
+ if (!head)
+ return -ENOMEM;
+
+ dev->archdata.iommu = head;
+ INIT_LIST_HEAD(&head->client);
+ head->m4udev = &m4updev->dev;
+ } else {
+ head = dev->archdata.iommu;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ goto err_free_mem;
+
+ priv->mtk_m4u_id = args->args[0];
+ list_add_tail(&priv->client, &head->client);
+
+ return 0;
+
+err_free_mem:
+ list_for_each_entry_safe(priv, next, &head->client, client)
+ kfree(priv);
+ kfree(head);
+ dev->archdata.iommu = NULL;
+ return -ENOMEM;
+}
+
+static struct iommu_ops mtk_iommu_ops = {
+ .domain_alloc = mtk_iommu_domain_alloc,
+ .domain_free = mtk_iommu_domain_free,
+ .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,
+ .add_device = mtk_iommu_add_device,
+ .remove_device = mtk_iommu_remove_device,
+ .device_group = mtk_iommu_device_group,
+ .of_xlate = mtk_iommu_of_xlate,
+ .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
+};
+
+static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
+{
+ u32 regval;
+ int ret;
+
+ ret = clk_prepare_enable(data->bclk);
+ if (ret) {
+ dev_err(data->dev, "Failed to enable iommu bclk(%d)\n", ret);
+ return ret;
+ }
+
+ regval = F_MMU_PREFETCH_RT_REPLACE_MOD |
+ F_MMU_TF_PROTECT_SEL(2);
+ writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
+
+ regval = F_L2_MULIT_HIT_EN |
+ F_TABLE_WALK_FAULT_INT_EN |
+ F_PREETCH_FIFO_OVERFLOW_INT_EN |
+ F_MISS_FIFO_OVERFLOW_INT_EN |
+ F_PREFETCH_FIFO_ERR_INT_EN |
+ F_MISS_FIFO_ERR_INT_EN;
+ writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
+
+ regval = F_INT_TRANSLATION_FAULT |
+ F_INT_MAIN_MULTI_HIT_FAULT |
+ F_INT_INVALID_PA_FAULT |
+ F_INT_ENTRY_REPLACEMENT_FAULT |
+ F_INT_TLB_MISS_FAULT |
+ F_INT_MISS_TRANSACTION_FIFO_FAULT |
+ F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
+ writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
+
+ writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base),
+ data->base + REG_MMU_IVRP_PADDR);
+
+ writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
+ writel_relaxed(0, data->base + REG_MMU_STANDARD_AXI_MODE);
+
+ if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0,
+ dev_name(data->dev), (void *)data)) {
+ writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
+ clk_disable_unprepare(data->bclk);
+ dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int mtk_iommu_bind(struct device *dev)
+{
+ struct mtk_iommu_data *data = dev_get_drvdata(dev);
+
+ return component_bind_all(dev, &data->smi_imu);
+}
+
+static void mtk_iommu_unbind(struct device *dev)
+{
+ struct mtk_iommu_data *data = dev_get_drvdata(dev);
+
+ component_unbind_all(dev, &data->smi_imu);
+}
+
+static const struct component_master_ops mtk_iommu_com_ops = {
+ .bind = mtk_iommu_bind,
+ .unbind = mtk_iommu_unbind,
+};
+
+static int mtk_iommu_probe(struct platform_device *pdev)
+{
+ struct mtk_iommu_data *data;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct component_match *match = NULL;
+ void *protect;
+ unsigned int i, larb_nr;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ data->dev = dev;
+
+ /* Protect memory. HW will access here while translation fault.*/
+ protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL);
+ if (!protect)
+ return -ENOMEM;
+ data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->irq = platform_get_irq(pdev, 0);
+ if (data->irq < 0)
+ return data->irq;
+
+ data->bclk = devm_clk_get(dev, "bclk");
+ if (IS_ERR(data->bclk))
+ return PTR_ERR(data->bclk);
+
+ larb_nr = of_count_phandle_with_args(dev->of_node,
+ "mediatek,larbs", NULL);
+ if (larb_nr < 0)
+ return larb_nr;
+ data->smi_imu.larb_nr = larb_nr;
+
+ for (i = 0; i < larb_nr; i++) {
+ struct device_node *larbnode;
+ struct platform_device *plarbdev;
+
+ larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
+ if (!larbnode)
+ return -EINVAL;
+
+ if (!of_device_is_available(larbnode))
+ continue;
+
+ plarbdev = of_find_device_by_node(larbnode);
+ of_node_put(larbnode);
+ if (!plarbdev) {
+ plarbdev = of_platform_device_create(
+ larbnode, NULL,
+ platform_bus_type.dev_root);
+ if (IS_ERR(plarbdev))
+ return -EPROBE_DEFER;
+ }
+ data->smi_imu.larb_imu[i].dev = &plarbdev->dev;
+
+ component_match_add(dev, &match, compare_of, larbnode);
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ ret = mtk_iommu_hw_init(data);
+ if (ret)
+ return ret;
+
+ if (!iommu_present(&platform_bus_type))
+ bus_set_iommu(&platform_bus_type, &mtk_iommu_ops);
+
+ return component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
+}
+
+static int mtk_iommu_remove(struct platform_device *pdev)
+{
+ struct mtk_iommu_data *data = platform_get_drvdata(pdev);
+
+ if (iommu_present(&platform_bus_type))
+ bus_set_iommu(&platform_bus_type, NULL);
+
+ free_io_pgtable_ops(data->m4u_dom->iop);
+ clk_disable_unprepare(data->bclk);
+ devm_free_irq(&pdev->dev, data->irq, data);
+ component_master_del(&pdev->dev, &mtk_iommu_com_ops);
+ return 0;
+}
+
+static int mtk_iommu_suspend(struct device *dev)
+{
+ struct mtk_iommu_data *data = dev_get_drvdata(dev);
+ struct mtk_iommu_suspend_reg *reg = &data->reg;
+ void __iomem *base = data->base;
+
+ reg->standard_axi_mode = readl_relaxed(base +
+ REG_MMU_STANDARD_AXI_MODE);
+ reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM_DIS);
+ reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
+ reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
+ reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
+ return 0;
+}
+
+static int mtk_iommu_resume(struct device *dev)
+{
+ struct mtk_iommu_data *data = dev_get_drvdata(dev);
+ struct mtk_iommu_suspend_reg *reg = &data->reg;
+ void __iomem *base = data->base;
+
+ writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
+ base + REG_MMU_PT_BASE_ADDR);
+ writel_relaxed(reg->standard_axi_mode,
+ base + REG_MMU_STANDARD_AXI_MODE);
+ writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM_DIS);
+ writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
+ writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
+ writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
+ writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base),
+ base + REG_MMU_IVRP_PADDR);
+ return 0;
+}
+
+const struct dev_pm_ops mtk_iommu_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk_iommu_suspend, mtk_iommu_resume)
+};
+
+static const struct of_device_id mtk_iommu_of_ids[] = {
+ { .compatible = "mediatek,mt8173-m4u", },
+ {}
+};
+
+static struct platform_driver mtk_iommu_driver = {
+ .probe = mtk_iommu_probe,
+ .remove = mtk_iommu_remove,
+ .driver = {
+ .name = "mtk-iommu",
+ .of_match_table = mtk_iommu_of_ids,
+ .pm = &mtk_iommu_pm_ops,
+ }
+};
+
+static int mtk_iommu_init_fn(struct device_node *np)
+{
+ int ret;
+ struct platform_device *pdev;
+
+ pdev = of_platform_device_create(np, NULL, platform_bus_type.dev_root);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ ret = platform_driver_register(&mtk_iommu_driver);
+ if (ret) {
+ pr_err("%s: Failed to register driver\n", __func__);
+ return ret;
+ }
+
+ of_iommu_set_ops(np, &mtk_iommu_ops);
+ return 0;
+}
+
+IOMMU_OF_DECLARE(mtkm4u, "mediatek,mt8173-m4u", mtk_iommu_init_fn);
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver
2016-01-26 4:12 ` [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
@ 2016-01-26 15:29 ` kbuild test robot
2016-01-26 17:42 ` Robin Murphy
2016-01-26 19:26 ` kbuild test robot
2 siblings, 0 replies; 22+ messages in thread
From: kbuild test robot @ 2016-01-26 15:29 UTC (permalink / raw)
To: linux-arm-kernel
Hi Yong,
[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.5-rc1 next-20160125]
[cannot apply to iommu/next]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Yong-Wu/MT8173-IOMMU-SUPPORT/20160126-201633
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux for-next
config: arm64-allyesconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
All error/warnings (new ones prefixed by >>):
drivers/iommu/mtk_iommu.c: In function 'mtk_iommu_domain_finalise':
>> drivers/iommu/mtk_iommu.c:246:4: error: 'IO_PGTABLE_QUIRK_NO_PERMS' undeclared (first use in this function)
IO_PGTABLE_QUIRK_NO_PERMS |
^
drivers/iommu/mtk_iommu.c:246:4: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/iommu/mtk_iommu.c:247:4: error: 'IO_PGTABLE_QUIRK_TLBI_ON_MAP' undeclared (first use in this function)
IO_PGTABLE_QUIRK_TLBI_ON_MAP,
^
>> drivers/iommu/mtk_iommu.c:255:34: error: 'ARM_V7S' undeclared (first use in this function)
dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
^
In file included from include/linux/swab.h:4:0,
from include/uapi/linux/byteorder/big_endian.h:12,
from include/linux/byteorder/big_endian.h:4,
from arch/arm64/include/uapi/asm/byteorder.h:20,
from include/asm-generic/bitops/le.h:5,
from arch/arm64/include/asm/bitops.h:50,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/linux/clk.h:16,
from drivers/iommu/mtk_iommu.c:14:
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:115:32: note: in definition of macro '__swab32'
(__builtin_constant_p((__u32)(x)) ? \
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
>> drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:17:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
>> drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:18:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
>> drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:19:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
>> drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:20:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0xff000000UL) >> 24)))
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
>> drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
>> drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:117:12: note: in definition of macro '__swab32'
__fswab32(x))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm64/include/asm/io.h:142:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
^
vim +/IO_PGTABLE_QUIRK_NO_PERMS +246 drivers/iommu/mtk_iommu.c
240 struct mtk_iommu_domain *dom = data->m4u_dom;
241
242 spin_lock_init(&dom->pgtlock);
243
244 dom->cfg = (struct io_pgtable_cfg) {
245 .quirks = IO_PGTABLE_QUIRK_ARM_NS |
> 246 IO_PGTABLE_QUIRK_NO_PERMS |
> 247 IO_PGTABLE_QUIRK_TLBI_ON_MAP,
248 .pgsize_bitmap = mtk_iommu_ops.pgsize_bitmap,
249 .ias = 32,
250 .oas = 32,
251 .tlb = &mtk_iommu_gather_ops,
252 .iommu_dev = data->dev,
253 };
254
> 255 dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
256 if (!dom->iop) {
257 dev_err(data->dev, "Failed to alloc io pgtable\n");
258 return -EINVAL;
259 }
260
261 /* Update our support page sizes bitmap */
262 mtk_iommu_ops.pgsize_bitmap = dom->cfg.pgsize_bitmap;
263
> 264 writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
265 data->base + REG_MMU_PT_BASE_ADDR);
266 return 0;
267 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 48155 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160126/f74fb45c/attachment-0001.obj>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver
2016-01-26 4:12 ` [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
2016-01-26 15:29 ` kbuild test robot
@ 2016-01-26 17:42 ` Robin Murphy
2016-01-26 19:26 ` kbuild test robot
2 siblings, 0 replies; 22+ messages in thread
From: Robin Murphy @ 2016-01-26 17:42 UTC (permalink / raw)
To: linux-arm-kernel
On 26/01/16 04:12, Yong Wu wrote:
> This patch adds support for mediatek m4u (MultiMedia Memory Management
> Unit).
Whilst I can't speak for the hardware specifics, I think we've got the
API aspects and general shape of the code looking pretty much right by
now - I don't see anything worth complaining about at this point.
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Yong Wu <yong.wu@mediatek.com>
> ---
> drivers/iommu/Kconfig | 16 +
> drivers/iommu/Makefile | 1 +
> drivers/iommu/mtk_iommu.c | 732 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 749 insertions(+)
> create mode 100644 drivers/iommu/mtk_iommu.c
>
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index a1e75cb..4922aa8 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -318,4 +318,20 @@ config S390_IOMMU
> help
> Support for the IOMMU API for s390 PCI devices.
>
> +config MTK_IOMMU
> + bool "MTK IOMMU Support"
> + depends on ARM || ARM64
> + depends on ARCH_MEDIATEK || COMPILE_TEST
> + select IOMMU_API
> + select IOMMU_DMA
> + select IOMMU_IO_PGTABLE_ARMV7S
> + select MEMORY
> + select MTK_SMI
> + help
> + Support for the M4U on certain Mediatek SOCs. M4U is MultiMedia
> + Memory Management Unit. This option enables remapping of DMA memory
> + accesses for the multimedia subsystem.
> +
> + If unsure, say N here.
> +
> endif # IOMMU_SUPPORT
> diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> index 42fc0c2..44ae2e0 100644
> --- a/drivers/iommu/Makefile
> +++ b/drivers/iommu/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o
> obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
> obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
> obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
> +obj-$(CONFIG_MTK_IOMMU) += mtk_iommu.o
> obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
> obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
> obj-$(CONFIG_ROCKCHIP_IOMMU) += rockchip-iommu.o
> diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
> new file mode 100644
> index 0000000..60fe97b
> --- /dev/null
> +++ b/drivers/iommu/mtk_iommu.c
> @@ -0,0 +1,732 @@
> +/*
> + * Copyright (c) 2015-2016 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/clk.h>
> +#include <linux/component.h>
> +#include <linux/dma-iommu.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iommu.h>
> +#include <linux/iopoll.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_iommu.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <soc/mediatek/smi.h>
> +#include <dt-bindings/memory/mt8173-larb-port.h>
> +
> +#include "io-pgtable.h"
> +
> +#define REG_MMU_PT_BASE_ADDR 0x000
> +
> +#define REG_MMU_INVALIDATE 0x020
> +#define F_ALL_INVLD 0x2
> +#define F_MMU_INV_RANGE 0x1
> +
> +#define REG_MMU_INVLD_START_A 0x024
> +#define REG_MMU_INVLD_END_A 0x028
> +
> +#define REG_MMU_INV_SEL 0x038
> +#define F_INVLD_EN0 BIT(0)
> +#define F_INVLD_EN1 BIT(1)
> +
> +#define REG_MMU_STANDARD_AXI_MODE 0x048
> +#define REG_MMU_DCM_DIS 0x050
> +
> +#define REG_MMU_CTRL_REG 0x110
> +#define F_MMU_PREFETCH_RT_REPLACE_MOD BIT(4)
> +#define F_MMU_TF_PROTECT_SEL(prot) (((prot) & 0x3) << 5)
> +
> +#define REG_MMU_IVRP_PADDR 0x114
> +#define F_MMU_IVRP_PA_SET(pa) ((pa) >> 1)
> +
> +#define REG_MMU_INT_CONTROL0 0x120
> +#define F_L2_MULIT_HIT_EN BIT(0)
> +#define F_TABLE_WALK_FAULT_INT_EN BIT(1)
> +#define F_PREETCH_FIFO_OVERFLOW_INT_EN BIT(2)
> +#define F_MISS_FIFO_OVERFLOW_INT_EN BIT(3)
> +#define F_PREFETCH_FIFO_ERR_INT_EN BIT(5)
> +#define F_MISS_FIFO_ERR_INT_EN BIT(6)
> +#define F_INT_CLR_BIT BIT(12)
> +
> +#define REG_MMU_INT_MAIN_CONTROL 0x124
> +#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_MISS_TRANSACTION_FIFO_FAULT BIT(5)
> +#define F_INT_PRETETCH_TRANSATION_FIFO_FAULT BIT(6)
> +
> +#define REG_MMU_CPE_DONE 0x12C
> +
> +#define REG_MMU_FAULT_ST1 0x134
> +
> +#define REG_MMU_FAULT_VA 0x13c
> +#define F_MMU_FAULT_VA_MSK 0xfffff000
> +#define F_MMU_FAULT_VA_WRITE_BIT BIT(1)
> +#define F_MMU_FAULT_VA_LAYER_BIT BIT(0)
> +
> +#define REG_MMU_INVLD_PA 0x140
> +#define REG_MMU_INT_ID 0x150
> +#define F_MMU0_INT_ID_LARB_ID(a) (((a) >> 7) & 0x7)
> +#define F_MMU0_INT_ID_PORT_ID(a) (((a) >> 2) & 0x1f)
> +
> +#define MTK_PROTECT_PA_ALIGN 128
> +
> +struct mtk_iommu_suspend_reg {
> + u32 standard_axi_mode;
> + u32 dcm_dis;
> + u32 ctrl_reg;
> + u32 int_control0;
> + u32 int_main_control;
> +};
> +
> +struct mtk_iommu_client_priv {
> + struct list_head client;
> + unsigned int mtk_m4u_id;
> + struct device *m4udev;
> +};
> +
> +struct mtk_iommu_domain {
> + spinlock_t pgtlock; /* lock for page table */
> +
> + struct io_pgtable_cfg cfg;
> + struct io_pgtable_ops *iop;
> +
> + struct iommu_domain domain;
> +};
> +
> +struct mtk_iommu_data {
> + void __iomem *base;
> + int irq;
> + struct device *dev;
> + struct clk *bclk;
> + phys_addr_t protect_base; /* protect memory base */
> + struct mtk_iommu_suspend_reg reg;
> + struct mtk_iommu_domain *m4u_dom;
> + struct iommu_group *m4u_group;
> + struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */
> +};
> +
> +static struct iommu_ops mtk_iommu_ops;
> +
> +static struct mtk_iommu_domain *to_mtk_domain(struct iommu_domain *dom)
> +{
> + return container_of(dom, struct mtk_iommu_domain, domain);
> +}
> +
> +static void mtk_iommu_tlb_flush_all(void *cookie)
> +{
> + struct mtk_iommu_data *data = cookie;
> +
> + writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, data->base + REG_MMU_INV_SEL);
> + writel_relaxed(F_ALL_INVLD, data->base + REG_MMU_INVALIDATE);
> + wmb(); /* Make sure the tlb flush all done */
> +}
> +
> +static void mtk_iommu_tlb_add_flush_nosync(unsigned long iova, size_t size,
> + size_t granule, bool leaf,
> + void *cookie)
> +{
> + struct mtk_iommu_data *data = cookie;
> +
> + writel_relaxed(F_INVLD_EN1 | F_INVLD_EN0, data->base + REG_MMU_INV_SEL);
> +
> + writel_relaxed(iova, data->base + REG_MMU_INVLD_START_A);
> + writel_relaxed(iova + size - 1, data->base + REG_MMU_INVLD_END_A);
> + writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
> +}
> +
> +static void mtk_iommu_tlb_sync(void *cookie)
> +{
> + struct mtk_iommu_data *data = cookie;
> + int ret;
> + u32 tmp;
> +
> + ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE, tmp,
> + tmp != 0, 10, 100000);
> + if (ret) {
> + dev_warn(data->dev,
> + "Partial TLB flush timed out, falling back to full flush\n");
> + mtk_iommu_tlb_flush_all(cookie);
> + }
> + /* Clear the CPE status */
> + writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
> +}
> +
> +static const struct iommu_gather_ops mtk_iommu_gather_ops = {
> + .tlb_flush_all = mtk_iommu_tlb_flush_all,
> + .tlb_add_flush = mtk_iommu_tlb_add_flush_nosync,
> + .tlb_sync = mtk_iommu_tlb_sync,
> +};
> +
> +static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
> +{
> + struct mtk_iommu_data *data = dev_id;
> + struct mtk_iommu_domain *dom = data->m4u_dom;
> + u32 int_state, regval, fault_iova, fault_pa;
> + unsigned int fault_larb, fault_port;
> + bool layer, write;
> +
> + /* Read error info from registers */
> + int_state = readl_relaxed(data->base + REG_MMU_FAULT_ST1);
> + fault_iova = readl_relaxed(data->base + REG_MMU_FAULT_VA);
> + layer = fault_iova & F_MMU_FAULT_VA_LAYER_BIT;
> + write = fault_iova & F_MMU_FAULT_VA_WRITE_BIT;
> + fault_iova &= F_MMU_FAULT_VA_MSK;
> + fault_pa = readl_relaxed(data->base + REG_MMU_INVLD_PA);
> + regval = readl_relaxed(data->base + REG_MMU_INT_ID);
> + fault_larb = F_MMU0_INT_ID_LARB_ID(regval);
> + fault_port = F_MMU0_INT_ID_PORT_ID(regval);
> +
> + if (report_iommu_fault(&dom->domain, data->dev, fault_iova,
> + write ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ)) {
> + dev_err_ratelimited(
> + data->dev,
> + "fault type=0x%x iova=0x%x pa=0x%x larb=%d port=%d layer=%d %s\n",
> + int_state, fault_iova, fault_pa, fault_larb, fault_port,
> + layer, write ? "write" : "read");
> + }
> +
> + /* Interrupt clear */
> + regval = readl_relaxed(data->base + REG_MMU_INT_CONTROL0);
> + regval |= F_INT_CLR_BIT;
> + writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
> +
> + mtk_iommu_tlb_flush_all(data);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void mtk_iommu_config(struct mtk_iommu_data *data,
> + struct device *dev, bool enable)
> +{
> + struct mtk_iommu_client_priv *head, *cur, *next;
> + struct mtk_smi_larb_iommu *larb_mmu;
> + unsigned int larbid, portid;
> +
> + head = dev->archdata.iommu;
> + list_for_each_entry_safe(cur, next, &head->client, client) {
> + larbid = MTK_M4U_TO_LARB(cur->mtk_m4u_id);
> + portid = MTK_M4U_TO_PORT(cur->mtk_m4u_id);
> + larb_mmu = &data->smi_imu.larb_imu[larbid];
> +
> + dev_dbg(dev, "%s iommu port: %d\n",
> + enable ? "enable" : "disable", portid);
> +
> + if (enable)
> + larb_mmu->mmu |= MTK_SMI_MMU_EN(portid);
> + else
> + larb_mmu->mmu &= ~MTK_SMI_MMU_EN(portid);
> + }
> +}
> +
> +static int mtk_iommu_domain_finalise(struct mtk_iommu_data *data)
> +{
> + struct mtk_iommu_domain *dom = data->m4u_dom;
> +
> + spin_lock_init(&dom->pgtlock);
> +
> + dom->cfg = (struct io_pgtable_cfg) {
> + .quirks = IO_PGTABLE_QUIRK_ARM_NS |
> + IO_PGTABLE_QUIRK_NO_PERMS |
> + IO_PGTABLE_QUIRK_TLBI_ON_MAP,
> + .pgsize_bitmap = mtk_iommu_ops.pgsize_bitmap,
> + .ias = 32,
> + .oas = 32,
> + .tlb = &mtk_iommu_gather_ops,
> + .iommu_dev = data->dev,
> + };
> +
> + dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
> + if (!dom->iop) {
> + dev_err(data->dev, "Failed to alloc io pgtable\n");
> + return -EINVAL;
> + }
> +
> + /* Update our support page sizes bitmap */
> + mtk_iommu_ops.pgsize_bitmap = dom->cfg.pgsize_bitmap;
> +
> + writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
> + data->base + REG_MMU_PT_BASE_ADDR);
> + return 0;
> +}
> +
> +static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type)
> +{
> + struct mtk_iommu_domain *dom;
> +
> + if (type != IOMMU_DOMAIN_DMA)
> + return NULL;
> +
> + dom = kzalloc(sizeof(*dom), GFP_KERNEL);
> + if (!dom)
> + return NULL;
> +
> + if (iommu_get_dma_cookie(&dom->domain)) {
> + kfree(dom);
> + return NULL;
> + }
> +
> + dom->domain.geometry.aperture_start = 0;
> + dom->domain.geometry.aperture_end = DMA_BIT_MASK(32);
> + dom->domain.geometry.force_aperture = true;
> +
> + return &dom->domain;
> +}
> +
> +static void mtk_iommu_domain_free(struct iommu_domain *domain)
> +{
> + iommu_put_dma_cookie(domain);
> + kfree(to_mtk_domain(domain));
> +}
> +
> +static int mtk_iommu_attach_device(struct iommu_domain *domain,
> + struct device *dev)
> +{
> + struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> + struct mtk_iommu_client_priv *priv = dev->archdata.iommu;
> + struct mtk_iommu_data *data;
> + int ret;
> +
> + if (!priv)
> + return -ENODEV;
> +
> + data = dev_get_drvdata(priv->m4udev);
> + if (!data->m4u_dom) {
> + data->m4u_dom = dom;
> + ret = mtk_iommu_domain_finalise(data);
> + if (ret) {
> + data->m4u_dom = NULL;
> + return ret;
> + }
> + } else if (data->m4u_dom != dom) {
> + /* All the client devices should be in the same m4u domain */
> + dev_err(dev, "try to attach into the error iommu domain\n");
> + return -EPERM;
> + }
> +
> + mtk_iommu_config(data, dev, true);
> + return 0;
> +}
> +
> +static void mtk_iommu_detach_device(struct iommu_domain *domain,
> + struct device *dev)
> +{
> + struct mtk_iommu_client_priv *priv = dev->archdata.iommu;
> + struct mtk_iommu_data *data;
> +
> + if (!priv)
> + return;
> +
> + data = dev_get_drvdata(priv->m4udev);
> + mtk_iommu_config(data, dev, false);
> +}
> +
> +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 *dom = to_mtk_domain(domain);
> + unsigned long flags;
> + int ret;
> +
> + spin_lock_irqsave(&dom->pgtlock, flags);
> + ret = dom->iop->map(dom->iop, iova, paddr, size, prot);
> + spin_unlock_irqrestore(&dom->pgtlock, flags);
> +
> + return ret;
> +}
> +
> +static size_t mtk_iommu_unmap(struct iommu_domain *domain,
> + unsigned long iova, size_t size)
> +{
> + struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> + unsigned long flags;
> + size_t unmapsz;
> +
> + spin_lock_irqsave(&dom->pgtlock, flags);
> + unmapsz = dom->iop->unmap(dom->iop, iova, size);
> + spin_unlock_irqrestore(&dom->pgtlock, flags);
> +
> + return unmapsz;
> +}
> +
> +static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
> + dma_addr_t iova)
> +{
> + struct mtk_iommu_domain *dom = to_mtk_domain(domain);
> + unsigned long flags;
> + phys_addr_t pa;
> +
> + spin_lock_irqsave(&dom->pgtlock, flags);
> + pa = dom->iop->iova_to_phys(dom->iop, iova);
> + spin_unlock_irqrestore(&dom->pgtlock, flags);
> +
> + return pa;
> +}
> +
> +static int mtk_iommu_add_device(struct device *dev)
> +{
> + struct iommu_group *group;
> +
> + if (!dev->archdata.iommu) /* Not a iommu client device */
> + return -ENODEV;
> +
> + group = iommu_group_get_for_dev(dev);
> + if (IS_ERR(group))
> + return PTR_ERR(group);
> +
> + iommu_group_put(group);
> + return 0;
> +}
> +
> +static void mtk_iommu_remove_device(struct device *dev)
> +{
> + struct mtk_iommu_client_priv *head, *cur, *next;
> +
> + head = dev->archdata.iommu;
> + if (!head)
> + return;
> +
> + list_for_each_entry_safe(cur, next, &head->client, client) {
> + list_del(&cur->client);
> + kfree(cur);
> + }
> + kfree(head);
> + dev->archdata.iommu = NULL;
> +
> + iommu_group_remove_device(dev);
> +}
> +
> +static struct iommu_group *mtk_iommu_device_group(struct device *dev)
> +{
> + struct mtk_iommu_data *data;
> + struct mtk_iommu_client_priv *priv;
> +
> + priv = dev->archdata.iommu;
> + if (!priv)
> + return ERR_PTR(-ENODEV);
> +
> + /* All the client devices are in the same m4u iommu-group */
> + data = dev_get_drvdata(priv->m4udev);
> + if (!data->m4u_group) {
> + data->m4u_group = iommu_group_alloc();
> + if (IS_ERR(data->m4u_group))
> + dev_err(dev, "Failed to allocate M4U IOMMU group\n");
> + }
> + return data->m4u_group;
> +}
> +
> +static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
> +{
> + struct mtk_iommu_client_priv *head, *priv, *next;
> + struct platform_device *m4updev;
> +
> + if (args->args_count != 1) {
> + dev_err(dev, "invalid #iommu-cells(%d) property for IOMMU\n",
> + args->args_count);
> + return -EINVAL;
> + }
> +
> + if (!dev->archdata.iommu) {
> + /* Get the m4u device */
> + m4updev = of_find_device_by_node(args->np);
> + of_node_put(args->np);
> + if (WARN_ON(!m4updev))
> + return -EINVAL;
> +
> + head = kzalloc(sizeof(*head), GFP_KERNEL);
> + if (!head)
> + return -ENOMEM;
> +
> + dev->archdata.iommu = head;
> + INIT_LIST_HEAD(&head->client);
> + head->m4udev = &m4updev->dev;
> + } else {
> + head = dev->archdata.iommu;
> + }
> +
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + goto err_free_mem;
> +
> + priv->mtk_m4u_id = args->args[0];
> + list_add_tail(&priv->client, &head->client);
> +
> + return 0;
> +
> +err_free_mem:
> + list_for_each_entry_safe(priv, next, &head->client, client)
> + kfree(priv);
> + kfree(head);
> + dev->archdata.iommu = NULL;
> + return -ENOMEM;
> +}
> +
> +static struct iommu_ops mtk_iommu_ops = {
> + .domain_alloc = mtk_iommu_domain_alloc,
> + .domain_free = mtk_iommu_domain_free,
> + .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,
> + .add_device = mtk_iommu_add_device,
> + .remove_device = mtk_iommu_remove_device,
> + .device_group = mtk_iommu_device_group,
> + .of_xlate = mtk_iommu_of_xlate,
> + .pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M,
> +};
> +
> +static int mtk_iommu_hw_init(const struct mtk_iommu_data *data)
> +{
> + u32 regval;
> + int ret;
> +
> + ret = clk_prepare_enable(data->bclk);
> + if (ret) {
> + dev_err(data->dev, "Failed to enable iommu bclk(%d)\n", ret);
> + return ret;
> + }
> +
> + regval = F_MMU_PREFETCH_RT_REPLACE_MOD |
> + F_MMU_TF_PROTECT_SEL(2);
> + writel_relaxed(regval, data->base + REG_MMU_CTRL_REG);
> +
> + regval = F_L2_MULIT_HIT_EN |
> + F_TABLE_WALK_FAULT_INT_EN |
> + F_PREETCH_FIFO_OVERFLOW_INT_EN |
> + F_MISS_FIFO_OVERFLOW_INT_EN |
> + F_PREFETCH_FIFO_ERR_INT_EN |
> + F_MISS_FIFO_ERR_INT_EN;
> + writel_relaxed(regval, data->base + REG_MMU_INT_CONTROL0);
> +
> + regval = F_INT_TRANSLATION_FAULT |
> + F_INT_MAIN_MULTI_HIT_FAULT |
> + F_INT_INVALID_PA_FAULT |
> + F_INT_ENTRY_REPLACEMENT_FAULT |
> + F_INT_TLB_MISS_FAULT |
> + F_INT_MISS_TRANSACTION_FIFO_FAULT |
> + F_INT_PRETETCH_TRANSATION_FIFO_FAULT;
> + writel_relaxed(regval, data->base + REG_MMU_INT_MAIN_CONTROL);
> +
> + writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base),
> + data->base + REG_MMU_IVRP_PADDR);
> +
> + writel_relaxed(0, data->base + REG_MMU_DCM_DIS);
> + writel_relaxed(0, data->base + REG_MMU_STANDARD_AXI_MODE);
> +
> + if (devm_request_irq(data->dev, data->irq, mtk_iommu_isr, 0,
> + dev_name(data->dev), (void *)data)) {
> + writel_relaxed(0, data->base + REG_MMU_PT_BASE_ADDR);
> + clk_disable_unprepare(data->bclk);
> + dev_err(data->dev, "Failed @ IRQ-%d Request\n", data->irq);
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> + return dev->of_node == data;
> +}
> +
> +static int mtk_iommu_bind(struct device *dev)
> +{
> + struct mtk_iommu_data *data = dev_get_drvdata(dev);
> +
> + return component_bind_all(dev, &data->smi_imu);
> +}
> +
> +static void mtk_iommu_unbind(struct device *dev)
> +{
> + struct mtk_iommu_data *data = dev_get_drvdata(dev);
> +
> + component_unbind_all(dev, &data->smi_imu);
> +}
> +
> +static const struct component_master_ops mtk_iommu_com_ops = {
> + .bind = mtk_iommu_bind,
> + .unbind = mtk_iommu_unbind,
> +};
> +
> +static int mtk_iommu_probe(struct platform_device *pdev)
> +{
> + struct mtk_iommu_data *data;
> + struct device *dev = &pdev->dev;
> + struct resource *res;
> + struct component_match *match = NULL;
> + void *protect;
> + unsigned int i, larb_nr;
> + int ret;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> + data->dev = dev;
> +
> + /* Protect memory. HW will access here while translation fault.*/
> + protect = devm_kzalloc(dev, MTK_PROTECT_PA_ALIGN * 2, GFP_KERNEL);
> + if (!protect)
> + return -ENOMEM;
> + data->protect_base = ALIGN(virt_to_phys(protect), MTK_PROTECT_PA_ALIGN);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + data->base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(data->base))
> + return PTR_ERR(data->base);
> +
> + data->irq = platform_get_irq(pdev, 0);
> + if (data->irq < 0)
> + return data->irq;
> +
> + data->bclk = devm_clk_get(dev, "bclk");
> + if (IS_ERR(data->bclk))
> + return PTR_ERR(data->bclk);
> +
> + larb_nr = of_count_phandle_with_args(dev->of_node,
> + "mediatek,larbs", NULL);
> + if (larb_nr < 0)
> + return larb_nr;
> + data->smi_imu.larb_nr = larb_nr;
> +
> + for (i = 0; i < larb_nr; i++) {
> + struct device_node *larbnode;
> + struct platform_device *plarbdev;
> +
> + larbnode = of_parse_phandle(dev->of_node, "mediatek,larbs", i);
> + if (!larbnode)
> + return -EINVAL;
> +
> + if (!of_device_is_available(larbnode))
> + continue;
> +
> + plarbdev = of_find_device_by_node(larbnode);
> + of_node_put(larbnode);
> + if (!plarbdev) {
> + plarbdev = of_platform_device_create(
> + larbnode, NULL,
> + platform_bus_type.dev_root);
> + if (IS_ERR(plarbdev))
> + return -EPROBE_DEFER;
> + }
> + data->smi_imu.larb_imu[i].dev = &plarbdev->dev;
> +
> + component_match_add(dev, &match, compare_of, larbnode);
> + }
> +
> + platform_set_drvdata(pdev, data);
> +
> + ret = mtk_iommu_hw_init(data);
> + if (ret)
> + return ret;
> +
> + if (!iommu_present(&platform_bus_type))
> + bus_set_iommu(&platform_bus_type, &mtk_iommu_ops);
> +
> + return component_master_add_with_match(dev, &mtk_iommu_com_ops, match);
> +}
> +
> +static int mtk_iommu_remove(struct platform_device *pdev)
> +{
> + struct mtk_iommu_data *data = platform_get_drvdata(pdev);
> +
> + if (iommu_present(&platform_bus_type))
> + bus_set_iommu(&platform_bus_type, NULL);
> +
> + free_io_pgtable_ops(data->m4u_dom->iop);
> + clk_disable_unprepare(data->bclk);
> + devm_free_irq(&pdev->dev, data->irq, data);
> + component_master_del(&pdev->dev, &mtk_iommu_com_ops);
> + return 0;
> +}
> +
> +static int mtk_iommu_suspend(struct device *dev)
> +{
> + struct mtk_iommu_data *data = dev_get_drvdata(dev);
> + struct mtk_iommu_suspend_reg *reg = &data->reg;
> + void __iomem *base = data->base;
> +
> + reg->standard_axi_mode = readl_relaxed(base +
> + REG_MMU_STANDARD_AXI_MODE);
> + reg->dcm_dis = readl_relaxed(base + REG_MMU_DCM_DIS);
> + reg->ctrl_reg = readl_relaxed(base + REG_MMU_CTRL_REG);
> + reg->int_control0 = readl_relaxed(base + REG_MMU_INT_CONTROL0);
> + reg->int_main_control = readl_relaxed(base + REG_MMU_INT_MAIN_CONTROL);
> + return 0;
> +}
> +
> +static int mtk_iommu_resume(struct device *dev)
> +{
> + struct mtk_iommu_data *data = dev_get_drvdata(dev);
> + struct mtk_iommu_suspend_reg *reg = &data->reg;
> + void __iomem *base = data->base;
> +
> + writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
> + base + REG_MMU_PT_BASE_ADDR);
> + writel_relaxed(reg->standard_axi_mode,
> + base + REG_MMU_STANDARD_AXI_MODE);
> + writel_relaxed(reg->dcm_dis, base + REG_MMU_DCM_DIS);
> + writel_relaxed(reg->ctrl_reg, base + REG_MMU_CTRL_REG);
> + writel_relaxed(reg->int_control0, base + REG_MMU_INT_CONTROL0);
> + writel_relaxed(reg->int_main_control, base + REG_MMU_INT_MAIN_CONTROL);
> + writel_relaxed(F_MMU_IVRP_PA_SET(data->protect_base),
> + base + REG_MMU_IVRP_PADDR);
> + return 0;
> +}
> +
> +const struct dev_pm_ops mtk_iommu_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(mtk_iommu_suspend, mtk_iommu_resume)
> +};
> +
> +static const struct of_device_id mtk_iommu_of_ids[] = {
> + { .compatible = "mediatek,mt8173-m4u", },
> + {}
> +};
> +
> +static struct platform_driver mtk_iommu_driver = {
> + .probe = mtk_iommu_probe,
> + .remove = mtk_iommu_remove,
> + .driver = {
> + .name = "mtk-iommu",
> + .of_match_table = mtk_iommu_of_ids,
> + .pm = &mtk_iommu_pm_ops,
> + }
> +};
> +
> +static int mtk_iommu_init_fn(struct device_node *np)
> +{
> + int ret;
> + struct platform_device *pdev;
> +
> + pdev = of_platform_device_create(np, NULL, platform_bus_type.dev_root);
> + if (IS_ERR(pdev))
> + return PTR_ERR(pdev);
> +
> + ret = platform_driver_register(&mtk_iommu_driver);
> + if (ret) {
> + pr_err("%s: Failed to register driver\n", __func__);
> + return ret;
> + }
> +
> + of_iommu_set_ops(np, &mtk_iommu_ops);
> + return 0;
> +}
> +
> +IOMMU_OF_DECLARE(mtkm4u, "mediatek,mt8173-m4u", mtk_iommu_init_fn);
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver
2016-01-26 4:12 ` [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
2016-01-26 15:29 ` kbuild test robot
2016-01-26 17:42 ` Robin Murphy
@ 2016-01-26 19:26 ` kbuild test robot
2 siblings, 0 replies; 22+ messages in thread
From: kbuild test robot @ 2016-01-26 19:26 UTC (permalink / raw)
To: linux-arm-kernel
Hi Yong,
[auto build test WARNING on robh/for-next]
[also build test WARNING on v4.5-rc1 next-20160125]
[cannot apply to iommu/next]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Yong-Wu/MT8173-IOMMU-SUPPORT/20160126-201633
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux for-next
config: arm-allmodconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All warnings (new ones prefixed by >>):
drivers/iommu/mtk_iommu.c: In function 'mtk_iommu_domain_finalise':
drivers/iommu/mtk_iommu.c:246:4: error: 'IO_PGTABLE_QUIRK_NO_PERMS' undeclared (first use in this function)
IO_PGTABLE_QUIRK_NO_PERMS |
^
drivers/iommu/mtk_iommu.c:246:4: note: each undeclared identifier is reported only once for each function it appears in
drivers/iommu/mtk_iommu.c:247:4: error: 'IO_PGTABLE_QUIRK_TLBI_ON_MAP' undeclared (first use in this function)
IO_PGTABLE_QUIRK_TLBI_ON_MAP,
^
drivers/iommu/mtk_iommu.c:255:34: error: 'ARM_V7S' undeclared (first use in this function)
dom->iop = alloc_io_pgtable_ops(ARM_V7S, &dom->cfg, data);
^
In file included from include/linux/swab.h:4:0,
from include/uapi/linux/byteorder/big_endian.h:12,
from include/linux/byteorder/big_endian.h:4,
from arch/arm/include/uapi/asm/byteorder.h:19,
from include/asm-generic/bitops/le.h:5,
from arch/arm/include/asm/bitops.h:340,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/linux/clk.h:16,
from drivers/iommu/mtk_iommu.c:14:
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:115:32: note: in definition of macro '__swab32'
(__builtin_constant_p((__u32)(x)) ? \
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:17:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:18:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:19:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:20:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0xff000000UL) >> 24)))
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:264:27: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:117:12: note: in definition of macro '__swab32'
__fswab32(x))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
>> arch/arm/include/asm/io.h:305:36: note: in expansion of macro 'writel_relaxed'
#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
^
drivers/iommu/mtk_iommu.c:264:2: note: in expansion of macro 'writel'
writel(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c: In function 'mtk_iommu_resume':
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:115:32: note: in definition of macro '__swab32'
(__builtin_constant_p((__u32)(x)) ? \
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:17:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:18:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:19:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:20:12: note: in definition of macro '___constant_swab32'
(((__u32)(x) & (__u32)0xff000000UL) >> 24)))
^
include/uapi/linux/byteorder/big_endian.h:32:43: note: in expansion of macro '__swab32'
#define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
drivers/iommu/mtk_iommu.c:681:35: error: 'struct io_pgtable_cfg' has no member named 'arm_v7s_cfg'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
include/uapi/linux/swab.h:117:12: note: in definition of macro '__swab32'
__fswab32(x))
^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
#define cpu_to_le32 __cpu_to_le32
^
drivers/iommu/mtk_iommu.c:681:2: note: in expansion of macro 'writel_relaxed'
writel_relaxed(data->m4u_dom->cfg.arm_v7s_cfg.ttbr[0],
^
vim +/writel_relaxed +305 arch/arm/include/asm/io.h
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 289 #define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; })
b0c1264f arch/arm/include/asm/io.h Olof Johansson 2011-10-04 290 #define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 291 __raw_readw(c)); __r; })
b0c1264f arch/arm/include/asm/io.h Olof Johansson 2011-10-04 292 #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 293 __raw_readl(c)); __r; })
e936771a arch/arm/include/asm/io.h Catalin Marinas 2010-07-28 294
af06bb9f arch/arm/include/asm/io.h Russell King 2012-05-25 295 #define writeb_relaxed(v,c) __raw_writeb(v,c)
af06bb9f arch/arm/include/asm/io.h Russell King 2012-05-25 296 #define writew_relaxed(v,c) __raw_writew((__force u16) cpu_to_le16(v),c)
af06bb9f arch/arm/include/asm/io.h Russell King 2012-05-25 297 #define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c)
e936771a arch/arm/include/asm/io.h Catalin Marinas 2010-07-28 298
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 299 #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 300 #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 301 #define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 302
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 303 #define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 304 #define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 @305 #define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
b92b3612 arch/arm/include/asm/io.h Russell King 2010-07-29 306
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 307 #define readsb(p,d,l) __raw_readsb(p,d,l)
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 308 #define readsw(p,d,l) __raw_readsw(p,d,l)
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 309 #define readsl(p,d,l) __raw_readsl(p,d,l)
^1da177e include/asm-arm/io.h Linus Torvalds 2005-04-16 310
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 311 #define writesb(p,d,l) __raw_writesb(p,d,l)
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 312 #define writesw(p,d,l) __raw_writesw(p,d,l)
5621caac arch/arm/include/asm/io.h Rob Herring 2012-02-10 313 #define writesl(p,d,l) __raw_writesl(p,d,l)
:::::: The code at line 305 was first introduced by commit
:::::: b92b3612134faff171981fad4f0adb33f485e02e ARM: Add barriers to io{read,write}{8,16,32} accessors as well
:::::: TO: Russell King <rmk+kernel@arm.linux.org.uk>
:::::: CC: Russell King <rmk+kernel@arm.linux.org.uk>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 56138 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160127/c36f54d9/attachment-0001.obj>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v8 5/5] dts: mt8173: Add iommu/smi nodes for mt8173
2016-01-26 4:12 [PATCH v8 0/5] MT8173 IOMMU SUPPORT Yong Wu
` (3 preceding siblings ...)
2016-01-26 4:12 ` [PATCH v8 4/5] iommu/mediatek: Add mt8173 IOMMU driver Yong Wu
@ 2016-01-26 4:12 ` Yong Wu
2016-01-28 12:36 ` Daniel Kurtz
4 siblings, 1 reply; 22+ messages in thread
From: Yong Wu @ 2016-01-26 4:12 UTC (permalink / raw)
To: linux-arm-kernel
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 | 81 ++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index ec135ea..8048811 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -14,6 +14,7 @@
#include <dt-bindings/clock/mt8173-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/memory/mt8173-larb-port.h>
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/power/mt8173-power.h>
#include <dt-bindings/reset/mt8173-resets.h>
@@ -277,6 +278,17 @@
reg = <0 0x10200620 0 0x20>;
};
+ iommu: iommu at 10205000 {
+ compatible = "mediatek,mt8173-m4u";
+ reg = <0 0x10205000 0 0x1000>;
+ interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_M4U>;
+ clock-names = "bclk";
+ mediatek,larbs = <&larb0 &larb1 &larb2
+ &larb3 &larb4 &larb5>;
+ #iommu-cells = <1>;
+ };
+
apmixedsys: clock-controller at 10209000 {
compatible = "mediatek,mt8173-apmixedsys";
reg = <0 0x10209000 0 0x1000>;
@@ -589,29 +601,98 @@
status = "disabled";
};
+ larb0: larb at 14021000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x14021000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+ clocks = <&mmsys CLK_MM_SMI_LARB0>,
+ <&mmsys CLK_MM_SMI_LARB0>;
+ clock-names = "apb", "smi";
+ };
+
+ smi_common: smi at 14022000 {
+ compatible = "mediatek,mt8173-smi-common";
+ reg = <0 0x14022000 0 0x1000>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+ clocks = <&mmsys CLK_MM_SMI_COMMON>,
+ <&mmsys CLK_MM_SMI_COMMON>;
+ clock-names = "apb", "smi";
+ };
+
+ larb4: larb at 14027000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x14027000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>;
+ clocks = <&mmsys CLK_MM_SMI_LARB4>,
+ <&mmsys CLK_MM_SMI_LARB4>;
+ clock-names = "apb", "smi";
+ };
+
imgsys: clock-controller at 15000000 {
compatible = "mediatek,mt8173-imgsys", "syscon";
reg = <0 0x15000000 0 0x1000>;
#clock-cells = <1>;
};
+ larb2: larb at 15001000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x15001000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_ISP>;
+ clocks = <&imgsys CLK_IMG_LARB2_SMI>,
+ <&imgsys CLK_IMG_LARB2_SMI>;
+ clock-names = "apb", "smi";
+ };
+
vdecsys: clock-controller at 16000000 {
compatible = "mediatek,mt8173-vdecsys", "syscon";
reg = <0 0x16000000 0 0x1000>;
#clock-cells = <1>;
};
+ larb1: larb at 16010000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x16010000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>;
+ clocks = <&vdecsys CLK_VDEC_CKEN>,
+ <&vdecsys CLK_VDEC_LARB_CKEN>;
+ clock-names = "apb", "smi";
+ };
+
vencsys: clock-controller at 18000000 {
compatible = "mediatek,mt8173-vencsys", "syscon";
reg = <0 0x18000000 0 0x1000>;
#clock-cells = <1>;
};
+ larb3: larb at 18001000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x18001000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VENC>;
+ clocks = <&vencsys CLK_VENC_CKE1>,
+ <&vencsys CLK_VENC_CKE0>;
+ clock-names = "apb", "smi";
+ };
+
vencltsys: clock-controller at 19000000 {
compatible = "mediatek,mt8173-vencltsys", "syscon";
reg = <0 0x19000000 0 0x1000>;
#clock-cells = <1>;
};
+
+ larb5: larb at 19001000 {
+ compatible = "mediatek,mt8173-smi-larb";
+ reg = <0 0x19001000 0 0x1000>;
+ mediatek,smi = <&smi_common>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_VENC_LT>;
+ clocks = <&vencltsys CLK_VENCLT_CKE1>,
+ <&vencltsys CLK_VENCLT_CKE0>;
+ clock-names = "apb", "smi";
+ };
};
};
--
1.8.1.1.dirty
^ permalink raw reply related [flat|nested] 22+ messages in thread