Re: [RFC 04/13] iommu/mediatek: Add APU iommu support

From: AngeloGioacchino Del Regno
Date: Tue Oct 26 2021 - 11:18:05 EST


Il 23/10/21 13:14, Flora Fu ha scritto:
APU IOMMU is a new iommu HW. it use a new pagetable.
Add support for mt8192 apu iommu.

Signed-off-by: Yong Wu <yong.wu@xxxxxxxxxxxx>
Signed-off-by: Flora Fu <flora.fu@xxxxxxxxxxxx>
---
drivers/iommu/mtk_iommu.c | 57 +++++++++++++++++++
include/dt-bindings/memory/mt8192-larb-port.h | 4 ++
2 files changed, 61 insertions(+)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 90be8ebbc98a..a5f8f19e053a 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -133,6 +133,7 @@
/* 2 bits: iommu type */
#define MTK_IOMMU_TYPE_MM (0x0 << 13)
#define MTK_IOMMU_TYPE_INFRA (0x1 << 13)
+#define MTK_IOMMU_TYPE_APU (0x2 << 13)
#define MTK_IOMMU_TYPE_MASK (0x3 << 13)
#define IFA_IOMMU_PCIe_SUPPORT BIT(15)
@@ -185,6 +186,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data, unsigned int ban
#define MTK_IOMMU_4GB_MODE_REMAP_BASE 0x140000000UL
static LIST_HEAD(m4ulist); /* List all the M4U HWs */
+static LIST_HEAD(apulist); /* List the apu iommu HWs */
#define for_each_m4u(data, head) list_for_each_entry(data, head, list)
@@ -209,6 +211,13 @@ static const struct mtk_iommu_iova_region mt8192_multi_dom[] = {
#endif
};
+static const struct mtk_iommu_iova_region mt8192_multi_dom_apu[] = {
+ { .iova_base = 0x0, .size = SZ_4G}, /* APU DATA */
+ { .iova_base = 0x4000000ULL, .size = 0x4000000}, /* APU VLM */
+ { .iova_base = 0x10000000ULL, .size = 0x10000000}, /* APU VPU */
+ { .iova_base = 0x70000000ULL, .size = 0x12600000}, /* APU REG */
+};
+
/* If 2 M4U share a domain(use the same hwlist), Put the corresponding info in first data.*/
static struct mtk_iommu_data *mtk_iommu_get_frst_data(struct list_head *hwlist)
{
@@ -923,6 +932,37 @@ static int mtk_iommu_mm_dts_parse(struct device *dev,
return 0;
}
+static int mtk_iommu_apu_prepare(struct device *dev)
+{
+ struct device_node *apupower_node;
+ struct platform_device *apudev;
+ struct device_link *link;
+
+ apupower_node = of_find_compatible_node(NULL, NULL, "mediatek,apusys-power");

Is it expected to have PM ops in the apusys-power driver? Currently, I can't see
any, but maybe it's because of how complex is this entire implementation.

In any case, the name suggests that this controls power for the entire APU... so
it would be more appropriate if apusys-power would expose a power domain (since it
also has some sort of OPP, from what I can see), in which case you wouldn't be
retrieving it here like you're doing right now... but simply as a power domain,
simplifying the entire handling of that in here.


+ if (!apupower_node) {
+ dev_warn(dev, "Can't find apu power node!\n");
+ return -EINVAL;
+ }
+
+ if (!of_device_is_available(apupower_node)) {
+ of_node_put(apupower_node);
+ return -EPERM;
+ }
+
+ apudev = of_find_device_by_node(apupower_node);
+ if (!apudev) {
+ of_node_put(apupower_node);
+ return -EPROBE_DEFER;
+ }
+
+ link = device_link_add(&apudev->dev, dev, DL_FLAG_PM_RUNTIME);
+ if (!link)
+ dev_err(dev, "Unable link %s.\n", apudev->name);
+
+ of_node_put(apupower_node);
+ return 0;
+}
+
static int mtk_iommu_probe(struct platform_device *pdev)
{
struct mtk_iommu_data *data;
@@ -1021,6 +1061,10 @@ static int mtk_iommu_probe(struct platform_device *pdev)
}
data->pericfg = infracfg;
+ } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_APU)) {
+ ret = mtk_iommu_apu_prepare(dev);
+ if (ret)
+ goto out_runtime_disable;
}
platform_set_drvdata(pdev, data);
@@ -1268,6 +1312,18 @@ static const struct mtk_iommu_plat_data mt8192_data = {
{0, 14, 16}, {0, 13, 18, 17}},
};
+static const struct mtk_iommu_plat_data mt8192_data_apu = {
+ .m4u_plat = M4U_MT8192,
+ .flags = WR_THROT_EN | DCM_DISABLE | MTK_IOMMU_TYPE_APU |
+ SHARE_PGTABLE,
+ .inv_sel_reg = REG_MMU_INV_SEL_GEN2,
+ .hw_list = &apulist,
+ .bank_nr = 1,
+ .bank_enable = {true},
+ .iova_region = mt8192_multi_dom_apu,
+ .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom_apu),
+};
+
static const struct mtk_iommu_plat_data mt8195_data_infra = {
.m4u_plat = M4U_MT8195,
.flags = WR_THROT_EN | DCM_DISABLE |
@@ -1323,6 +1379,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = {
{ .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data},
{ .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data},
{ .compatible = "mediatek,mt8192-m4u", .data = &mt8192_data},
+ { .compatible = "mediatek,mt8192-iommu-apu", .data = &mt8192_data_apu},
{ .compatible = "mediatek,mt8195-iommu-infra", .data = &mt8195_data_infra},
{ .compatible = "mediatek,mt8195-iommu-vdo", .data = &mt8195_data_vdo},
{ .compatible = "mediatek,mt8195-iommu-vpp", .data = &mt8195_data_vpp},
diff --git a/include/dt-bindings/memory/mt8192-larb-port.h b/include/dt-bindings/memory/mt8192-larb-port.h
index 23035a52c675..908d6831bf99 100644
--- a/include/dt-bindings/memory/mt8192-larb-port.h
+++ b/include/dt-bindings/memory/mt8192-larb-port.h
@@ -240,4 +240,8 @@
#define M4U_PORT_L20_IPE_RSC_RDMA0 MTK_M4U_ID(20, 4)
#define M4U_PORT_L20_IPE_RSC_WDMA MTK_M4U_ID(20, 5)
+#define IOMMU_PORT_APU_DATA MTK_M4U_ID(0, 0)
+#define IOMMU_PORT_APU_VLM MTK_M4U_ID(0, 1)
+#define IOMMU_PORT_APU_VPU MTK_M4U_ID(0, 2)
+
#endif